1. 程式人生 > 實用技巧 >JavaScript this

JavaScript this

this用的很多,react 的class component用了這麼多自己也比較熟悉的了,下面就來講講如何判斷一個this的繫結以及call、apply、bind的實現。

判斷this繫結

主要就是以下的五點:

  1. 由new呼叫:繫結到新建立的物件上面。在類裡面的contructor中,指向將要通過構造器建立的物件。
  2. 由call、apply、bind來呼叫,繫結到指定的物件上面。
  3. 由上下文物件呼叫,就繫結到上下文的物件上面。
  4. 預設:全域性物件,node為global,瀏覽器為window

如何實現call

Function.prototype.call = function(context) {
  var context = Object(context) || window;
  // call是由一個函式呼叫的,此時this就指向該函式
  context.fn = this;
  var args = [];
  for(let i = 1; i < arguments.length; i++) {
    args.push('arguments[' + i + ']');
  }
  var res = eval('context.fn(' + args + ')');	
  delete context.fn;
  return res;
}

var obj = {
  a: 1
}

function print() {
  console.log(this.a)
}
print.call(obj);

如何實現apply

apply與call的最大區別就是,apply僅有第二個引數apply(obj, arguments),且arguments為一個數組,數組裡面存放了要傳遞給呼叫call方法的函式的引數

而call則一個一個的接收引數call(obj, argument1, argument2, argument3, ... argumentn)

Function.prototype.apply = function(context, arr) {
  var context = Object(context) || window;
  context.fn = this;
  var res;
  if(!arr) {
    res = context.fn();
  } else {
    var args = [];
    for(let i = 0; i < arr.length; i++) {
      args.push('arr[' + i + ']');
    }
    res = eval('context.fn(' + args + ')');
  }
  delete context.fn;
  return res;
}

var obj = {
  a: 1
}
function bar(b, c) {
  return {
    a: this.a,
    b: b,
    c: c
  }
}
bar.apply(obj, [2,3])

如何實現bind

Function.prototype.bind = function(context) {
  if(typeof this !== "function") {
    throw new Error("Function.prototype.bind - what is trying to be bound is not callable");
  }
  var self = this;
  var args = Array.prototype.call(arguments, 1);
  var fNOP = function() {};
  var fBound = function() {
    self.apply(this instanceof self ? this : context, args.concat(Array.prototype.slice.call(arguments)));
  }
  fNOP.prototype = this.prototype;
  fbound.prototype = new fNOP();
  return bound;
}