this是什麼?segmentfault
理論上this是執行上下文的一個屬性,this的值在進入到執行上下文的時候就已經肯定了,且不會再改變。這一點很重要。數組
this的做用?app
this 的機制提供了一個優雅的方式,隱式地傳遞一個對象,這可讓函數設計的更加簡潔,而且複用性更好。函數
new綁定,this指向由new建立的對象this
顯示綁定,this指向apply或者call函數的第一個參數設計
隱式綁定,this指向函數的調用者。code
默認綁定,嚴格模式下指向undefinded,非嚴格模式this指向全局對象。對象
箭頭函數綁定,this指向箭頭函數外邊包裹的普通函數作用域
當用new建立一個新的對象的時候,this指向了由new關鍵字聲明建立的對象。get
class Person(name){ constructor(name){ this.name = name; } showThis(){ return this; } } var p1 = new Person('zhang'); var p2 = new Person('zhao'); console.log(p1.showThis() === p1); //true console.log(p2.showThis() === p2); //true console.log(p1.showThis() === Persion) //false
能夠看到,這種狀況下this的值指向了由new建立的對象的引用。this會被綁定到這個對象上去。
所謂的顯式綁定,指的是經過apply或者call方法的第一個參數。
call和apply的不一樣,兩個方法的第一個參數都是this賦給的對象。不一樣在於,以後的參數被看成call方法的形參依次傳進去,而apply則是接受一個數組。
看代碼:
function foo(){ console.log(this === obj); //true console.log(this.a === 2); //true } var obj = { a:2 } foo.call(obj);
隱式綁定用的次數比較多。一個最重要的特色就是,this的指定順序和在哪裏定義沒有關係,而是取決於調用者。
嚴格意義來講,this是上下文裏的一個屬性(存放各類變量的變量對象一樣也是上下文裏的屬性),this的值老是指向當前上下文的父級上下文,其實也就是當前上下文的調用者。
看代碼:
//第一個簡單的例子 var obj = { a : 1, foo : function(){ console.log(this === obj); //trun console.log(this.a === 1); //true }, bar : bar } //假如把一個屬性定義在對象外邊 function bar(){ console.log(this === obj); //true } obj.foo(); obj.bar(); //都是true
再來一個例子
function bar(){ console.log(this === obj1); console.log(this === obj2); } function foo(){ console.log(this === obj1); console.log(this === obj2); } var obj1 = { bar: bar, foo: foo } var obj2 = { bar: obj1.bar, foo: obj1.foo, } obj1.foo(); //true false obj2.foo(); //false true obj1.bar(); //true false obj2.foo(); //false true
很簡單,foo和bar兩個方法分別由obj1和obj2調用,哪怕obj2中的foo和bar是obj1的也不要緊,與在哪裏定義沒有關係,純粹看是看誰調用的,obj2.foo()就是obj2調用的foo方法,因此,這個時候this指向obj2。
多說一句,若是既有顯示綁定又有隱式綁定,固然是以顯示綁定爲準。
這種狀況下,this不屬於任何一個函數方法內,即在全局做用域下,這種狀況下稱爲默認綁定。
非嚴格模式下,這個時候this值爲window全局對象。
function foo(){ console.log(this === window); } foo();
嚴格模式下,this的值是undefined
"use strict"; function foo() { console.log( this === undefined ); } foo(); // true foo.call(undefined); // true foo.call(null); // false
箭頭函數實際上是一個語法躺,箭頭函數的裏的this指向包裹箭頭函數的那個函數的this值。很好理解。
// ES6 function foo() { setTimeout(() => { console.log(this === obj); // true }, 100); } const obj = { a : 1 } foo.call(obj); // ES5 function foo() { var _this = this; setTimeout(function () { console.log(_this === obj); // true }, 100); } var obj = { a : 1 } foo.call(obj);
用僞代碼的形式來表示
if (`newObj = new Object()`) { this = newObj } else if (`bind/call/apply(thisArgument,...)`) { if (`use strict`) { this = thisArgument } else { if (thisArgument == null || thisArgument == undefined) { this = window || global } else { this = ToObject(thisArgument) } } } else if (`Function Call`) { if (`obj.foo()`) { // base value . Reference = base value + reference name + strict reference // 例外: super.render(obj). this = childObj ? this = obj } else if (`foo()`) { // 例外: with statement. this = with object this = `use strict` ? undefined : window || global } }