1.全局上下文中的 this
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>this 指向</title> </head> <body> <script type="text/javascript"> /* 1.全局上下文中的 this 瀏覽器環境下: 嚴格模式下: Window 非嚴格模式下: Window */ 'use strict'; // 嚴格模式 // demo 1: console.log(this); // demo 2: var a = this; console.log(a); // demo 3: b = this; // 注意:嚴格模式下,變量必須得聲明;非嚴格模式,能夠省略聲明符 console.log(b); /* 分析: 瀏覽器環境下: 在整個 執行上下文 建立過程,都是在 全局執行環境下進行的,而這種由全局執行環境建立的執行上下文,又叫 「全局執行上下文」; 而在 Web瀏覽器中,全局執行環境被認爲是 window對象; 結果 輸出了 Window對象,也就說 this 指向了「執行上下文的環境對象」; 因此,結論 「this 指向其執行上下文的環境對象」,經過; */ </script> </body> </html>
2.函數上下文的 this
嚴格模式:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>this 指向</title> </head> <body> <script type="text/javascript"> /* 2.函數上下文中的 this 瀏覽器環境下: 嚴格模式下 */ // demo : 'use strict'; // 嚴格模式 var a = 1; // demo 1: function test1(){ console.log(this); } test1(); // strict-->undefined nostrict-->Window /* 首先,要了解一點,函數的 this指向,有些特殊; 它與全局環境中的 this 不同,由於全局中的 this 已經明顯指出了它的執行上下文環境就是 全局環境,那麼它的 this 必定指向全局對象 Window; 根據 《JavasScript 高級程序設計》中提到的,關於 javascript嚴格模式,this 指向的說明:「嚴格模式下,函數的 this值始終是 指定的值,不管這個指定的值是什麼」; 那麼,咱們一直是在求證咱們的「this指向 其執行上下文的環境對象」,那麼咱們就開始試着把這個 「指定的值」理解爲咱們所說的 環境對象;看看在以後的論述中是否說的通; 而後咱們作一個這樣的總結,也就是說,在嚴格模式下,function的環境對象是指定的; 結合上面 demo在嚴格模式下運行的結果爲 undefined來看,應該是說的通了, 分析: 由於 test1() 在執行的時候,並無給它指定環境對象,因此 得出結果是 undefined; */ /* 下面,咱們給 test1() 指定 一個環境變量後再看一下輸出; */ test1.call(window); //strict-->Window nostrict-->Window /* 也許有人會問,window能夠直接調用 test1(),而且輸出 this值爲 Window, 這是爲何呢? 以下: */ window.test1(); // Window /* 這是由於,function test1 在全局做用域下聲明的,而全局做用域下聲明的變量都是 window對象的方法,因此能夠用這樣的 對象.方法() 的形式 執行函數; 而,函數做爲對象方法被使用的時候,函數的執行上下文環境對象就爲 這個擁有它的對象; */ /* 咱們再給 test1() 指定其它的環境對象,看看狀況是什麼樣的; */ var obj = {name: 'obj'}; test1.call(obj) // {name: 'obj'} test1.call(null) // null test1.call(undefined) // undefined /* 還真是 指定啥就是啥啊! */ /* 以上的論述 最終思想,是證實了,嚴格模式下,函數的 this 指向是指定的對象,即便,指定的是 null 和 undefined, this的指向也是 null 和 undefined; 若是沒有指定 會返回 undefined; 而咱們 把這個被指定的對象,來做爲 test()執行上下文的環境對象,那麼 咱們的結論 是說的通的; 歸納一下: 瀏覽器環境 嚴格模式下: 函數做爲單獨函數 執行: 1.函數執行上下文的環境對象 是指定的,指定什麼就是什麼;this指向這個指定的環境對象; 函數做爲對象方法 執行: 2.這個函數執行上下文的環境對象就是這個擁有它的對象;this指向這個擁有它的對象; */ </script> </body> </html>
非嚴格模式:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>this 指向</title> </head> <body> <script type="text/javascript"> /* 2.函數上下文中的 this 瀏覽器環境下: 非嚴格模式下 */ /* 好了,嚴格模式下,咱們已經得出結論了; 咱們再來看看非嚴格模式下 輸出結果會是什麼樣; */ // demo 1: 做爲單獨函數 執行 // "use strict" function test1(){ console.log(this); } test1(); // Window test1.call(window); // Window window.test1(); // Window var obj = {name: 'obj'}; test1.call(obj) // {name: 'obj'} test1.call(null) // Window test1.call(undefined) // Window // demo 2: 做爲對象方法 執行 var obj2 = { a:1, sayThis: function(){ console.log(this); } } obj2.sayThis(); // obj2 /* 咱們發現,原來 沒有被指定執行上下文環境對象 或 指定了執行上下文環境變量爲 undefined 和 null 的,它的 this 值都指向了 Window 對象; 非嚴格模式下,咱們應該能夠這樣下個結論, "非嚴格模式下,若是函數在執行時 沒有指定執行上下文環境對象 或者 指定執行上下文環境對象爲 null 或 undefined, 那麼它的執行上下文環境對象 會默認爲 全局對象", 也就是 this 會指向 全局對象; 歸納一下: 瀏覽器環境 非嚴格模式下: 函數做爲單獨函數 執行: 1.函數執行上下文的環境對象 是指定的,指定什麼就是什麼;this指向這個指定的環境對象; 函數做爲對象方法 執行: 2.這個函數執行上下文的環境對象就是這個擁有它的對象;this指向這個擁有它的對象; */ </script> </body> </html>
複雜測試:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>this 指向</title> </head> <body> <script type="text/javascript"> /* 2.函數上下文中的 this 瀏覽器環境下: */ /* 有人會說啊,你這都是在全局環境下運行的例子而且例子太簡單了,而後就下結論了,這太不具有說服力了: 我的一直認爲,分析原理性的東西,越是從簡單入手,才能越是切中要害,掌握單個知識點的精髓,複雜的分析 只是由 n多個小知識點 組合而成而已; 我下面來個複雜點的,驗證咱們的結論; */ // demo 3: "use strict" var name = "sss"; var obj = { name: "jjj", sayName: function(){ console.log(this); innerFunction(); function innerFunction(){ console.log(this); } return function(){ console.log(this); } } } // scene 1: obj.sayName(); // strict -->obj undefined no strict -->obj window /* 分析: sayName()做爲 obj對象方法來執行,它的環境對象是 obj對象; innerFunction() 沒有指定執行上下文的環境對象, 因此,執行上下文的環境對象,嚴格模式下,爲 undefined; 非嚴格模式下,爲 Window對象; */ // scene 2: obj.sayName()(); // strict -->obj undefined undefined no strict-->obj window window /* --> 上式的執行 至關於 下面兩句表達式 */ var test = obj.sayName(); // strict -->obj undefined no strict-->obj window test(); // strict -->undefined no strict-->window /* 分析: 先執行 obj.sayName(), 輸出結果的緣由,已在 scene 1中作了說明,再也不重複; 執行 test(),因爲 test表明 obj.sayName()執行後,返回的匿名函數,當這個匿名函數 執行時,因爲沒有給它指定 執行上下文的環境對象, 因此,它的執行上下文環境對象,嚴格模式下 是 undefined; 非嚴格模式下 是 Window對象; 輸出結果,與結論相穩合; */ // scene 3: test.call(obj); // strict -->obj no strict-->obj /* 分析: 接着 scene 2的解釋,test表明 obj.sayName()執行後,返回的匿名函數,而後又給這個函數指定了執行上下文的環境對象 obj; 從輸出結果來看,這符合給出的結論; */ /* 綜上,瀏覽器環境下,咱們的對 函數的執行上下文環境對象的結論歸納 是成立的; */ </script> </body> </html>
3.對象屬性中的 this
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>this 指向問題</title> </head> <body> <script type="text/javascript"> /* 3.對象屬性中的 this 注意:這裏指的是以下的形式,不要把它和 對象方法中的 this搞混;對象方法中的 this,要規劃到 函數上下文的 this中; 瀏覽器環境下: 嚴格模式下:Window 非嚴格模式下: Window */ 'use strict' var obj = { a: 1, b: 2, c: this, sayHi: function(){ console.log('Hi'); } } console.log(obj.c); // Window /* 分析: 其實,這樣的對象字面量的形式,可能看起來會有些困惑,咱們能夠變形來分析;由於對象字面量的形式,其實是由以下的形式簡化而來的寫法; var obj = new Object(); obj.a =1; obj.b = 2; obj.c = this; obj.sayHi = function(){ console.log('Hi'); } 這樣看來就清晰不少了,上邊這段代碼執行的時候,不就是把全局執行上下文的環境對象賦給 obj.c 屬性嗎,關於全局上下文的 this,咱們已經介紹過了; 並且結果,也正符合咱們此時所得出的結果; 因此,這樣做爲對象中的 this,能夠規到全局執行上下文中的 this 一類中,this 指向全局對象 window; */ /* 一個例子,可能沒有什麼說服力,咱們再來個嵌套形式的 來證明咱們的結論, 以下: */ var o1 = { a: 1, b: this, o2: { a: 1, b: this } } console.log(o1.o2.b); // Window /* 結果依然是 Window, 其實 如上的形式,能夠變形爲: var o1 = new Object(); o1.a = 1, o1.b = this; o1.o2 = new Object(); o1.o2.a = 1; o1.o2.b = this; 上面這段代碼 在執行時,它的執行上下文的環境對象依然是 Window對象;因此說 this依然指向 Window對象; */ /* 歸納:對象屬性中的 this指向 全局對象 Window對象; */ </script> </body> </html>
4.構造函數 和 原型方法中的 this
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> </head> <body> <script type="text/javascript"> /* 4.構造函數 和 原型方法中的 this 瀏覽器環境下: 嚴格模式下:以構造函數名命名的新對象 非嚴格模式下: 以構造函數名命名的新對象 */ // "use strict" function Person(){ console.log(this); // Person {} this.name = 'jack'; console.log(this); // Person {name: "jack"} } Person.prototype.sayThis = function(){ console.log(this); } Person.prototype.sayThis(); // {sayThis: ƒ, constructor: ƒ} new Person(); // Person {} --> // Person {name: "jack"} /* 分析 1: 構造函數與普通函數的最重要的不一樣之處,就是構造函數可經過 new操做符,創造實例; 那麼在利用構造函數創造實例的過程到底發生了什麼呢? 其實呢,是要經歷如下幾個過程的: 1.創造一個 新對象,做爲執行上下文的環境對象;(注意:這裏爲何說成是新對象,而不說成是空對象呢,由於 function默認是有 prototype屬性存在的,它指向原型對象) 2.構造函數開始執行,它的執行上下文環境對象就爲這個新對象,也就是說 this指向這個新對象; 3.利用 this來給這個新對象賦值; 4.返回這個被賦值以後的 新對象; 經過上面 new Person() 執行後輸出的結果來看,確實是這樣的一個過程;沒有沒給 this賦值前輸出的是 Person{}, 賦值後,輸出的 Person{name:'jack'}; 歸納: 構造函數中的執行上下文的環境對象爲,以構造函數名命名的新對象; 分析 2: 至於原型方法中 this, 其實,在咱們瞭解了 「函數上下文的 this」 以後,應該很清楚了,它指向給它指定的環境對象,也就是肯定了的 構造函數的原型對象; 因此,Person.prototype.sayThis() 執行後,輸出的結果是 Person構造函數的原型對象 --> Person.prototype 對象; */ </script> </body> </html>
5.應用 call、apply、bind 方法後的 this
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>this 指向</title> </head> <body> <script type="text/javascript"> /* 5.應用 call、apply、bind 方法後的 this 瞭解:call、apply、bind 這三個方法是 Function對象纔有的方法;它們的做用,主要是指定函數中 this中的指向,只是用法稍有不一樣; 瀏覽器環境下: 嚴格模式下:this指向 這三個方法所指定的這個值,不管是什麼,即便是 null、undefined, this 也指向它們; 非嚴格模式下:this指向 這三個方法所指定的這個值,null 和 undefined 值會被轉換爲全局對象 window; */ // demo 1: var o1 = { a: 11, b: 12, sayA: function(){ console.log(this.a); } } var o2 = { a: 21, b: 22 } o1.sayA.call(o2); // 21 // demo 2: function sayB(){ console.log(this.b); } sayB.call(o2); // 22 sayB.apply(o2); // 22 var bSayB = sayB.bind(o2); bSayB(); // 22 /* 其實這塊不該該單提出來一個做總結分析的,徹底能夠規劃到「函數上下文的 this」中去,只是在咱們平時 coding的時候, 這三個方法是常常要用到的 因此單拿出來,以做記憶吧; */ </script> </body> </html>
原創:轉載註明出處,謝謝 :)