this

JavaScript 中的 this 含義非常多,它可以是全局對象、當(dāng)前對象或者任意對象,這完全取決于函數(shù)的調(diào)用方式

隨著函數(shù)使用場合的不同,this的值會發(fā)生變化。但是有一個總的原則,那就是this指的是,調(diào)用函數(shù)的那個對象

1 作為函數(shù)調(diào)用

  • 在函數(shù)被直接調(diào)用時this綁定到全局對象。在瀏覽器中,window 就是該全局對象
console.log(this);

function fn1(){
    console.log(this);
}

fn1();

2 內(nèi)部函數(shù)

  • 函數(shù)嵌套產(chǎn)生的內(nèi)部函數(shù)的this不是其父函數(shù),仍然是全局變量
function fn0(){
    function fn(){
        console.log(this);
    }
    fn();
}

fn0();

3 setTimeout、setInterval

  • 這兩個方法執(zhí)行的函數(shù)this也是全局對象,也就是創(chuàng)建一個定時器而這個定時器屬于window對象
document.addEventListener('click', function(e){
    console.log(this);
    setTimeout(function(){
        console.log(this);
    }, 200);
}, false);

4 在構(gòu)造函數(shù)中調(diào)用
構(gòu)造函數(shù)能夠用來生成一個新的對象(object),這是函數(shù)中的this就指向新的對象(object)
在創(chuàng)建對象時new操作符具有以下作用

  • 創(chuàng)建一個新對象實例,將實例中的—prototype—屬性指向構(gòu)造函數(shù)的prototype
  • 初始化實例,調(diào)用構(gòu)造函數(shù)并傳入?yún)?shù),將this指向該實例
  • 返回實例
function Person(name){
    this.name = name;
}
Person.prototype.printName = function(){
    console.log(this.name);
};

var p1 = new Person('Byron');
var p2 = new Person('Casper');
var p3 = new Person('Vincent');

p1.printName();//Byron
p2.printName();//Casper
p3.printName();//Vincent

5 在 JavaScript 中,函數(shù)也是對象,因此函數(shù)可以作為一個對象的屬性,此時該函數(shù)被稱為該對象的方法,在使用這種調(diào)用方式時,this 被自然綁定到該對象

var obj1 = {
    name: 'Byron',
    fn : function(){
        console.log(this);
    }
};

obj1.fn();//obj1
var a =obj1.fn
a()//window

6 DOM對象綁定事件

  • 在事件處理程序中this代表事件源DOM對象(低版本IE有bug,指向了window)
document.addEventListener('click', function(e){
    console.log(this);//document
    var _document = this;
    setTimeout(function(){
        console.log(this);//window
        console.log(_document);//document
    }, 200);
}, false);

7 Function.prototype.bind

  • bind,返回一個新函數(shù),并且使函數(shù)內(nèi)部的this為傳入的第一個參數(shù)
var obj1 = {
    fn: function() {
        console.log(this)
    }
}
var fn3 = obj1.fn.bind(obj1);
fn3();//obj1

8 使用call和apply設(shè)置this

  • call apply,調(diào)用一個函數(shù),傳入函數(shù)執(zhí)行上下文及參數(shù)
    fn.call(context, param1, param2...)
    fn.apply(context, paramArray)
    第一個參數(shù)都是希望設(shè)置的this對象,不同之處在于call方法接收參數(shù)列表,而apply接收參數(shù)數(shù)組
    fn2.call(obj1);
    fn2.apply(obj1);

函數(shù)的執(zhí)行環(huán)境

  • JavaScript中的函數(shù)既可以被當(dāng)作普通函數(shù)執(zhí)行,也可以作為對象的方法執(zhí)行,這是導(dǎo)致 this 含義如此豐富的主要原因

  • 一個函數(shù)被執(zhí)行時,會創(chuàng)建一個執(zhí)行環(huán)境(ExecutionContext),函數(shù)的所有的行為均發(fā)生在此執(zhí)行環(huán)境中,構(gòu)建該執(zhí)行環(huán)境時,JavaScript 首先會創(chuàng)建 arguments變量,其中包含調(diào)用函數(shù)時傳入的參數(shù)

  • 接下來創(chuàng)建作用域鏈,然后初始化變量。首先初始化函數(shù)的形參表,值為 arguments變量中對應(yīng)的值,如果 arguments變量中沒有對應(yīng)值,則該形參初始化為 undefined。

  • 如果該函數(shù)中含有內(nèi)部函數(shù),則初始化這些內(nèi)部函數(shù)。如果沒有,繼續(xù)初始化該函數(shù)內(nèi)定義的局部變量,需要注意的是此時這些變量初始化為 undefined,其賦值操作在執(zhí)行環(huán)境(ExecutionContext)創(chuàng)建成功后,函數(shù)執(zhí)行時才會執(zhí)行,這點對于我們理解JavaScript中的變量作用域非常重要,最后為this變量賦值,會根據(jù)函數(shù)調(diào)用方式的不同,賦給this全局對象,當(dāng)前對象等

  • 至此函數(shù)的執(zhí)行環(huán)境(ExecutionContext)創(chuàng)建成功,函數(shù)開始逐行執(zhí)行,所需變量均從之前構(gòu)建好的執(zhí)行環(huán)境(ExecutionContext)中讀取

三種變量

  • 實例變量:(this)類的實例才能訪問到的變量

  • 靜態(tài)變量:(屬性)直接類型對象能訪問到的變量

  • 私有變量:(局部變量)當(dāng)前作用域內(nèi)有效的變量

例子

function ClassA(){
    var a = 1; //私有變量,只有函數(shù)內(nèi)部可以訪問
    this.b = 2; //實例變量,只有實例可以訪問
}

ClassA.c = 3; // 靜態(tài)變量,也就是屬性,類型訪問(函數(shù)也是對象)

console.log(a); // error
console.log(ClassA.b) // undefined(在實例創(chuàng)建之后才能訪問到)
console.log(ClassA.c) //3

var classa = new ClassA();
console.log(classa.a);//undefined(a作為實例的屬性沒有被定義,與函數(shù)內(nèi)部定義的變量a沒有任何關(guān)系)
console.log(classa.b);// 2
console.log(classa.c);//undefined c是ClassA構(gòu)造函數(shù)(對象)的屬性創(chuàng)建實例時 new操作符只執(zhí)行構(gòu)造函數(shù)內(nèi)部的代碼,不會繼承構(gòu)造函數(shù)的其他屬性
?著作權(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)容