今天在控制台寫刪除數組第一個元素的代碼時,發現了一個問題,以下是書中源碼,
let arr = [1,2,3,4,5] Array.prototype.reIndex = function (myArray) { const newArray = []; for (let i=0; i<myArray.length; i++) { if (myArray[i] !== undefined) { newArray.push(myArray[i]); } } return newArray; } Array.prototype.removeFirPos = function () { for (let i=0;i<this.length;i++){ this[i] = this[i+1] } return this.reIndex(this) } arr = arr.removeFirPos() console.log(arr)//控制台輸出
按這個源碼,我進行了更改,使用了箭頭函數,如下
let arr = [1,2,3,4,5] Array.prototype.reIndex = (myArray) => { const newArray = []; for (let i=0; i<myArray.length; i++) { if (myArray[i] !== undefined) { newArray.push(myArray[i]); } } return newArray; } Array.prototype.removeFirPos = () => { for (let i=0;i<this.length;i++){ this[i] = this[i+1] } return this.reIndex(this) } arr = arr.removeFirPos() console.log(arr)//控制台輸出
然后發現報錯,typeerror:this.reIndex is not a function。查找下發現箭頭函數沒有自己的this。
我又想了一下,變量arr調用方法removeFirPos(),那么這個this不就是指向了arr嗎,后來一想。。。這不是非箭頭函數時候的指向嘛
然后繼續網絡查找找到了一句話:由於箭頭函數不綁定this, 它會捕獲其所在(即定義的位置)上下文的this值, 作為自己的this值
所有this的指向在非嚴格模式下是window。為了更好的理解我編寫以下代碼
function Test1() { console.log(this); setTimeout(() => { console.log('這是箭頭函數',this) }) } function Test2() { console.log(this); setTimeout(function () { console.log('這是普通函數',this) }) } let t1 = new Test1() let t2 = new Test2()
輸出結果如下
VM90:2 Test1 {}
VM90:9 Test2 {}
VM90:4 這是箭頭函數 Test1 {}
VM90:11 這是普通函數 Window {window: Window, self: Window, document: document, name: "", location: Location, …}
原因是箭頭函數捕獲的是其所在上下文中的this值,而由於setTimeout()調用的代碼運行在所在函數完全分離的執行環境上,this指向的是window(其實我也沒咋明)
到這基本原因就明確了。
后面在我查找知識的時候,發現了let和var聲明的不同,貼下人家的代碼,這是在知乎找的(https://zhuanlan.zhihu.com/p/149239478)
var bar = { myName:"bar", printName: function () { console.log(myName) } } let myName = "global" let _printName = bar.printName _printName() // global bar.printName() // global
對於這個代碼都比較好理解,前面全局變量bar,myName,_printName的聲明,然后_printName聲明這行,bar.printName是一函數,讓變量_printName執行了這一函數
然后在全局作用域下直接調用了函數,則輸出的myName將在全局域中查找為global;最后一行相同原理
然后對代碼稍加更改
var bar = { myName:"bar", printName: function () { console.log(this.myName) } } let myName = "global" let _printName = bar.printName _printName() // undefined bar.printName() // bar
仍然是_printName變量執行函數bar.printName,這次執行時因為是全局作用域下,輸出的應該是window.myName。這下問題出來了,全局作用域下不是有myName嗎
非也,起初我也迷惑,但后來代碼放在控制台跑一下,發現其實let聲明變量的作用域並非全域,而是在script域中,也就是說全域並沒有myName這一變量,故輸出undefined
bar調用函數printName執行,則執行環境在bar塊作用域中,故輸出bar
萌新小白,請教
