ES6-10的整理筆記,僅為梳理知識體系,回頭查閱方便。本節(scope作用域 -- let&const -- Array) ...
大綱
(慕課的圖先用著)
scope-作用域
作用域是指程式源代碼中定義變數的區域,規定瞭如何查找變數,也就是確定當前執行代碼對變數的訪問許可權。
JavaScript作用域共有兩種主要的工作模型——詞法作用域(靜態作用域)和動態作用域。
JavaScript預設採用詞法作用域(lexical scoping),也就是靜態作用域。
詞法作用域是由開發者在寫代碼時將變數和塊作用域寫在哪裡來決定的。由此出現全局作用域,函數作用域(局部作用域),塊狀作用域
動態作用域一般由this產生
註:1.如果一個變數或者表達式不在“當前的作用域”,那麼JavaScript機制會繼續沿著作用域鏈向上查找直到全局作用域(global或瀏覽器中的window)如果找不到將不判定為不可被使用。
2.作用域也會根據代碼層次分層,作用域之間形成父子關係,嵌套關係。子作用域可以訪問父作用域。通常沿著鏈式的作用域鏈查找向上查找,而不能從父作用域引用訪問子作用域的變數和引用
全局作用域
所有在全局作用域中聲明的變數、函數都會變成window對象的屬性和方法
變數在函數或者代碼塊{}外定義,即為全局作用域。一般可以在頁面任何地方訪問
var oneName = " Volvo";
// 此處可調用 oneName 變數
function myFunction() {
// 函數內可調用 oneName 變數
}
if(true){
//代碼塊內可調用oneName變數
}
在函數或者代碼塊{}內未定義的變數也擁有全局作用域。該變數將作為global或者window的屬性存在
// 此處可調用 oneName 變數
function myFunction() {
carName = "Volvo";
// 函數內可調用 oneName 變數
}
if(true){
//代碼塊內可調用oneName變數
}
註:在函數內部或者代碼塊中沒有定義的變數實際上是作為global/window的屬性存在,而不是全局變數。該變數是可以被delete掉,而全局變數不可以。因為通過var語句添加的全局變數有一個configcurable屬性,預設值為false。可以通過Object.getOwnPropertyDescriptor(window,"...")查看
window對象上的屬性在書寫時可以省略window.
函數作用域(局部作用域)
在函數內部定義的變數對外是封閉的,從外層無法直接訪問函數內部的作用域
function bar() {
var testValue = 'inner';
}
console.log(testValue); // 報錯:ReferenceError: testValue is not defined
如果想讀取函數內部的變數,必須藉助return或者閉包
//使用return方式
function bar(value) {
var testValue = 'inner';
return testValue + value;
}
console.log(bar('fun')); // "innerfun"
return 是函數對外交流的出口,而 return 可以返回的是函數,根據作用域的規則,函數bar內部的子函數inner是可以獲取函數bar作用域內的變數result
//使用閉包方式
function bar(value) {
var testValue = 'inner';
var result = testValue + value;
function innser() {
return result;
};
return innser();
}
console.log(bar('fun')); // "innerfun"
塊狀作用域
在其他編程語言中,塊狀作用域是很熟悉的概念,但是在JavaScript中不被支持。在ES6中已經有了{}塊狀作用域。
if(true){
let a = 1
console.log(a) //1
}
console.log(a) //a is not defined
註:事實上塊狀作用域在ES3就已經存在,只是不明顯。比如catch塊捕獲的異常僅在catch塊可見
詞法作用域(靜態作用域)與動態作用域
在javaScript採用詞法作用域,執行foo函數,先從foo函數內部查找局部變數value,如果沒有,就根據書寫的位置,查找上面一層的代碼,也就是value等於1,所以結果會列印1
var value = 1;
function foo() {
console.log(value);
}
function bar() {
var value = 2;
foo();
}
bar();
// 結果是1
這裡 bind 已經把作用域的範圍進行了修改指向了 { a: 2 }
,而 this 指向的是當前作用域對象
window.a = 3
function test () {
console.log(this.a)
}
test.bind({ a: 2 })() // 2
test() // 3
如果要開啟動態作用域請藉助 bind、with、eval 等。
let&Const
let&Const是ES6之後的語法。let擁有的特性Const都擁有。在ES6之後聲明變數有6個方式var,function,let,const,import,class
var命令和function命令聲明的全局變數依然是頂層對像(window/global)的成員。但let,const,class命令聲明的全局變數,不在屬於頂層對象的成員。從ES6開始全局變數將逐步與頂層對象的屬性脫鉤。
註:let和Const聲明的變數去哪了?參考https://juejin.im/post/5c0be11b6fb9a049df23e388#heading-1
let
let聲明的變數擁有塊級作用域
{
let a = 1
}
console.log(a); //undefined
let聲明的全局變數不是全局對象的屬性
不可以通過window變數名的方式訪問這些變數,而var聲明的全局變數是window的屬性,是可以通過window變數名的訪問
var a = 1
console.log(window.a); //1
let a = 1
console.log(window.a); // undefined
用let重定義變數會拋出一個語法錯誤,var可以重覆定義。
var a = 1
var a = 2
console.log(a) //2
let a = 1
let a = 2
// VM131:1 Uncaught SyntaxError: Identifier 'a' has already been declared
// at <anonymous>:1:1
let聲明的變數不會進行變數提升,存在暫時性死區(TDZ)。在死區結束前變數不會初始化
function test () {
console.log(a)
var a = 1
}
test() //undefined
function test () {//TDZ開始
console.log(a)//
...
...
let a = 1 //TDZ結束
}
test()
// Uncaught ReferenceError: Cannot access 'a' before initialization
const
Const除了具有let的塊級作用域和不會變數,並且它定義的常量,在用const定義變數後,就不能修改。對其修改會拋出異常
const PI = 3.1415;
console.log(PI);
PI = 22;
console.log(PI);
// Uncaught TypeError: Assignment to constant variable.
const聲明的變數必須進行初始化,否則會拋出異常Uncaught SyntaxError: Missing initializer in const declaration
const PI
PI = 3.1415
// Uncaught SyntaxError: Missing initializer in const declaration
Array
ES6新增了一些實用的原生API,方便開發者對Array的操控性更強。
ES5操作數組的方法 concat、join、push、pop、shift、unshift、slice、splice、substring 和 substr 、sort、 reverse、indexOf 和 lastIndexOf 、every、some、filter、map、forEach、reduce
ES6新增操作數組的方法 find、findIndex、fill、copyWithin、Array.from、Array.of、entries、values、key、includes
圍繞數組產生的動作無非是遍歷,轉換,生成,查找。。。。。。(資料庫增刪改查一樣一樣的)
數組遍歷的方法有很多例如for迴圈,forEach,every,for...in,for...of等等
數組的遍歷
舉幾個例子
for迴圈
for (var i = 0; i < array.length; i++) {
console.log(array[i]);
}
forEach
forEach ( ) 方法。等同於for,不支持break;continue,會拋出異常
forEach()對於空數組是不會執行回調函數的
array.forEach(function(i){
console.log(i);
})
[1,2,3,4,5].forEach(function(i){
if(i===2){
return;
}else{
console.log(i) //1,3,4,5
}
})
every
every()方法遍歷可以達到break效果。
every的代碼塊種仍然不能使用break,continue,會拋出異常
[1,2,3,4,5].every(function(i){
if(i===2){
return false; //return false等同於break
}else{
console.log(i)
return true // return true 等同於continue
}
})
for...in
for... in 的目的是用來遍歷對象,而數組剛好是可遍歷對象。。。
for (var index in array) {
//index是索引值,是字元串
console.log(array[index]);
}
for...of
for…of是支持 break、continue的,所以在功能上非常貼近原生的 for。
for…of 遍歷的是一切可遍歷的元素(數組、對象、集合)等。ES6 中允許開發者自定義遍歷
for (variable of iterable) {}
variable:每個迭代的屬性值被分配給該變數
iterable:一個具有可枚舉屬性並且可以迭代的對象
數組轉換功能
偽數組 具有length屬性; 按索引方式存儲數據; 不能調用數組的方法
ES5偽數組轉換為數組
let args = [].slice.call(arguments)
let imgs= [].slice.call(document.querySelectorAll('img'))//NodeList
ES6偽數組轉換為數組
let args = Array.from(arguments)
let imgs = Array.from(document.querySelectorAll('img'))
Array.from(arrayLike,mapFn,thisArg)
//arrayLike 必選 想要轉換成數組的偽數組對象或可迭代對象
//mapFn 可選 新數組中的每個元素會執行該回調函數
//thisArg 可選 執行回調函數 mapFn 時 this 對象
數組的生成
ES5初始化一個長度為5的數組,每個數組元素有預設值
Array.from({ length: 5 }, function () { return 1 })
ES6初始化一個長度為5的數組,每個數組元素有預設值
Array.prototype.from()方法
Array.from({ length: 5 }, function () { return 1 })
Array.prototype.of()方法
Array.of(element0[, element1[, ...[, elementN]]])
elementN 任意個參數,將按順序成為返回數組中的元素。
Array.of(7); // [7]
Array.of(1, 2, 3); // [1, 2, 3]
Array(7); // [ , , , , , , ]
Array(1, 2, 3); // [1, 2, 3]
Array.prototype.fill()方法
fill() 方法用一個固定值填充一個數組中從起始索引到終止索引內的全部元素。不包括終止索引。
let array = [1, 2, 3, 4]
array.fill(0, 1, 2)
// [1,0,3,4]
arr.fill(value[, start[, end]])
value 必選 用來填充數組元素的值
start 可選 起始索引,預設值為0
end 可選 終止索引,預設值為this.length
數組的查找
ES6新增查找方法find(),findIndex()
Array.prototype.find()方法
find() 方法返回數組中滿足提供的測試函數的第一個元素的值,否則返回 undefined。
let array = [5, 12, 8, 130, 44];
let found = array.find(function(element) {
return element > 10;
});
console.log(found);// 12
array.find(function(currentValue, index, arr),thisValue)
//function(currentValue, index, arr) 在數組每一項上執行的函數
//currentValue 當前遍歷到的元素
//index 當前遍歷到的索引
//array 數組本身
//thisArg 執行回調時用作this的對象
Array.prototype.findIndex()方法
findIndex()方法返回數組中滿足提供的測試函數的第一個元素的索引。否則返回-1。其實這個和 find() 是成對的,不同的是它返回的是索引而不是值