call,apply,bind,new方法的实现原理

337 阅读2分钟

1.call方法的使用原理

  • 1.function.call(obj, arg1, arg2, ...)这个函数调用的时候this的指向改变了(this绑定为传入的第一个参数)
  • 2.从call函数传入的第二个参数开始,作为function的参数传入
  • 3.不更改obj的任何属性和方法。
Function.prototype._call = function (obj, ...args) {
  let attribute = "attr" + Math.random();
  // 防止对象obj已经含有属性attribute
  while (obj[attribute]) {
    attribute = "attr" + Math.random();
  }
  obj[attribute] = this;
  let res = obj[attribute](...args);
  delete obj[attribute];
  return res;
};
let obj = { name: "coderwhh" };
function func() {
  console.log(this.name);
}
// coderwhh
func._call(obj);
// coderwhh
func.call(obj);

2.apply方法的使用原理

  • 使用原理与call方法的使用原理一致,唯一不同之处在于传递的第二个参数为数组格式
Function.prototype._call = function (obj, ...args) {
  let attribute = "attr" + Math.random();
  // 防止对象obj已经含有属性attribute
  while (obj[attribute]) {
    attribute = "attr" + Math.random();
  }
  obj[attribute] = this;
  // 不同之处
  let res = obj[attribute](args);
  delete obj[attribute];
  return res;
};
let obj = { name: "coderwhh" };
function func() {
  console.log(this.name);
}
func._apply(obj);
func.apply(obj);

3.bind方法的使用原理

bind一共做了四件事情

    1. bind改变了func中的函数的指向
    1. 可以在调用func的时候就可以第一次传入参数
    1. bind返回一个函数,可以在调用的时候再次传入参数
    1. bind函数会创建一个新绑定的函数(fBound),绑定函数可以使用new运算符来构造,提供的this值会被忽略。
Function.prototype._bind = function () {
  arguments = Array.of(arguments)
  let thatFunc = this
  let thatArgs = arguments[0]
  let args = arguments.slice(1)
  if(typeof thatFunc !== 'function') {
    throw new Error('Function.prototype.bind - what is trying to be bound is not callable')
  }
  let fBound = function () {
    return thatFunc.apply(this instanceof fBound ? this : thatArgs, args.concat(Array.of(arguments)))
  }
  fBound.prototype = thatFunc.prototype
  return fBound
};
let obj = {name: 'coderwhh'}
function func() {
  console.log(this, arguments);
}
func.bind(obj, 'age: 12')('height: 198')

4.new方法的实现原理

    1. 创建一个对象
    1. 将obj的__proto__指向fn的prototype实现继承(使用指定的原型对象及其属性去创建一个新的对象)
    1. 改变this的指向,执行构造函数为func传递参数
    1. 返回新的对象obj
function _new(func, ...args) {
  let obj = Object.create(func.prototype);
  let result = func.apply(obj, args);
  return result instanceof func ? result : obj;
}

function _new2() {
  // 创建一个对象
  let obj = {};
  // 获得构造参数
  let Con = [].shift.call(arguments);
  // 链接到原型(给obj这个新生对象的原型指向它的构造函数的原型)
  obj.__proto__ = Con.prototype;
  // 绑定this
  let result = Con.apply(obj, arguments);
  // 确保new出来的是一个对象
  return result instanceof Con ? result : obj;
}

function func(age) {
  this.name = "coderwhh";
  this.age = age;
}

let obj = new func(12);
let obj1 = _new(func, 12);
let obj2 = _new2(func, 12);
// func { name: 'coderwhh', age: 12 }
console.log(obj, obj1, obj2);