關於this

用call來解釋this很形象,可是不是那麼嚴謹,詳情看補充1;javascript

瞭解this的本質

比較嚴謹的解釋:一個函數能夠在多個環境中執行,函數執行時容許訪問環境中的其餘變量,this會指向調用函數的那個環境;html

比較易懂的解釋:java

  • 函數調用時都指定了它的外部環境,這裏用call來展現外部環境:
  • fn(x);,能夠理解爲fn.call(undefined,x);這裏fn中的this就是undefined;
  • obj.fn(); 能夠理解爲obj.fn.call(obj,x);這裏fn中的this就是obj;

call函數的第一個參數就是指定的外部環境,就是this
想要知道一個函數中的this是誰,大部分狀況下能夠去函數調用棧中找上一個函數看到。node

this的綁定規則

1.默認綁定瀏覽器

  • 像fn();
  • 嚴格模式下等價於fn.call(undefined);
  • 非嚴格模式下等價於fn.call(全局對象);這個全局對象在瀏覽器中是window,node中是global;

2.隱氏綁定app

  • 像obj.fn();等價於fn.call(obj),obj做爲一個上下文對象隱性傳遞到了fn中;
  • 這個傳遞是隱性的,咱們觀察不到的。

3.顯示綁定函數

  • 像fn.call(context); fn在執行時,this就是context;
  • 這個綁定很明顯,是咱們能夠觀察、而且控制的。
  • 顯示綁定很經常使用,這裏貼一個bind方法的極簡實現
function bind(fn, obj) {
    return function() {
        return fn.apply( obj, arguments );
    }; 
}

4.new綁定this

  • js中的new操做符和其餘語言的new機制徹底不同。
  • new執行的操做用僞代碼表達一下:
// 執行new Foo()時發生的操做
var obj = {};                        // 建立空對象
obj.__proto__ = Foo.prototype;        // 鏈接到foo的原型,繼承機制
Foo.call(obj);                        // 綁定成上下文,並執行foo
return obj;                            // foo中若是沒有return的話,return obj這個對象回去

補充1:this被忽略的狀況,用call作例子不嚴謹的緣由

  • 當把null或undefined做爲this傳入call、apply、bind時,實際應用的是默認綁定規則;
// 非嚴格模式
function foo() { 
    console.log( this.a );
}
var a = 2;
foo.call( null ); // 2

補充2:一個結合this、聲明提高、全局局部變量的例子:

var a=10;    
function test(){        
    a=5;        
    alert(a);        
    alert(this.a);        
    var a;       
    alert(this.a);        
    alert(a);    
}
執行test()和new test() 結果是什麼

答案:
alert的內容:test(): 5,10,10,5
new test():5,undefined,undefined,5

補充3:this丟失(優先級)

// 用一個簡單的例子開個頭
// obj.fn是一種隱性綁定,將fn中的this指向obj
// 可是this又被context覆蓋了,這種this丟失能夠引伸出優先級的問題。
obj.fn.call(context)

補充4:箭頭函數

箭頭函數的this繼承上層函數prototype

var obj = {
      say: function () {
        setTimeout(() => {
            console.log(this)    //obj
        }, 0)
      }
    }

補充5

當即執行函數執行時,obj仍是undefinedcode

var obj = {
    say: function () {
      function _say() {
        console.log(this)    //window or global
      }
      return _say.bind(obj)
    }()
}
obj.say()

補充6

var length = 10;
function fn() {
    console.log(this.length);
}

var obj = {
  length: 5,
  method: function(fn) {
    fn();
    arguments[0]();    // arguments.0()
  }
};

obj.method(fn, 1);
// 10 2

補充7

var a=10;
var foo={
  a:20,
  bar:function(){
      var a=30;
      return this.a;
    }
}
foo.bar()
(foo.bar)()
(foo.bar=foo.bar)()
(foo.bar,foo.bar)()
// 20 20 10 10

補充8

var num = 1;
function codequn(){
    'use strict';
    console.log('codequn: ',this.num++);
}
function codequn2(){
    console.log('codequn2: ',++this.num);
}
(function(){
    'use strict';
    codequn2();
})();
codequn();
// codequn2: 2   
// Cannot read property 'num' of undefined

補充9

箭頭函數中的this是定義時所在對象的this,而不是執行時

const debounce = function(fn, time) {
  let timeout = null
  return function() {
    const _self = this
    clearTimeout(timeout)
    timeout = setTimeout(()=>{
      console.log(this === _self)    //true
      fn.call(this, ...arguments)
    }, time)
  }
}
參考:
《你不知道的javascript上卷》;
https://www.zhihu.com/questio...
http://www.ruanyifeng.com/blo...
https://developer.mozilla.org...
相關文章
相關標籤/搜索