淺談Javascript中的this
目錄
一、什麼是this?
this是JavaScript中的一個關鍵字,在函式執行期間自動生成的物件,只可以在函式內部使用,表示函式在執行時候的環境物件。
其值在不同的地方表述的含義也不相同,下面做簡單介紹。
二、this的值
情景一:純函式呼叫
var name = 'lei';
function sayHi(){
var name = 'hahaha'
console.log('hi '+ this.name);
}
sayHi(); // hi lei
window.sayHi();// hi lei
這種情況下相當於全域性呼叫,this指向全域性物件。this.指向呼叫函式的物件。
情景二:作為物件的方法呼叫
var person =
{
name : 'lei',
sayHi :function(){
var name = 'hahaha';
console.log('hi,' + this.name);
}
}
person.sayHi(); //hi,lei
這種情況下this指向此物件。其實等同於上一種情況,這裡的sayHi是函式,其this指向呼叫函式的物件。
情況三 apply 呼叫
沿用上面的程式碼。
sayHi.call(person); sayHi.apply(person);
apply和call方法,可以使this指向傳入的第一個引數。
func.apply(thisArg, [argsArray]) func.call(thisArg, arg1, arg2...)
如果這個函式處於非嚴格模式下,則指定為
null
或undefined
時會自動替換為指向全域性物件,原始值會被包裝。
情景四:建構函式中的this
function Person(name, age){ this.name = name, this.age = age, this.sayInfo =function(){ console.log('my name is ' + this.name+' and I\'m ' + this.age + ' years old!'); } } let me = new Person('lei', 999); me.sayInfo();
這裡設計到原型和原型鏈,我們先對new操作符做的一些事情進行簡單介紹,然後在下一篇文章中給出關於原型及原型鏈的一些分析。
let me = new Person('lei', 999);
上面程式碼使用new操作符生成Person的例項,過程如下:
1)let me =new Object() //建立一個空物件,這裡的new你先不要管他,學習了原型鏈之後就知道怎麼回事了
2)me.__proto__ = Person.prototype //me繼承自Person,把me物件掛在對應的原型鏈上
3)var obj = Person.call(me) //執行建構函式,這裡我們用到了call(),使其this指向me
4)判斷執行完建構函式後的返回值,若顯式返回一個物件型別,則返回返回此物件,即3)中的obj;否則返回1)中建立的物件me;
if(typeof obj == 'object'){ return obj; }else return{ return me; }
情景五、箭頭函式
箭頭函式不會建立this,而是沿作用域鏈從上一級作用域繼承this(父級執行上下文,這個概念以後做具體介紹)。
var name = 'lei'
setTimeout(() =>{
var name = 'hahaha';
console.log(this.name)
},1000) // lei
上面例項中,非同步呼叫匿名函式,輸出this.name。此時this繼承於上一級作用域,也就是全域性作用域,返回name屬性值。
當遇到多層箭頭函式巢狀的時候,只需要沿作用域鏈找出外層呼叫箭頭函式的物件即是this的指向物件。
最後給出一道題
var a=11
function test1(){
this.a=22;
let b=function(){
console.log(this.a);
};
b();
}
var x=new test1();
//熟悉閉包的同學馬上會發現變數b是一個閉包,本質是一個函式
//那麼我們參考情景一的情況,會發現找不到它的呼叫物件,因此在嚴格模式下其呼叫物件為undifined,而在非嚴格模式下,認為其呼叫物件為window,因此結果為 11;
/**********************************/
var a=11;
function test2(){
this.a=22;
let b=()=>{console.log(this.a)}
b();
}
var x=new test2()
//變數b雖然也是一個閉包,但是箭頭函式會繼承來自父級執行上下文的this。
那麼我們就找找父級執行上下文,參考紅寶書中給出的案例,可以知曉其父級上下文為function test1(),那麼this指向於test1,因此結果為22;
詳細的參考文章:
總結:
(1)this存在於函式中,指向呼叫物件的物件。
(2)若指向物件不存在,在非嚴格模式下預設指向全域性物件,這個在閉包中常用。嚴格模式下指向undefined。
(3)箭頭函式中無this,因此不能做建構函式,其this繼承自父級執行上下文中的this。