大綱

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 = 'https://www.cnblogs.com/xingchenhuanqi/p/inner';
}
console.log(testValue); // 報錯:ReferenceError: testValue is not defined
如果想讀取函式內部的變數,必須借助return或者閉包
//使用return方式
function bar(value) {
var testValue = 'https://www.cnblogs.com/xingchenhuanqi/p/inner';
return testValue + value;
}
console.log(bar('fun')); // "innerfun"
return 是函式對外交流的出口,而 return 可以回傳的是函式,根據作用域的規則,函式bar內部的子函式inner是可以獲取函式bar作用域內的變數result
//使用閉包方式
function bar(value) {
var testValue = 'https://www.cnblogs.com/xingchenhuanqi/p/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 = https://www.cnblogs.com/xingchenhuanqi/p/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),在死區結束前變數不會初始化,在這個區間即使是使用typeof()也會報錯
function test () {
console.log(a)
var a = 1
}
test() //undefined
function test () {//TDZ開始
console.log(a)// Cannot access 'a' before initialization
typeof(a)// Cannot access 'a' before initialization
...
...
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() 是成對的,不同的是它回傳的是索引而不是值
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/92056.html
標籤:JavaScript
上一篇:當 JS 工程師遇到了 TypeScript 會發生什么?
下一篇:js 獲取視頻的總時長
