03-this對象

this對象

this總是返回一個對象,也就是返回屬性或者方法當(dāng)前所在的對象。
可以近似地認(rèn)為,this是所有函數(shù)在運行時的一個隱藏參數(shù),指向該函數(shù)在運行時的環(huán)境對象。
如果一個函數(shù)在調(diào)用時,被某一個對象所擁有,那么該函數(shù)在調(diào)用時,內(nèi)部的this指向該對象。
如果函數(shù)獨立調(diào)用,那么該函數(shù)內(nèi)部的this,則指向undefined。
在非嚴(yán)格模式中,當(dāng)this指向undefined時,它會被自動指向全局對象window。
即函數(shù)在調(diào)用時,this總指向它的擁有者(調(diào)用者),若自己獨立調(diào)用,就指向undefined,非嚴(yán)格模式中獨立調(diào)用指向window。

    // 使用嚴(yán)格模式
    function foo() {
        'use strict';
        console.log(this);
    }
    foo();  // foo()獨立調(diào)用 this指向undefined
    window.foo(); // foo()被window調(diào)用,this指向window

this指向在運行時確定,一旦確定,不可更改。

    var name = 'Tom';
    var obj = {
        name: 'Leo'
    };
    function sayName() {
        this = obj; // 試圖在函數(shù)運行時修改this
        console.log(this.name);
    }
    sayName();//報錯,函數(shù)在運調(diào)用時已確定this指向,無法更改

賦值操作會改變this指向。

    var name = 'Tom'
    function sayName() {
        console.log(this.name);
    }
    var obj = {
        name: 'Leo',
        say: sayName  // 將sayName函數(shù)的引用賦值給say
    }
    obj.say(); //Leo
    var foo = obj.say;  // 將sayName函數(shù)的的引用賦值給全局變量foo
    foo();
    // obj.say()在obj中被調(diào)用,this指向obj
    // foo()獨立調(diào)用,非嚴(yán)格模式中,this指向window
    // 也可以理解為foo()在window中被調(diào)用,因為在全局環(huán)境中foo()==window.foo()

    var name = 'Tom';
    var obj = {
        name: 'Leo',
        foo: {
            name: 'Bob',
            sayName: function () {
                console.log(this.name);
            }
        }
    }
    obj.foo.sayName(); // Bob
    var say = obj.foo.sayName; //將sayName函數(shù)的引用地址賦值給say
    say(); // Tom 函數(shù)sayName獨立執(zhí)行,this指向window
    var box = obj.foo; // 將對象foo的引用地址賦值給box
    box.sayName(); // Bob  函數(shù)sayName在foo對象中執(zhí)行,this指向foo

this指向函數(shù)運行時的環(huán)境對象,與函數(shù)定義時的位置無關(guān)。

    var name = 'Tom';
    var obj = {
        name: 'Leo',
        sayName: function () {  // sayName函數(shù)在obj中定義
            console.log(this.name);
        }
    };
    obj.sayName(); // Leo,在obj中調(diào)用sayName,指向obj
    var foo = obj.sayName;  // 將sayName引用地址賦值給foo
    foo(); // Tom  獨立調(diào)用sayName,this指向window
    var box = {
        name: 'Bob',
        say:foo // 將sayName引用地址賦值給say
    };
    box.say(); // Bob 在box中調(diào)用sayName,this指向box

分析一些例子

    // demo01
    function sayName() {
        // 'use strict';
        console.log(this.name)
    }
    function func(fn) {
        fn(); // 函數(shù)被傳進來后獨立調(diào)用
    }
    var name = 'Tom';
    var obj = {
        name: 'Leo',
        say: sayName // 函數(shù)sayName引用地址賦值給say
    };
    func(obj.say);  // Tom
    // 將sayName函數(shù)傳入func函數(shù),并調(diào)用sayName
    // 函數(shù)sayName獨立調(diào)用,非嚴(yán)格模式時函數(shù)中的this為window
    // 使用嚴(yán)格模式時,this為undefined,執(zhí)行this.name會報錯

    // demo02
    var name = 'Tom';
    var obj = {
        name: 'Leo',
        func: function () {
            (function () {
                //'use strict'
                console.log(this.name);
            })();
        }
    }
    obj.func();//Tom
    // obj.func()調(diào)用時,內(nèi)部自執(zhí)行函數(shù)自動執(zhí)行,沒有調(diào)用者,this指向window
    // 使用嚴(yán)格模式時,this為undefined,執(zhí)行this.name會報錯

JavaScript提供了三種綁定this的方法:call、apply和bind。
call方法,第一個參數(shù)是this的指向(即函數(shù)執(zhí)行時所在的作用域),然后在所指定的作用域中,調(diào)用該方法。
call方法的第一個參數(shù)應(yīng)該是一個對象,如果參數(shù)為空、null、和undefined,則默認(rèn)傳入全局對象。
如果傳入的第一參數(shù)是原始值,那么會自動轉(zhuǎn)換成對應(yīng)的包裝類型,然后再傳入call方法。
call第二個及以后的參數(shù)是函數(shù)調(diào)用時所需的參數(shù)。
apply方法和call方法類似,第一個參數(shù)也是this的指向。唯一區(qū)別是它接受一個數(shù)組作為函數(shù)執(zhí)行時的參數(shù)。
apply/call方法不僅綁定函數(shù)執(zhí)行時所在的對象,還會立即執(zhí)行函數(shù),因此要把綁定的語句寫在函數(shù)體內(nèi)。
bind方法將函數(shù)體內(nèi)的this綁定到某個對象,然后每次返回一個新函數(shù)。
bind方法比apply/call方法更進一步,除了綁定this,還可以綁定原函數(shù)的參數(shù)。

    function fn(n, m) {
        console.log(this.a + n + m);
    }
    var obj = {
        a: 20
    }
    fn.call(obj, 100, 10); // 130
    fn.apply(obj, [20, 10]); // 50

    var arr = [8,3,4,1,5,9];
    console.log(Math.max.apply(null, arr)); // 9

    // 使用call/apply將arguments轉(zhuǎn)換為數(shù)組, 返回結(jié)果為數(shù)組,arguments自身不會改變
    var arg = [].slice.call(arguments);
    //將DOM中的nodelist轉(zhuǎn)換為數(shù)組
    [].slice.call( document.getElementsByTagName('li') );

    // 實現(xiàn)繼承
    var Person = function (name) {
        this.name = name;
    }
    var Student = function (age) {
        this.age = age;
        Person.call(this, name);
    }
    Student.prototype.message = function () {
        console.log('name:'+ this.name+', age:'+this.age);
    }
    new Student('Leo', '26').message();

靈活使用this。

    var name = 'Tom';
    var obj = {
        name: 'Leo',
        sayName: function() {
            setTimeout(function() {
                console.log(this.name)
            }, 500)
        }
    }
    obj.sayName(); // Tom*/
    // 定時器中回調(diào)函數(shù)獨立調(diào)用,this指向window
    // 要獲取obj中的name
    // 方法1,使用一個變量,保存this
    var obj = {
        name: 'Leo',
        sayName: function() {
            var _this = this;
            setTimeout(function() {
                console.log(_this.name)
            }, 500)
        }
    }
    obj.sayName() // Leo
    // 方法2 使用bind (注意:若使用call/apply會立即執(zhí)行回調(diào)函數(shù))
    var obj = {
        name: 'Leo',
        sayName: function() {
            setTimeout(function() {
                console.log(this.name)
            }.bind(this), 500)
        }
    }
    obj.sayName() // Leo

參考資料:
《JavaScript高級程序設(shè)計》
《JavaScript 標(biāo)準(zhǔn)參考教程》
湯姆大叔-深入理解JavaScript系列

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容