1. 程式人生 > >淺談Javascript中的this

淺談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。