this關鍵詞
概述
this是什麼
this關鍵字是JavaScript中最複雜的機制之一。它是一個很特別的關鍵字,被自動定義在全部函數的做用域中。可是即便在很是有經驗的JavaScript開發者也很難說清它到底指向什麼。
世界上,JavaScript中this 的機制並無那麼先進,可是開發者每每會把理解過程複雜化。絕不誇張地說,不理解它的含義,大部分開發任務都沒法完成。
this都有一個共同點,他老是返回一個對象。簡單說,this就是屬性或方法‘當前’所在的對象。
var = person ={
name :'張三',
describe:function(){
return'姓名'+this.name;}
};
person.descibe();//'姓名:張三'前端
爲何要使用this
this提供了一種更優雅的方式來隱式‘傳遞’一個對象引用,所以能夠將API設計的更加簡介而且易於複用。
隨着你的使用模式愈來愈複雜,顯示傳遞上下文對象會讓代碼變得愈來愈混亂,使用this則不會這樣。
function indetify() {return this.name.toUpperCase();}
function speak(){ console.log('Hello, i'm'+identify.call(this)); }
var me ={name :'Kyle'};
var you ={name:'Reader'};
identify.call(me);//KYLE
identify.call(you);//READER
speak.call(me);//Hello,我是KYLE
speak.call(you);//Hello,我式READER數組
調用位置
想要了解this的綁定過程,首先要理解調用位置:調用位置就是函數在代碼中被調用的位置(而不是聲明的位置)。
一般來講,尋找調用位置就是尋找「函數被調用的位置」。最重要的式要分析調用棧(就是爲了到達當前執行位置調用的全部函數)。
function baz(){
//當前調用棧式:baz。所以,當前調用位置式全局做用域
console.log('baz');
bar();//<--bar的調用位置
}
function bar (){82
//當前調用棧式baz-> bar。所以,當前調用位置在baa中sonsole.log('bar');
}
baz();//<--baz的調用位置app
綁定規則
默認綁定
在一個函數體中使用this,當該函數被獨立調用。能夠把這條規則看做式沒法應用 其餘規則時的默認規則。
function foo(){
console.log(this,a);
}
var a =2
foo();//2
聲明在全局做用域中的變量(好比 var a=2)就是全局對象的一個同名屬性。當調用foo()函數時,
this a 被解析成了全局變量a。
函數調用時應用了this 的默認綁定,所以this指向全局對象。ide
隱式綁定
隱式綁定的規則須要考慮的式調用位置是否有上下文對象,或者說是否被某個對象擁有或者包含。固然,這種說法並不許確。
function foo(){
console.log(this.a);}
var obj = {a:2,
foo:foo};
obj.foo()//2
調用位置會使用ovj上下文來引用函數,所以你能夠說函數被調用時obj對象‘’擁有或者 ‘包含’它。
隱式綁定
隱式丟失式最多見的this 綁定問題,指的就是被隱式綁定的函數會丟失綁定對象,也就是說它會應用默認綁定,從而把this綁定到全局對象。
function foo(){
console.log(this.a);}
var obj ={a:2,
foo:foo};
var bar = obj.foo;函數別名
var a ='Opps,global';//a式全局對象屬性
bar();//'oops,global'
bar式obj.foo的一個引用,可是實際上,他引用的是foo函數自己,所以此時的bar()實際上是一個不帶任何修飾符的函數調用,所以應用了默認綁定。函數
顯示綁定
顯示綁定就是肯定在調用時,this所綁定的對象。JavaScript中提供了apply()方法和call方法實現,
這兩個方法的第一個參數接受一個對象,會把這個對象綁定到this,接着在調用函數是指定這個this。
function foo(){
console.log(this.a);}
var obj ={a:2};
foo.call(obj);//2
若是傳入了一個原始值來看成this 的綁定對象,這個原始值會被轉換成它的對象形式,這一般被稱之爲'裝箱'。oop
new綁定
在JavaScript中,構造函數只是一些使用new操做符時被調用的函數。包括內置對象函數在內的全部函數均可用new函數,會自動執行下面的操做:
1建立(或者說構造)一個全安行的對象。
2這個新對象會綁定到函數調用的this。
3若是函數沒有返回其餘對像,那麼new表達式中的函數調用會自動返回這個新對象。
function foo (a){
this.a = a;}
var bar = new foo(2);
console.log(bar.a);//2this
綁定例外
被忽略的this
若是把null或者undefined做爲this 的綁定對象的傳入call ,apply或者bind,這些值在調用時會被忽略,實際應用的是默認綁定規則。
function foo(){
console.log(this.a);}
var a = 2;
foo.call (null);//2
間接引用
有可能(有意或者無心的)建立一個函數的'間接引用',在着中狀況下,調用這個函數會應用默認綁定規則。
間接引用最容易在賦值時放生:
function foo(){
console.log(this.a);}
var a =2;
var 0 = {a:3,
foo:foo};
var p = {a:4};
o.foo();//3
(p,foo = o.foo)();//2設計
注意事項
避免多層this
多層函數或方法嵌套可能致使不一樣層次的this綁定的對象不一樣,以下示代碼所示:
var 0 = {
f1:function (){
console.log(this);
var f2 = function(){
console.log(this);}
();}}o.f1();
上面代碼包含兩層this,結果運行後,第一層指向對象o,第二層指向全局對象。對象
避免數組方法中的this
數組的map和foreach方法,容許提供一個函數做爲參數。這個函數內部不該該使用this。
var o = {
v:'hello',
p:['a1','a2'],
f:function f(){
this.p.forEach(function(idem){
console.log(this.v+''+item);}) }}
o.f();
上面代碼中,foreach方法的回調函數中的this,實際上是指向全局對象,所以取不到o.v的值。ip
避免回電函數中的this 回調函數中的this 常常會改變綁定的對象,最好的解決方案就是避免這樣使用this。Var 0 ={name :'臥龍學院'}o.fn = function(){console.log (this.name);}var name = '前端開發';function f(v){v();}f(o.fn);上面的代碼中,f()方法的回調函數中this ,實際上是指向全局對象。