Simulation implementation of "Note" call, apply, bind, new

Reference link: github.com/mqyqingfeng…

1. call

Pass in any parameters and execute immediately

Call a function or method with a specified this value and a number of specified parameter values:

var foo = { value : 1}
function bar(){
    console.log(this.value)
}
bar.call(foo)// 1
// call 改变了 this 的指向,指向了 foo;
// bar 函数执行了;
复制代码

To achieve the specified this value, the simulation steps are divided into:

  • Set the function as a property of the object;
  • execute the function;
  • delete the function;
Function.prototype.call = function(context){
    // 获取调用 call 的函数,用 this 可以获取
    console.log(this)// bar(){ console.log( this.value ) }
    context.fn = this
    context.fn()
    delete context.fn
}
// 测试一下
var foo = { value : 1 }
function bar(){
    console.log(this.value)
}
bar.call(foo)// 1,相当于foo.bar()
复制代码

Implements several specified parameter values:

  • Get the value from the Arguments object, take the second to last arguments, and put them in an array
Function.prototype.call = function(context){
    context.fn = this
    
    var args = [...arguments].slice(1)
    context.fn(...args)
    
    delete context.fn
}
// 测试一下
var foo = { value : 1 }
function bar(name,age){
    console.log(this.value)
    console.log(name)
    console.log(age)  
}
bar.call(foo,'zouyan','18')
// 1
// zouyan
// 18
复制代码

optimization:

  • This parameter can be passed null, when it is null, it is regarded as pointing to the window;
  • Functions can have return values;
Function.prototype.call = function(context) {
  var context = context || window
  context.fn = this
  var args = [...arguments].slice(1)
  var result = context.fn(...args)
  delete context.fn
  return result
}
// 测试一下
var value = 2
var foo ={ value : 1 }
function bar(name,age){
    console.log(this.value)
    return{
        value: this.value,
        name: name,
        age:age
    }
}
bar.call(null)// 2
bar.call(foo,'zouyan',18)// {value:1,name:'zouyan',age:'18'}
复制代码

2. apply

Pass in the parameter array and execute it immediately

Function.prototype.apply = function(context, arr) {
  var context = Object(context) || window
  context.fn = this

  var result
  if (!arr) {
    result = context.fn()
  } else {
    var args = arr || []
    result = context.fn(...args)
  }
  delete context.fn
  return result
}
// 测试一下
var value = 2
var foo ={ value : 1 }
function bar(name,age){
    console.log('value',this.value)
    return{
        value: this.value,
        name: name,
        age:age
    }
}
bar.apply(null)
bar.apply(foo,['zouyan',18])// {value:1,name:'zouyan',age:'18'}
复制代码

3. bind

Pass in parameters and return functions, which need to be executed manually

  • The bind() method creates a new function;
  • Pass in the first parameter of bind as this when it runs;
  • The other parameters passed in are used as the parameters of the function runtime;
  • Two features: return a function that can pass in parameters;
// 模拟返回函数:
Function.prototype.bind = function(cxt){
    var self = this
    return function(){
        return self.apply(cxt)
    }
}
// 模拟传参
Function.prototype.bind = function(cxt){
    var self = this
    // 获取 bind 函数从第二个参数到最后一个参数
    var args = [].slice.call(arguments, 1)
    return function(){
        // arguments 指 bind 返回的函数传入的参数
        var newArgs = args.concat([].slice.call(arguments))
        return self.apply(cxt, newArgs)
    }
}
复制代码

A bound function can also create objects using the new operator: this acts as if the original function were a constructor. The supplied this value is ignored, and the arguments are supplied to the mock function at the time of invocation.

// 模拟实现构造函数
Function.prototype.bind = function(cxt){
    var self = this
    var args = [].slice.call(arguments, 1)
    var fNOP = function(){}
    var fBound = function(){
        var newArgs = args.concat([].slice.call(arguments))
        return self.apply(this instanceof fNOP ? this : cxt, newArgs)
    }
    fNOP.prototype = this.prototype
    fBound.prototype = new fNOP()
    return fBound
}
// 调用 bind 函数,不是函数则报错
// 兼容
Function.prototype.bind = function(cxt){
    if(typeof this !== "function"){
        throw new Error("is not a function")
    }
    var self = this
    var args = [].slice.call(arguments, 1)// 获取第二个参数到最后一个参数
    var fNOP = function(){}
    var fBound = function(){
        var newArgs = args.concat([].slice.call(arguments)) 
        return self.apply(this instanceof fNOP ? this : cxt, newArgs)
    }
    fNOP.prototype = this.prototype
    fBound.prototype = new fNOP()
    return fBound
}
复制代码

4. new

  • Instances can access properties in the constructor;
  • Instances can access properties in the constructor prototype;

Implementation steps:

  • ① Create a new object obj: because the result of new is a new object;
  • ②The obj._proto_property points to the prototype of the constructor: because the instance needs to access the properties on the prototype;
  • ③ Use apply to add new properties to obj: because obj has properties in the constructor;
  • ④ Judging whether the return value is an object, it is an object that returns an object, otherwise it returns obj: the constructor may have a return value;
// 模拟实现 new 关键字
function objectFactory() {
    // 步骤 ①
    var obj = new Object(),//存疑,为什么模拟new里面使用new?
    //var obj = Object.create(null),//报错:TypeError
    //var obj = {},//正常
    //var obj = Object.create({}),//正常
    //var obj = Object.create(Object.prototype),//正常
    
    // 步骤 ②
    // 获取构造函数,截取第一个参数;
    // shift 会修改原数组,所以 arguments 会被去除的一个参数;
    Constructor = [].shift.call(arguments);// 等同于 Array.prototype.shift.call(arguments)
    obj.__proto__ = Constructor.prototype; 
    
    var ret = Constructor.apply(obj, arguments); // 步骤 ③
    return typeof ret === 'object' ? ret||obj : obj; // 步骤 ④
};
// 构造函数
function Otaku (name, age) {
    this.name = name;
    this.age = age;
    this.habit = 'Games';
}
Otaku.prototype.strength = 60;
Otaku.prototype.sayYourName = function () {
    console.log('I am ' + this.name);
}
// 模拟创建实例
var person = objectFactory(Otaku, 'Kevin', '18')

console.log(person.name) // Kevin
console.log(person.habit) // Games
console.log(person.strength) // 60
person.sayYourName(); // I am Kevin
复制代码

Guess you like

Origin juejin.im/post/7078569691177812005