JavaScript中的this(你不知道的JavaScript)
阿新 • • 發佈:2018-12-31
JavaScript中的this,剛接觸JavaScript時大家都在大肆渲染說其多麼多麼的靈巧重要,然而自己並不關心;隨著自己對JavaScript一步步深入瞭解,突然恍然大悟,原來它真的很重要!所以,自己花費了大約2周的時間去查貼、翻閱之前讀的書籍,將this的全貌展示如下。
一、this是什麼--基於呼叫位置的上下文;呼叫位置不同,this值不同。
大家都JavaScript中this存在兩個誤解:(1)this指向函式自身
(2)this指向函式的作用域
作用域無法通過JavaScript程式碼訪問,它存在於JavaScript引擎內部。每當把this和詞法作用域的查詢混合使用時,一定要提醒自己,這是無法實現的!
this是在執行時進行繫結的,並不是在編寫時繫結,它的上下文取決於函式呼叫時的各種條件。this的繫結和函式宣告的位置沒有任何關係,只取決於函式的呼叫位置(也就是函式的呼叫方式)!
示例:[javascript] view plain copy
- var foo = "golbal foo";
- var myObj = {foo : 'myObj foo'};
- var say = function(){
- console.log(this.foo);
- }
- myObj.say = say;
-
myObj.say(); //結果:myObj foo
- say(); //結果:golbal foo
二、為什麼使用this
[javascript] view plain copy- var me = {
- name: "fenfei"
- };
- //不使用this,呼叫
- function speak(name){
- console.log("Hello, I'm "+ name);
- }
- speak(me.name); //Hello, I'm fenfei
- //使用this,呼叫
- function speak(){
-
console.log("Hello, I'm "
- }
- speak.call(me); //Hello, I'm fenfei
this提供了一種更優雅的方式來隱式“傳遞”物件引用,因此可以將API設計得更加簡潔並易於複用。
三. this的四大繫結規則
1. 預設繫結--函式呼叫型別:獨立函式呼叫,this指向全域性物件。
[javascript] view plain copy- var a = "foo";
- function foo(){
- console.log(this.a);
- }
- foo(); // "foo"
在嚴格模式下,全域性物件將無法使用預設繫結,因此this會繫結到undefined。
[javascript] view plain copy- var a = "foo";
- function foo(){
- "use strict";
- console.log(this.a);
- }
- foo(); // TypeError:this is undefined
2. 隱式繫結--呼叫位置是否有上下文物件,或者說被某個物件擁有或者包含
[javascript] view plain copy- function foo(){
- console.log(this.a);
- }
- var obj1 = {
- a : 2,
- foo : foo
- }
- var obj2 = {
- a : 1,
- obj1 : obj1
- }
- obj2.obj1.foo(); //結果:2
當foo()被呼叫時,它的落腳點指向obj1物件,隱式繫結規則會把函式呼叫中的this繫結到這個上下文物件。
物件屬性引用鏈中只有最頂層或者說最後一次層會影響呼叫位置。
常見的this繫結問題就是“隱式繫結”的函式會丟失繫結物件,也就是“預設繫結”,從而把this繫結到全域性物件(嚴格模式下為undefined)。
[javascript] view plain copy- var a = "foo";
- function foo(){
- console.log(this.a);
- }
- var obj = {
- a : 2,
- foo : foo
- }
- var bar = obj.foo;
- bar(); //"foo"
雖然bar是obj.foo的一個引用,但是實際上,它引用的是foo函式本身,因此此時的bar()其實是不帶任何修飾的函式呼叫,因此應用了預設繫結。
[javascript] view plain copy- var a = "foo";
- function foo(){
- console.log(this.a);
- }
- function doFoo(fn){ //var fn = obj.foo
- fn();
- }
- var obj = {
- a : 2,
- foo : foo
- }
- doFoo(obj.foo); //"foo"
- setTimeout(obj.foo, 100); //"foo"
引數傳遞其實就是一種隱式賦值,因此傳入函式式會被隱式賦值(LHS)
3. 顯示繫結
(1)call、apply(2)硬繫結
[javascript] view plain copy
- function foo(){
- console.log(this.a);
- }
- var obj = { a:2 };
- var bar = function(){