this指向 - 瀏覽器環境

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>
 

 

 
原創:轉載註明出處,謝謝 :)
相關文章
相關標籤/搜索