javascript中this那些事

nyz發表於2018-12-01

定義

this是函式執行的上下文。

呼叫方式

1. 作為函式呼叫,指向window(嚴格模式報undefined的錯)。

var name='hello';
function a() {    
    console.log(this.name)   
}
a();     //hello

var c={    
    name:'haha',    
    d: function(){ 
       a(); 
    } 
}
c.d();    //hello
複製程式碼

2. 作為屬性呼叫,指向該物件。

var name='hello';
function a(){   
    console.log(this.name)
}
var b={    
    name:'world',    
    a:a    
}
b.a();    //world
複製程式碼

有個陷阱,作為函式別名呼叫時,會丟失this。

var name='hello';
function a(){   
    console.log(this.name)
}
var b={    
    name:'world',    
    a:a    
}

var test=b.a;
test();     //hello
複製程式碼

3. 作為建構函式呼叫,會把屬性掛到new出來的例項上。

function A(){    
    this.name='xiaoming'
}
var a=new A();
console.log(a.name);    //xiaoming
複製程式碼

如果建構函式有return,且return物件(包括{}、[]),那麼new的例項就是return的值.

function A(){    
    this.name='xiaoming';
    return {}  
}
var a=new A();
console.log(a.name)    //undefined
複製程式碼

如果return的是字串、“”、null、undefined,new的例項和無return時new的例項一樣。

function A(){    
    this.name='xiaoming';
    return null
}
var a=new A();
console.log(a.name);    //xiaoming
複製程式碼

其實new做了三件事:

  1. 建立一個新物件:var obj={}

  2. 將obj的__proto__指向A.prototype:obj.__proto__=A.prototype;該步驟是為了繼承建構函式A原型鏈。

  3. 將this指向該新物件執行A:A.call(obj)

function Animal(){    
    this.animal="animal";
}
Animal.prototype.name="9"; //Animal建構函式原型的屬性name
function Dog(){    
    this.dog="dog";    
}
Dog.prototype.__proto__=Animal.prototype;

var d=new Dog();
var obj={};
obj.__proto__=Dog.prototype;
Dog.call(obj);
複製程式碼

上面的例子中,物件d和物件obj完全一樣,結果都是下圖的例項,都能訪問Animal建構函式原型的屬性name和方法。

javascript中this那些事

改變this指向的三種方式

1.call

使用:Function.call(obj,arg0,arg1...)

將Function的this指向obj,第一個引數是this指向,後面的引數是傳入Function的引數,一般用於引數個數固定的的函式。對於改變this指向,我個人理解是把函式裡所有用到this的地方替換為obj。

2.apply

使用:Function.apply(obj,[arg0,arg1...])

將Function的this指向obj,第一個引數是this指向,第二個引數是傳入Function的引數組成的陣列,一般用於引數個數不固定的的函式。

3.bind

使用:Funtion(arg0,arg1...).bind(obj)

誤區

誤區1:this指向函式本身?

var name='hello'
function a(){    
    console.log(this.name);    
}
a.name='world';
a() ;    //列印hello
console.log(a.name)     //world
複製程式碼

題外話:

javascript中this那些事
Object和Function既是物件,又是函式,兩者內部同時含有proto和prototype屬性。 Function.prototype指向”內建函式“。而Object.prototype指向”根源物件“

Object.__proto__ === Function.prototype //true
Object.__proto__ === Function.__proto__//true
Object.prototype === Function.prototype.__proto__ // true
//因此
Function instanceof Object //true
Object instanceof Function //true
複製程式碼

函式a的原型:

javascript中this那些事
所有的函式都繼承自Object,函式的原型是Object的例項, 因為Function.__proto__.__proto__===Object.prototype為true,也可以用Function.prototype.isPrototypeOf(Object)為true判斷。
是物件就可以增加屬性,所以a.name掛在了函式上,那他有沒有丟呢?由例子列印的第二個值可以看出來沒丟。

是物件都可以增加屬性,Array.__proto__.__proto__===Object.prototype為ture,Object.prototype.isPrototypeOf(Array.prototype)為true,所以Array和Function一樣,也可以增加屬性。感興趣可自行測試。

javascript中this那些事

誤區2:this是函式區域性作用域?

var name='hello'
function a(){  
    var name='world';  
    console.log(this.name)  
}
a();    //hello
複製程式碼

上例列印hello,不是world,說明this並不是函式的區域性作用域。

誤區3:this指向父級函式作用域?

var name='hello'
function a(){  
    console.log(this.name) 
}
function b(){ 
    var name='world';    
    a();   
}
b();    //hello
複製程式碼

該例子列印的是hello,而不是world,說明this並不是父級函式作用域,而是呼叫上下文。

誤區4:函式的this指向與呼叫該函式的地方this相同?

var name='hello';
function a(){   
    console.log(this.name)
}
var c={    
    name:'haha',    
    d: function(){ 
        console.log(this.name); // haha 
        a(); 
    } 
}
c.d();    // haha  hello
複製程式碼

照理說,如果函式的this指向與呼叫該函式的地方this相同,那麼兩個都列印haha,然而事實卻是,先列印haha,再列印hello,說明跟呼叫函式外部的this無關,可能有人有困惑,為什麼會這樣呢?我也不知道哈哈

相關文章