摘要:應該算是前期比較容易混淆的一個關鍵字了,在這里,我就打算按照我的理解來說一下首先呢,的值是跟運行時被調用的位置相關的,而不是詞法作用域。來一個例子在瀏覽器中執行,會發現,如果作為一個函數多帶帶調用,那么指向的就是全局對象。
this應該算是前期比較容易混淆的一個關鍵字了,在這里,我就打算按照我的理解來說一下
首先呢,this的值是跟運行時被調用的位置相關的,而不是詞法作用域。
也就是說,他的綁定的值很可能是動態的,不同的調用位置,很可能值就不一樣,比如說:
function foo() { console.log(this.a); } var a = 2; var obj = { a: 3, foo, } foo(); //2 obj.foo(); //3 var c = obj.foo; c(); //2
然后你會驚訝的發現,foo()通過不同的形式調用,他最終的值是不一樣的,咱們這一節主要就來講一講他們里面的這些綁定的規則
默認綁定
獨立的函數調用,它的作用域是作用在全局的,這種綁定規則最常見并且是優先級最低的一種綁定規則。來一個例子
function foo() { console.log(this.a); //2 console.log(this === window); //true } var a = 2; foo();
在瀏覽器中執行,會發現,如果foo()作為一個函數多帶帶調用,那么this指向的就是全局對象windows。
但是呢,也有一種例外,如果函數使用的嚴格模式的話,那么全局對象講無法使用默認綁定,this將會綁定到undefined,還是剛才的例子:
function foo() { "use strict" console.log(this.a); console.log(this === window); } var a = 2; foo(); //Uncaught TypeError: Cannot read property "a" of undefined
可以看到,foo直接拋出一個error,說this是undefined,取不到a,如果用到嚴格模式的時候,可以稍微注意下這個區別
咱們剛剛的例子,說的是函數內用嚴格模式的話,講無法使用默認綁定,那么如果是在函數調用位置用嚴格模式,會受影響嗎
function foo() { console.log(this.a); //2 console.log(this === window); //true } var a = 2; (function () { "use strict" foo(); })();
很明顯,可以看出,是不受影響的,還有一個問題,如果把var定義變成let會怎么樣呢
function foo() { console.log(this.a); //undefined console.log(this === window); //true } let a = 2; (function () { "use strict" foo(); })();
也就是說,let定義并不會加到全局變量中,這個和var的區別需要稍微留意一下
隱式綁定
這一條規則考慮的是是否有上下文對象,舉個例子
function foo() { console.log(this.a); //2 console.log(this === obj); // true } var obj = { a: 2, foo, } obj.foo();
在這種情況下,foo會使用obj的上下文對象來引用函數,此時的this指向的就是obj。
那么如果是嵌套對象這種的,會怎么處理呢?
function foo() { console.log(this.a); // 1 console.log(this === obj) // true console.log(this === obj1) // fale } var obj = { a: 1, foo, }; var obj1 = { a: 2, obj, } obj1.obj.foo();
可以看到,實際上此時foo中的this指向了離他最近的對象obj,也就是說,對象屬性引用鏈的最后一層會影響它的調用位置
還有一種情況。
function foo() { console.log(this.a); } var obj = { a: 3, foo, } var a = 2; var f = obj.foo; f(); // 2
這種情況下,雖然f是obj.foo的引用,但是最后依然用的是默認綁定,而不是隱式綁定,所以說呢,咱們可以這么理解,雖然他是對象中函數的引用,但是在執行的時候,調用的方式確是函數調用的方式,不是對象.屬性()的方式,這塊在使用的時候需要注意一下
顯式綁定
很簡單,顯式綁定就是手動直接改變其this指向的一種方式,這個主要是用幾種api來實現的
function foo() { console.log(this.a); } var obj = { a: 2, }; foo.call(obj); foo.apply(obj); var f = foo.bind(obj); f();
這個就是顯式綁定的常見的三種形式
這三種形式的話,call和apply差不多,就不展開了,詳情看文檔就行,咱們仔細看一下bind函數,來在看一個例子
function foo(num1, num2) { console.log(num1 + num2); //5 console.log(this === obj); // true } var obj = { a: 1, }; var f = foo.bind(obj, 2); f(3);
這個可以看出,bind的用法和call以及apply還是有一些差別的。
注意,如果顯式綁定傳入的是null或者是undefined的話,將會使用默認綁定規則,舉個例子
function foo() { console.log( this.a ); } var a = 2; foo.call( null ); // 2
new綁定
這個主要是new 函數()的綁定形式的,這個的this指向的是函數構造出的那個對象,new的時候,它的執行過程可以大概執行以下幾步
創建一個全新的對象
這個新對象會被執行prototype連接
新對象綁定到函數調用的this
如果函數沒有返回其他對象,那么new表達式中的函數調用會自動返回這個新對象
注意最后一句話,如果函數沒有返回對象,那么就會返回函數調用的新對象,如果返回了一個對象呢,那么結果就是直接返回這個對象
var abc = { a: 10 } function foo() { return abc; } foo.prototype = { b: 20 }; var a = new foo(); console.log(a === abc); // true console.log(a.b); // undefined function bar() { this.a = 10; } bar.prototype = { b: 20 }; var b = new bar(); console.log(b.a); // 10 console.log(b.b); // 20
以上四種常見的this綁定方式已經介紹的差不多了,那么問題來了,誰的優先級更高呢
很明顯,默認綁定的優先級最低,就不展開說了
顯式綁定與隱式綁定哪個優先級高呢,舉個例子
function foo() { console.log( this. a ); } var obj1 = { a: 2, foo: foo }; var obj2 = { a: 3, foo: foo }; obj1.foo(); // 2 obj2.foo(); // 3 obj1.foo.call( obj2 ); // 3 obj2.foo.call( obj1 ); // 2
很明顯,顯式綁定優先級要高于隱式綁定
那么new綁定和顯式綁定誰更高呢,來再看個例子
function foo(something) { this.a = something; } var obj1 = {}; var bar = foo.bind( obj1 ); bar( 2 ); console.log( obj1.a ); // 2 var baz = new bar(3); console.log( obj1.a ); // 2 console.log( baz.a ); // 3
很明顯,new的優先級會更高
所以,這樣的話,優先級排序就出來了,分別為
new綁定 > 顯式綁定 > 隱式綁定 > 默認綁定
以上就是大家常用到的幾種,不過es6出現了一種箭頭函數,箭頭函數理論上不能應用上面四種的任意一種,它的this是根據代碼的詞法作用域來走的,比如說
function foo() { return (a) => { console.log( this.a ); }; } var obj1 = { a: 2 }; var obj2 = { a: 3 }; var bar = foo.call( obj1 ); bar.call( obj2 ); // 2
結果已經很明顯了,
好了,以上內容就講完了,通過我的一些講解,是不是有一點理解了呢,如果有任何的不同意見,歡迎討論哦
參考書籍《你不知道的Javascript》上卷
轉載自:http://www.lht.ren/article/4
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/108856.html
摘要:出現箭頭函數的時候,指向為定義時的上下文對象而非指向時,并且不能被改變首先我們先看一個例子由上面的例子我們可以看出來此時指針在用改變了之后指向的依然是全局對象非嚴格瀏覽器環境中是而非。 javascript基礎之this指針 越往后面學越發現基礎的重要性,所以打算重新過一遍基礎,之后出幾個vue和react的實戰教程。ok,嚴歸正傳。 首先什么是this this是執行上下文創建時確定...
摘要:系統,扎實的語言基礎是一個優秀的前端工程師必須具備的。第一個參數為調用函數時的指向,隨后的參數則作為函數的參數并調用,也就是。和的區別只有一個,就是它只有兩個參數,而且第二個參數為調用函數時的參數構成的數組。 系統,扎實的 javascript 語言基礎是一個優秀的前端工程師必須具備的。在看了一些關于 call,apply,bind 的文章后,我還是打算寫下這篇總結,原因其實有好幾個。...
摘要:本文是面向前端小白的,大手子可以跳過,寫的不好之處多多分鐘搞定常用基礎知識前端掘金基礎智商劃重點在實際開發中,已經非常普及了。 JavaScript字符串所有API全解密 - 掘金關于 我的博客:louis blog SF專欄:路易斯前端深度課 原文鏈接:JavaScript字符串所有API全解密 本文近 6k 字,讀完需 10 分鐘。 字符串作為基本的信息交流的橋梁,幾乎被所有的編程...
摘要:如果有一方是布爾值,則轉換為,轉換為,再進行判斷。等同運算符類型不同返回類型相同如果同為數字字符串則比較值如果同為布爾值,相同則為不同為如果兩個操作數同為引用類型,且引用的為同一個對象函數,數組,則相同。 本文主要記錄平時開發遇到的知識點和小技巧 相等判斷(==) 類型相同: 判斷其值是否相同 類型不同: 1. 如果數字和字符串比較, 則字符串會被隱式轉換為數字,在做判斷。 2....
摘要:在最開始的時候,原型對象的設計主要是為了獲取對象的構造函數。同理數組通過調用函數通過調用原型鏈中描述了原型鏈的概念,并將原型鏈作為實現繼承的主要方法。 對象的創建 在JavaScript中創建一個對象有三種方式。可以通過對象直接量、關鍵字new和Object.create()函數來創建對象。 1. 對象直接量 創建對象最直接的方式就是在JavaScript代碼中使用對象直接量。在ES5...
閱讀 486·2019-08-30 15:44
閱讀 901·2019-08-30 10:55
閱讀 2731·2019-08-29 15:16
閱讀 931·2019-08-29 13:17
閱讀 2805·2019-08-26 13:27
閱讀 572·2019-08-26 11:53
閱讀 2123·2019-08-23 18:31
閱讀 1891·2019-08-23 18:23