javascript之深入剖析this
this的重要性不言而喻,比如面試題經常考到,其次,如果徹底理解了this,那麼對理解框架源碼及編寫高質量代碼都有很大的幫助。本文就是要深入剖析this的幾種情況,理解了原理,以後媽媽再也不用擔心你的this了。。
this是動態綁定的,其實相對應的是作用域,因為作用域是在代碼剛剛寫完的時候,就已經定義好了。理解了作用域,對理解閉包很有幫助。本文主要講解this綁定,大家心裡先有和作用域的一個大致對比就行,以後的文章會專門講解。
所謂動態綁定,就是只有在函數被調用的時候,this才能確定它真正指向的是哪個對象。
this分為以下四種情況,這四種掌握了,就打遍天下無敵手了~
我們先定義一個函數:
function foo(name){
this.name=name;
console.log(this.name);
}
一、new綁定
var obj=new foo("yx");
控制台輸出結果:"yx"
繼續在控制台輸入: obj.name ,結果依然是"yx"
對於上面的 foo 函數,
如果改成
function foo(name){
var o={name:"peggy"};
this.name=name;
console.log(this.name);
return o;
}
var obj=new foo;
控制台輸出結果依然是"yx"
繼續在控制台輸入 obj.name ,發現結果竟然變成了"peggy"!
其實我覺得原因大家已經猜出來了:
如果 foo 函數返回了一個對象,那麼 obj 等於返回的那個對象o,如果沒返回對象的話,則默認是 return this ;
可能有些小夥伴會認為 foo 應該大寫,而且 foo 是構造函數,其實壓根沒有什麼構造函數,函數名大寫也只是一種約定而已,其實真實的情況是使用 new 關鍵字構造調用了 foo 函數!那麼此時的 this 在 foo 函數被調用的過程中,綁定到了一個新創建的對象上,如果沒有指定對象返回的話,那麼返回的就是這個新創建的對象。這個新創建的對象的內部 [[proto]] 屬性會指向 foo.prototype ,這就涉及到原型與繼承問題了,以後再討論。
所以結果為什麼這樣就很清晰了:兩次調用 console.log(this.name) 會返回 "yx" 是因為 this 就是新創建的這個對象。而最後 obj.name 不一樣,是因為函數返回的對象不一樣了,所以此時 obj 代表的對象也就不一樣了。
二、顯式綁定
所謂的顯示綁定有三種: call , apply , bind
我們定義函數:
function person(age, hobby){
this.age=age;
this.hobby=hobby;
console.log(this.name);
console.log(this.age);
console.log(this.hobby);
}
因為函數也是對象,所以也是有方法的,每個函數其實可以理解為是由 Function 函數通過new構造調用的,即 new Function
所以每一個函數內部 [[proto]] 屬性都指向 Function.prototype ,所以可以繼承 Function.prototype 中的方法,比如; call , apply , bind
call 方法和 apply 方法的共同點是:第一個參數代表 this 指向的對象
不同點是: call 方法從第二個參數開始,傳遞的都是 person 函數需要的對應的參數,挨個挨個的傳遞
apply 方法的第二個參數,傳遞的是一個數組,數組中的每一項與 person 函數需要的參數對應
(1)call var obj={name:"yx"};
person.call(obj,24,"singing");
此時 this 指向 obj ,所以控制台輸出結果是"yx",24,"singing"
(2)apply var obj1={name:"peggy"};
person.apply(obj1,[24,"running"]);
此時, this 指向 obj1 ,控制台輸出結果是"yx",24,"running"
使用 apply 還可以用來展開數組,第二個參數傳遞 arguments 數組( arguments 數組代表函數實際傳遞的參數)
比如:繼承會用到
var obj2={name:"xixi"};
function student(age,hobby){
person.apply(this,arguments);
}
student.call(obj2,24,"singing");
此時 student 函數中的 this 指向傳入的 obj , arguments 是一個類數組,代表傳遞的實參,
所以如果想實現繼承 person 函數的屬性或者方法,可以用 apply 展開 arguments
(3) bind var obj3={name:"nancy"};
var obj4={name:"mingming"};
var newFn=person.bind(obj3);
調用 bind 函數會返回一個新函數,新函數的 this 會綁定在 obj3 上,無論以後是怎麼調用 newFn , this 都會一直綁定在 obj3
比如在控制台輸入: newFn.call(obj4,24,"singing") 或者輸入 newFn(24,"singing") 都不能改變this的綁定
發現結果依然是輸出:"nancy",而不是"mingming"
bind 還可以用來進行科里化,就是可以先傳參數進去,比如:
var newFn1 = person.bind(obj3,24);
newFn1("singing");
newFn1("running");
相當於先傳了一個參數,之後調用的時候再傳另外的參數就好。
不是所有的函數都有 protoype ,用 bind 創建的函數就沒有 prototype 。比如:
function fn{return this.x}; var boundFn=fn.bind({x:1})
那麼 boundFn 就是沒有 prototype 屬性的。
三、隱式綁定 function foo{
console.log(this.name)
}
var obj={
name:"yx",
fn:foo
}
obj.fn;
控制台結果:"yx"
此時 this 指向 obj , obj 為此時的上下文環境
四、默認綁定: var name="yx";
function foo{
var name="peggy";
console.log(this.name);
}
foo;
控制台結果:"yx"
此時: this 指向 global 對象
(1)瀏覽器環境中: this=window
(2)node開發環境中: this=global
其實上面四種情況的順序,我是刻意這樣安排的,因為從上到下優先順序依次降低。
根據這幾種不同的調用方式, this 指向的對象是不同的。
依次判斷 new綁定-> 顯式綁定-> 隱式綁定->默認綁定
大家可以親自去驗證下,是不是這個順序。
牛刀小試:(1)
function a(xx){this.x=xx;return this};
var x=a(5);var y=a(6);
console.log(x.x);
console.log(y.x);
(2)
var obj = {
x: 1,
y: 2,
t: function {
console.log(this.x)
}
}
obj.t;
var dog={x:11};
dog.t=obj.t;
dog.t;
show=function{
console.log("show"+this.x);
}
dog.t=show;
dog.t;
(3)
var number=2;
var obj={
number:4,
fn1:(function{
var number;
this.number*=2;//4
number=number*2;//NaN
number=3;
return function{
var num=this.number;
this.number*=2;//6
console.log(num);
number*=3;//9
alert(number);
}
}),
db2:function{
this.number*=2;
}
}
var fn1=obj.fn1;
alert(number);
fn1;
obj.fn1;
alert(window.number);
alert(obj.number);
※js實用方法記錄-簡單cookie操作
※CentOS 7 安裝Graphite
※selenium+python環境的搭建的自動化測試
※C超簡單方法實現兩個richtextbox控制項滾動條同步滾動
※初次嘗試Linux並記錄一二
TAG:達人科技 |
※深入 git rebase
※深入 JVM 分析 spring-boot 應用 hibernate-validatorNoClassDefFoundError
※深入 SpringBoot : 怎樣排查 expectedsinglematchingbeanbutfound 2 的異常
※Node.js進階:cluster模塊深入剖析
※Greenlight深入分析Oculus Go的消費者認知
※深入 Spring Boot :實現對 Fat Jar jsp 的支持
※深入淺析一致性模型之Linearizability
※MapReduce Shuffle深入理解
※convergencias展覽 深入探索古巴設計
※async/await使用深入詳解
※深入解讀Google Lens
※Glibc堆漏洞利用基礎-深入理解ptmalloc2 part1
※深入近賞劃時代手機 Samsung Galaxy Fold
※深入對比數據科學工具箱:SparkR vs Sparklyr
※深入GlobalFoundries的晶元前沿領域探索之路
※protobuf深入講解
※android 結合源碼深入剖析AsyncTask機制原理
※三星GalaxyBuds深入體驗報告附對比榮耀flypods
※深入骨髓的精緻,就是大家都在追的「effortless chic」!
※深入談談String.intern在JVM的實現