摘要:而當做普通函數調用的話,實際上即第種情況下,對函數普通調用,此時的指向這是正常情況下,會正確返回并且指向該對象,但是在構造函數當中,如果返回了一個對象,那么會指向返回的那個對象。
this應該是一個討論了很久的話題了。其中,關于this的文章,在很多的博客當中也有很多介紹,但是,以前我都是一知半解的去了解它,就是看博客當中,只介紹了一些情況下的 this 的使用方式,但是也并沒有自己去做過總結。剛好是在掘金當中有看到一篇關于this的一些詳細文章,文末會附上鏈接以及英文原文,這里純粹是自己進行一個總結,以后方便自己進行回顧以及加深印象。希望這篇文章對于你了解this有一定的幫助,文末還有一些練習題噢~希望真的對你們有幫助。(因為寫項目過程中,一直被 this 坑過,卻找了很久的 bug ,我真是 樂了狗)
在了解this之前,相信大家都應該會知道作用域這個知識點的存在,函數在創建之后,會構建自己的執行環境以及作用域,這是一開始就確定了。但是實際的上下文(context)環境,也可以理解為就是this,它是動態確定的,即在函數運行時才確定this所指向的對象,而非聲明時所指向的對象。
關于this,總結起來,主要有以下幾個途徑能夠被運用到。
1 對象方法中調用this如果函數被當中對象的一個方法進行調用,則this值指向該對象。
var person = { name: "Alice", sayName: function() { alert("welcome " + this.name); } } person.sayName(); // this == person, alert: "welcome Alice"
在這里,函數的this指向該對象(即 person);但是有一點需要注意,就是當對象的方法被賦予給一個變量時,其則變為了函數觸發,此時的this為 window 或者 undefined(嚴格模式下),如下:
var name = "Bob"; var person; // 即上面的定義,此不拓展詳細,直接使用 var say = person.sayName; // this == window || undefined say(); // "welcome Bob" || throw an error: Cannot read property "name" of undefined(...)2 函數內部使用
在函數內部當中使用了 this,即函數被當做方法使用,不同于 1 當中作為對象的方法使用,此時調用,是在全局作用域下進行調用,即在window下進行調用,由定義可以知道,在全局作用域下聲明一個函數,其自動加為window的一個屬性。this此時名正言順的會指向window,嚴格模式下為 undefined
function sayThis() { alert(this == window); // true }
結合第一點,函數作為對象的一個方法使用,這里存在一個小坑,即閉包,啥是閉包,這個在這里就不扯開了,最簡單的理解就是 Function that returns function,如果不理解什么是閉包的話,可以去翻翻 《JavaScript 高級程序設計》第七章關于閉包的相關內容。第一點當中存在一個小坑,就是將對象的方法賦予給一個變量的時候,其變為函數觸發,此時的 this 實際上是指向 window(非嚴格模式)。
那么,當函數中返回一個函數,此時在對象當中調用該方法,其就相當于是函數觸發,此時的 this,在不做任何上下文綁定的前提之下,其指向 window(非嚴格模式)。
var name = "Bob", person = { name: "Alice", sayName: function() { console.log(this === person); // true return function() { console.log(this === person); // false console.log(this === window); // true console.log(this.name); // Bob }; } }; person.sayName()();
當然,要解決這個問題的方法,很簡單,就是給他綁定一個上下文。
var name = "Bob", person = { name: "Alice", sayName: function() { console.log(this === person); // true return function() { console.log(this === person); // true console.log(this === window); // false console.log(this.name); // Alice }.bind(this); } }; person.sayName()();3 new 當中進行使用
我們知道在使用 new 方法創建對象的時候,會經過如下這些個過程:
創建對象,將 this 值賦予新的對象
調用構造函數,為 this 添加屬性和方法
返回 this 給當前的對象
function Person(name, age) { this.name = name; this.age = age; } var person1 = new Person("Alice", 29); console.log(person1.name); // Alice
這里要記得使用 new 運算符,否則,其只能算是普通的調用,而不是創建一個新的實例對象。而當做普通函數調用的話,實際上即 第 2 種情況下,對函數普通調用,此時的 this 指向 window
function Person(name, age) { this.name = name; this.age = age; return this; } var person1 = Person("Alice", 29); console.log(person1.name); // Alice console.log(window.name); // Alice console.log(person1 === window); // true
這是正常情況下,this 會正確返回并且指向該對象,但是在構造函數當中,如果返回了一個對象,那么 this 會指向返回的那個對象。
function Person(name, age) { this.name = name; this.age = age; return { name: "Bob" }; } var person1 = new Person("Alice"); console.log(person1.name); // Bob console.log(person1.age); // undefined
題外話,類似的,聯想到 var a = new Person(),則 a instanceof Person一定返回 true嗎?留給你們想一想咯。
4 使用 call、apply 或 bind 改變 this在引用類型 Function當中,函數存在兩個方法屬性,call 和 apply,在 ECMAScript5當中,加入了 bind 方法。題外話,他們三者區別,應該都知道了吧,不知道的加緊補習呀。
var name = "Bob"; var person = { name: "Alice", age: 29 } function sayName() { console.log(this.name); } sayName.call(person); // Alice
這里是使用了 call 方法來改變了 this的執行環境,至于使用 apply,效果一樣,只是二者差別在于傳入參數的不同。
func.call(context, arg1, arg2, ...) func.apply(context, [arg1, arg2, ...])
使用 bind 方法進行上下文的改變,bind 方法與 call 和 apply有著本質的不同,其不同點是,bind()函數返回的是一個新的函數,即方法,而后兩者則都是立即執行函數,使用的時候即調用了該函數,返回方法操作的結果。
并且,使用 bind()方法創建的 上下文,其為永久的上下文環境,不可修改,即使是使用 call 或者 apply方法,也無法修改 this 所指向的值。
var name = "Bob"; var person = { name: "Alice", age: 29 } function sayName() { console.log(this.name); } var say = sayName.bind(person); say(); // Alice sayName(); // Bob5 箭頭函數
箭頭函數并不創建其自身的上下文,其上下文 this,取決于其在定義時的外部函數。
并且,箭頭函數擁有靜態的上下文,即一次綁定之后,便不可再修改,即使是用了 第 4 種用途當中的改變上下文的方法,也不為之動容。
var num = [1, 2, 3]; (function() { var showNumber = () => { console.log(this === num); // true console.log(this); // [1, 2, 3] } console.log(this === num); // true showNumber(); // true && [1, 2, 3] showNumber.call([1, 2]); // true && [1, 2, 3] showNumber.apply([1, 2]); // true && [1, 2, 3] showNumber.bind([1, 2])(); // true && [1, 2, 3] }).call(num);
由于箭頭函數的外部決定上下文以及靜態上下文等的特性,不太建議使用箭頭函數在全局環境下來定義方法,因為不能通過其他方法改變其上下文。這很蛋疼。
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); console.log(walkPeriod.hours); walkPeriod.format(); // => "undefined hours and undefined minutes"
此時的 this 實際上是指向了 window,所以 this.hours 和 this.minutes實際上沒有聲明的,故為 undefined。
在全局環境下,還是選用 函數表達式 來進行函數的定義,可以保證正確的上下文環境
function Period (hours, minutes) { this.hours = hours; this.minutes = minutes; } Period.prototype.format = function() { console.log(this === walkPeriod); // => true return this.hours + " hours and " + this.minutes + " minutes"; }; var walkPeriod = new Period(2, 30); walkPeriod.format(); // "2 hours and 30 minutes"練習
// 練習1 var func = (function(a) { this.a = a; return function(a) { a += this.a; return a; } })(function(a, b) { return a; }(1, 2)) func(4) // ? // 練習2 var x = 10, foo = { x: 20, bar: function() { var x = 30; return this.x; } } console.log(foo.bar()); console.log((foo.bar)()); console.log((foo.bar = foo.bar)()); console.log((foo.bar, foo.bar)());
希望看完這篇文章,這兩個練習題,你是能夠做出來的呀~ 好好分析一下唄。如果不確定的話,可以在留言板上,咱們相互討論一下呀~
參考JavaScript This之謎 (第二個參考的譯文)
Gentle explanation of "this" keyword in JavaScript
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/87892.html
摘要:一般我們對這種構造函數命名都會采用,并把它稱呼為類,這不僅是為了跟的理念保持一致,也是因為的內建類也是這種命名。由生成的對象,其是。這是標準的規定。本文的主題是原型系統的變遷,所以并沒有涉及和對原型鏈的影響。 概述 JavaScript 的原型系統是最初就有的語言設計。但隨著 ES 標準的進化和新特性的添加。它也一直在不停進化。這篇文章的目的就是梳理一下早期到 ES5 和現在 ES6,...
摘要:第一部分請點擊快速掌握面試基礎知識一閉包閉包由一個函數以及該函數定義是所在的環境組成。當匿名函數執行的時候,的值為。這個問題可以改用后面會介紹方法來解決,通過對每一個匿名函數構建獨立的外部作用域來實現。 譯者按: 總結了大量JavaScript基本知識點,很有用! 原文: The Definitive JavaScript Handbook for your next develope...
摘要:引用是從匿名函數內部引用自身的唯一方法,不過,最好的方法是避免使用匿名函數,至少在那些需要引用自身的時候,使用命名函數或者表達式。 [翻譯]Chapter1 this or that 第一次翻譯,翻譯的不好,已經再盡全力s去翻譯了,如果哪里看不明點,請出門左轉下邊原文地址 英文原文點擊這里 javascript中最令人困惑的東西就是this關鍵字,它在每個函數作用域中都會自動定義的一個...
摘要:那么,它到底是如何工作的呢讓我們從一種更簡單的實現開始實際上這種實現代碼更短,并且更易讀是函數原型中的一個函數,它調用函數,使用第一個參數作為參數,并傳遞剩余參數作為被調用函數的參數。 原文:The Most Clever Line of JavaScript 作者:Seva Zaikov 原文 最近 一個朋友 發給我一段非常有趣的 JavaScript 代碼,是他在某個 開源庫中...
摘要:運行規則根據的運作原理,我們可以看到,的值和調用棧通過哪些函數的調用運行到調用當前函數的過程以及如何被調用有關。 1. this的誕生 假設我們有一個speak函數,通過this的運行機制,當使用不同的方法調用它時,我們可以靈活的輸出不同的name。 var me = {name: me}; function speak() { console.log(this.name); }...
閱讀 2445·2021-10-13 09:40
閱讀 3334·2019-08-30 13:46
閱讀 1119·2019-08-29 14:05
閱讀 2952·2019-08-29 12:48
閱讀 3653·2019-08-26 13:28
閱讀 2141·2019-08-26 11:34
閱讀 2276·2019-08-23 18:11
閱讀 1156·2019-08-23 12:26