What are the similarities and differences between the three?

Instructions

Function.call(object, arg1, arg2...)

Function.apply(object, [arg1,arg2,...])

Function.bind(object, arg1, arg2,...)

Same point

You can change the point of this, and the first parameter is the object this will point to.

difference

Call and apply will automatically execute functions when they are used, but bind will not.

Can you manually implement the three methods yourself?

bind method

concept of returns a copy of the original function (also called the binding function), and sets the this keyword to the provided value when calling. And when calling the new function, take the given parameter list as the first several items of the original function's parameter sequence.

function.bind(thisArg[, arg1[, arg2[, ...]]])
  • thisArg : The value passed to the target function this parameter when calling the binding function. If the new operator is used to construct the binding function, this value is ignored. When bind in setTimeout when creating a function (provided as a callback), as thisArg any original value passed will be converted to object . If the parameter list of the bind this execution scope will be regarded as the thisArg new function.
  • arg1, arg2, ... : When the target function is called, the parameters are added to the parameter list of the bound function in advance.

example of

 window.value = 3;
 var foo = {
     value:1
 };
 function bar() {
    console.log(this.value);
 }
 bar();   // 3
 bar.call(foo);    //1 
 
//指定函数this绑定为foo, 产生一个新函数,之后再运行的时候,内部的this就是被绑定的对象
 var bindFoo = bar.bind(foo);
 setTimeout( function() {
     bindFoo();
 },2000)
// 2秒后打印 1

This example can well understand the application of bind

  • bar() directly calls the function, where value refers to all variables value = 3
  • bar.call(foo) here uses call immediately change the bar in this to foo
  • bind often used for asynchronous. In setTimeout bar of this keeps pointing to foo within the set time, so it will print 1 instead of 3 after two seconds.

pre-knowledge:

MDN: The binding function can also be constructed using the new operator, and it will behave as if the target function has been constructed. The provided this value will be ignored, but the preceding parameters will still be provided to the simulation function.

Special note: After the binding function is new , it needs to inherit the prototype chain method of the original function, and the this provided during the binding process is ignored (inheriting the this object of the original function), but the parameter will still use

code implementation

const wang = {
    age: 18,
    love: 'coding',
    hello: function (age, love) {
        if (age) this.age = age;
        if (love) this.love = love;
        console.log("hello world, i am ghostwang," + this.age + "," + this.love);
    }
};
const ye = {
    age: 19,
    love: 'sleeping'
};

// wang.hello.myCall(ye, 0);

Function.prototype.myBind = function () {
    if (typeof this !== 'function') {
        throw new TypeError(this + 'must be a function');
    }
    const target = Array.from(arguments)[0]; // 第一个参数是this
    const args = Array.from(arguments).slice(1);
    const self = this;
    let fBound =  function () {
        const _this = this instanceof self ? this : target; // 检测是否使用new创建
        return self.apply(_this, args);
    }
    /** 假设我们将调用bind的函数称为C,
    将fBound的prototype原型对象指向C的prototype原型对象(上例中就是self),
    这样的话如果将fBound作为构造函数(使用new操作符)实例化一个对象,
    那么这个对象也是C的实例,this instanceof self就会返回true。
    这时就将self指向新创建的对象的this上就可以达到原生bind的效果了(不再固定指定的this)。
    否则,才使用oThis,即绑定指定的this。**/
    if (this.prototype) {
        fBound.prototype = this.prototype
    } 
    return fBound;
}

const foo = wang.hello.myBind(ye);
const foo2 = wang.hello.myBind(ye, 10, 'mom love u');
const nFoo = new foo2(); // hello world, i am ghostwang,10,mom love u
foo(); // hello world, i am ghostwang,19,sleeping

call method

Concept: function.call(thisArg, arg1, arg2, ...) ;

  • thisArg : The value this specified when the fun Note that the specified this value is not necessarily true when the function is executed this value, if the function is in the lower non-strict mode, designated as null and undefined of this value will automatically point to the global object ( this , which is the original value (number, string, Boolean value), will point to the automatic packaging object of the original value.
  • arg1, arg2, ... : The specified parameter list.
var obj = { name:'segmentfault' };
function fn() {
    // console.log(this);
    console.log(this.name);
}
fn();          // undefined
fn.call(obj);  // segmentfault

Understand: First, look for call method, by looking for the prototype chain, in Function.prototype find on call method; then, change fn function of this point, will fn execution.

var obj = { name:'wc' };
function fn(age, country) {
    console.log(this.name + '-' + age + '-' + country);
}
fn.call(obj, 18, 'China'); // wc-19-China

Understanding: With parameters passed in, the parameters need to be expanded. This is the only apply method.

code implementation

Function.prototype.myCall = function () {
    const argumentsArr = Array.from(arguments);
    const target = argumentsArr[0];
    if (!target) { // 判断是node还是浏览器环境
        target = typeof window === undefined ? global : window;
    }
    target.fn = this; // 这里的this指向的是.前面的对象,也就是被调用的函数的原型对象
    // 现在taget的fn属性就是缓存了被调用的函数, 需要改变这个函数的内部this,.前面是谁,this就指向谁,所以现在this是taget
    const res = target.fn(argumentsArr.slice(1));
    delete target.fn;
    return res;
}
const wang = {
    age: 18,
    love: 'coding',
    hello: function () {
        console.log("hello world, i am zhou," + this.age + "," + this.love);
    }
};
const ye = {
    age: 19,
    love: 'sleeping'
};

wang.hello.myCall(ye); // hello world, i am ghostwang,19,sleeping

summary:

  • The first parameter of the call method is used to change the function that calls the call this points to , but if the value of null/undefined this will point to window
  • call method needs to pass the actual parameters in according to the number of formal parameters
  • call last method uses parameters to perform call function in vivo this points to function, generally point to call call function

apply method

Concept: a call having a given this function value, as well as an array (or similar array of objects parameters) supplied.

func.apply(thisArg, [argsArray])
  • thisArg : Optional. The value this used when the function func Please note that this may not be the actual value seen by this method: if this function is in non-strict mode, when it is specified as null or undefined , it will automatically be replaced with a pointer to the global object, and the original value will be wrapped.
  • argsArray : Optional. An array or array-like object in which the array elements will be passed as separate parameters to the func function. If the value of this parameter is null or undefined , it means that no parameters need to be passed in.

code implementation

const wang = {
    age: 18,
    love: 'coding',
    hello: function () {
        console.log("hello world, i am zhou," + this.age + "," + this.love);
    }
};
const ye = {
    age: 19,
    love: 'sleeping'
};

Function.prototype.myApply = function () {
    const argumentsArr = Array.from(arguments);
    const target = argumentsArr[0];
    if (!target) { // 判断是node还是浏览器环境
        target = typeof window === undefined ? global : window;
    }
    target.fn = this; // 这里的this指向的是.前面的对象,也就是被调用的函数的原型对象
    // 现在taget的fn属性就是缓存了被调用的函数, 需要改变这个函数的内部this,.前面是谁,this就指向谁,所以现在this是taget
    const res = target.fn(...argumentsArr.slice(1));
    delete target.fn;
    return res;
}

wang.hello.myApply(ye); // hello world, i am zhou,19,sleeping

MangoGoing
780 声望1.2k 粉丝

开源项目:详见个人详情