this与new、call、apply、bind的关系

什么是this

this的指向在函数定义的时候是确定不来的,只有函数执行的时候,才能确定。
this的最终指向是那个调用它的对象,确切的说,是它的上级父对象,父对象有可能包含在其他对象中。
示例:

    

对于构造函数中的this

在《原型链》中我们提到过new的本质:

  1. 创建一个空对象o
  2. 让 o 的proto属性等于目标对象(即构造函数的prototype)
  3. 执行构造函数,指定执行上下文为o,使o获取到构造函数的属性和方法
  4. 判断执行构造函数的返回,如果是对象则返回该对象,否则返回o
function newObject(func) {
  var o = Object.create(func.prototype);
  var k = func.call(o);
  if (typeof(k) === 'object'&&k !== null) {
    return k;
  } else {
    return o;
  }
}

Object.create()方法创建一个新对象,使用现有的对象来提供新创建的对象的__proto__
这里引出一个知识点:

  1. 在new的语法中,实例对象赋值给谁,this指向的就是谁,确切的说,其实this指向的是示例中的o或k,具体看返回
  2. 当构造函数中this碰到return,跟示例中一样,如果返回类型是个对象(k),那么this就指向这个新对象,否则返回指向函数的实例(o)
    示例:
    

bind的原理

总的来说bind有如下三个功能点:

  • 改变原函数的 this 指向,即绑定上下文,返回原函数的拷贝
  • 当绑定函数被调用时,bind的额外参数将置于实参之前传递给被绑定的方法。
  • 注意,一个绑定函数也能使用new操作符创建对象,这种行为就像把原函数当成构造器,thisArg 参数无效。也就是 new 操作符修改 this 指向的优先级更高。
 // 定义这个方法为myBind
  Function.prototype.myBind = function(thisArg) {
    if (typeof this !== 'function') {
      return;
    }
    var _self = this;
    var args = Array.prototype.slice.call(arguments, 1) //从第二个参数截取

    // 返回一个函数,函数执行才触发apply
    var fnBound = function() {
      // 注意,这里的arguments是return的这个function的入参,与上面的arguments不是同一个
      // 这里是bind的额外入参与return函数的入参合并,作为apply的入参
      return _self.apply(thisArg, args.concat(Array.prototype.slice.call(arguments)));
    }
    
    // 此处是为了解决new 的优先级高导致的异常
    fnBound.prototype = Object.create(this.prototype);

    return fnBound;
  }

测试用例:

function foo(name) {
this.name = name;
}
var obj = {};
var bar = foo.myBind(obj);
bar('Jack');
console.log(obj.name);  // Jack
var alice = new bar('Alice');
console.log(obj.name);  // Jack
console.log(alice.name);    // Alice

call、apply、bind

相同点:

  • 接收多个参数
  • 改变了函数执行时this指向,指向为第一个入参对象

不同点:

  • call、apply会立即执行函数,bind不执行,返回新的函数对象,需调用
  • call、bind支持从第二个参数开始传多个参数,apply只传两个参数,除第一个指定对象外还可以传一个数组形式的参数
    示例:
    

你可能感兴趣的:(this与new、call、apply、bind的关系)