摘要:至于,其只是以數組的方傳入參數,其它部分是一樣的,如下它們也可用于在中的類繼承中,調用父級構造器。間接調用,調用了父級構造器對比方法和,它倆都立即執行了函數,而函數返回了一個新方法,綁定了預先指定好的,并可以延后調用。
其實this是一個老生常談的問題了。關于this的文章非常多,其實我本以為自己早弄明白了它,不過昨天在做項目的過程中,還是出現了一絲疑惑,想到大概之前在JavaScript weekly里收藏待看的一篇詳解this的文章(后有鏈接,也附上了稀土上的中文譯文)和另一篇一位前輩推薦的文章,就把它們看了看,對this的認識確實提升了一些。
JavaScript 中的’this‘是動態的,它在函數運行時被確定而非在函數聲明時被確定。所有的函數都可以調用"this",這無關于該函數是否屬于某個對象。關于this,主要有以下四種情況。
1.被當做對象的方法被調用如果該函數是被當做某一個對象的方法,那么該函數的this指向該對象;
var john = { firstName: "John" } function func() { alert(this.firstName + ": hi!") } john.sayHi = func john.sayHi() // this = john
這里有一點值得注意,當一個對象的方法被取出來賦值給一個變量時,該方法變為函數觸發,this指向window或underfind(嚴格模式)。
2.函數之內調用當函數中有 this,其實就意味著它被當做方法調用,之間調用相當于把他當做window對象的方法,this指向window,值得注意的是ES5其實是規定這種情況this=undefined的,只瀏覽器大多還是按照老的方法執行(本人在最新版的Chrome,Safari,Firefox中測試都指向window(201607)),在火狐下使用嚴格模式指向undefined;
func() function func() { alert(this) // [object Window] or [object global] or kind of.. }
為了傳遞this,()之前應該為引用類型,類似于obj.a 或者 obj["a"],不能是別的了。
這里還存在一個小坑,當對象的方法中還存在函數時,該函數其實是當做函數模式觸發,所以其this默認為window(嚴格模式下為undefined)解決辦法是給該函數綁定this。
var numbers = { numberA: 5, numberB: 10, sum: function() { console.log(this === numbers); // => true function calculate() { // this is window or undefined in strict mode console.log(this === numbers); // => false return this.numberA + this.numberB; } return calculate(); } }; numbers.sum(); // => NaN or throws TypeError in strict mode
var numbers = { numberA: 5, numberB: 10, sum: function() { console.log(this === numbers); // => true function calculate() { console.log(this === numbers); // => true return this.numberA + this.numberB; } // use .call() method to modify the context return calculate.call(this); } }; numbers.sum(); // => 153.在new中調用
一個引用對象的變量實際上保存了對該對象的引用,也就是說變量實際保存的是對真實數據的一個指針。
使用new關鍵字時this的改變其實有以下幾步:
創建 this = {}.
new執行的過程中可能改變this,然后添加屬性和方法;
返回被改變的this.
function Animal(name) { this.name = name this.canWalk = true } var animal = new Animal("beastie") alert(animal.name)
需要注意的是如果構造函數返回一個對象,那么this指向返回的那個對象;
function Animal() { this.name = "Mousie"; this.age = "18"; return { name: "Godzilla" } // <-- will be returned } var animal = new Animal() console.log(animal.name) // Godzilla console.log(animal.age)//undefined
這里需要注意的是不要忘記使用new,否則不會創建一個新的函數。而是只是執行了函數,相當于函數調用,this其實指向window
function Vehicle(type, wheelsCount) { this.type = type; this.wheelsCount = wheelsCount; return this; } // Function invocation var car = Vehicle("Car", 4); car.type; // => "Car" car.wheelsCount // => 4 car === window // => true4.明確調用this,使用call和apply
這是最具JavaScript特色的地方。
如下代碼:
func.call(obj, arg1, arg2,...)
第一個參數將作為this的指代對象,之后的參數將被作為函數的參數,解決方法是使用bind。
function Animal(type, legs) { this.type = type; this.legs = legs; this.logInfo = function() { console.log(this === myCat); // => true console.log("The " + this.type + " has " + this.legs + " legs"); }; } var myCat = new Animal("Cat", 4); // logs "The Cat has 4 legs" setTimeout(myCat.logInfo.bind(myCat), 1000); // setTimeout??
var john = { firstName: "John", surname: "Smith" } function func(a, b) { alert( this[a] + " " + this[b] ) } func.call(john, "firstName", "surname") // "John Smith"
至于apply,其只是以數組的方傳入參數,其它部分是一樣的,如下:
func.call(john, "firstName", "surname") func.apply(john, ["firstName", "surname"])
它們也可用于在 ES5 中的類繼承中,調用父級構造器。
function Runner(name) { console.log(this instanceof Rabbit); // => true this.name = name; } function Rabbit(name, countLegs) { console.log(this instanceof Rabbit); // => true // 間接調用,調用了父級構造器 Runner.call(this, name); this.countLegs = countLegs; } var myRabbit = new Rabbit("White Rabbit", 4); myRabbit; // { name: "White Rabbit", countLegs: 4 }5..bind()
對比方法 .apply() 和 .call(),它倆都立即執行了函數,而 .bind() 函數返回了一個新方法,綁定了預先指定好的 this ,并可以延后調用。
.bind() 方法的作用是創建一個新的函數,執行時的上下文環境為 .bind() 傳遞的第一個參數,它允許創建預先設置好 this 的函數。
var numbers = { array: [3, 5, 10], getNumbers: function() { return this.array; } }; // Create a bound function var boundGetNumbers = numbers.getNumbers.bind(numbers); boundGetNumbers(); // => [3, 5, 10] // Extract method from object var simpleGetNumbers = numbers.getNumbers; simpleGetNumbers(); // => undefined or throws an error in strict mode
使用.bind()時應該注意,.bind() 創建了一個永恒的上下文鏈并不可修改。一個綁定函數即使使用 .call() 或者 .apply()傳入其他不同的上下文環境,也不會更改它之前連接的上下文環境,重新綁定也不會起任何作用。
只有在構造器調用時,綁定函數可以改變上下文,然而這并不是特別推薦的做法。
箭頭函數并不創建它自身執行的上下文,使得 this 取決于它在定義時的外部函數。
箭頭函數一次綁定上下文后便不可更改,即使使用了上下文更改的方法:
var numbers = [1, 2]; (function() { var get = () => { console.log(this === numbers); // => true return this; }; console.log(this === numbers); // => true get(); // => [1, 2] // 箭頭函數使用 .apply() 和 .call() get.call([0]); // => [1, 2] get.apply([0]); // => [1, 2] // Bind get.bind([0])(); // => [1, 2] }).call(numbers);
這是因為箭頭函數擁有靜態的上下文環境,不會因為不同的調用而改變。因此不要使用箭頭函數定義方法
function Period (hours, minutes) { this.hours = hours; this.minutes = minutes; } Period.prototype.format = () => { console.log(this === window); // => true return this.hours + " hours and " + this.minutes + " minutes"; }; var walkPeriod = new Period(2, 30); walkPeriod.format(); // => "undefined hours and undefined minutes"參考
Four scents of "this"
Gentle explanation of "this" keyword in JavaScript
JavaScript This 之謎(譯文)
強烈推薦覺得沒弄明白的同學看看上面三篇文章,其中第三篇是第二篇的譯文。如果大家對this還有疑問,也歡迎大家一起討論,交流促進思考,共同進步。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/86447.html
摘要:理解的函數基礎要搞好深入淺出原型使用原型模型,雖然這經常被當作缺點提及,但是只要善于運用,其實基于原型的繼承模型比傳統的類繼承還要強大。中文指南基本操作指南二繼續熟悉的幾對方法,包括,,。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。 怎樣使用 this 因為本人屬于偽前端,因此文中只看懂了 8 成左右,希望能夠給大家帶來幫助....(據說是阿里的前端妹子寫的) this 的值到底...
摘要:正在失業中的課多周刊第期我們的微信公眾號,更多精彩內容皆在微信公眾號,歡迎關注。若有幫助,請把課多周刊推薦給你的朋友,你的支持是我們最大的動力。是一種禍害譯本文淺談了在中關于的不好之處。淺談超時一運維的排查方式。 正在失業中的《課多周刊》(第3期) 我們的微信公眾號:fed-talk,更多精彩內容皆在微信公眾號,歡迎關注。 若有幫助,請把 課多周刊 推薦給你的朋友,你的支持是我們最大的...
摘要:正在失業中的課多周刊第期我們的微信公眾號,更多精彩內容皆在微信公眾號,歡迎關注。若有幫助,請把課多周刊推薦給你的朋友,你的支持是我們最大的動力。是一種禍害譯本文淺談了在中關于的不好之處。淺談超時一運維的排查方式。 正在失業中的《課多周刊》(第3期) 我們的微信公眾號:fed-talk,更多精彩內容皆在微信公眾號,歡迎關注。 若有幫助,請把 課多周刊 推薦給你的朋友,你的支持是我們最大的...
閱讀 1108·2021-11-16 11:45
閱讀 3128·2021-10-13 09:40
閱讀 720·2019-08-26 13:45
閱讀 1199·2019-08-26 13:32
閱讀 2173·2019-08-26 13:23
閱讀 915·2019-08-26 12:16
閱讀 2827·2019-08-26 11:37
閱讀 1753·2019-08-26 10:32