js the call, apply, bind in the end what is the difference? The method can also bind returned this point to modify it?

 One ❀ lead

Colleagues looking at recent angularjs source code, the source code is a variety of bind, apply get disoriented; he asked me, you know the difference apply, call and bind it? I say that is a function call and apply application, specify this method will also perform different bind, it is only responsible for this binding and returns a new method, will not be executed.

He asked, that if the object is a way to bind a, and then bind the object b, and finally bind the object c, this time to perform this function points to who? (He often asked this wonderful question ...); I answered without thinking, it is c; Really? He asked to.

Asked the moment, I know I should be wrong, I wrote down a small demo verification, sure enough, so I feel the need to understand the differences in detail under the three methods.

let o1 = {
    a: 1
};
let o2 = {
    a: 2
};
let o3 = {
    a: 3
};

function fn(b, c) {
    console.log(this.a);
};

let fn1 = fn.bind(o1);
let fn2 = fn1.bind(o2);
let fn3 = fn2.bind(o3);
fn3() //?

 II ❀ function calls and function application

We know that the implementation of a function in two ways, one is the common function call, the second function is applied.

From the active-passive relationship to explain the function call is more passive, and function application it is very active, and we look at an example:

var name = "hear the wind is the wind" , 
    obj = { 
        name: 'echo' 
    }; 

function Fn () { 
    the console.log ( the this .name); 
}; 

// function call 
Fn () // hear the wind is the wind 

/ / function application 
fn.call (obj); // echo

 fn () is equivalent to window.fn () , se fn is invoked window, so this points to the window, it's like an ancient child marriages, arranged for fn for this plainly, and not freedom of marriage .

The fn.call () although it is equivalent to window.fn.call () , but the call to fn provides the opportunity to change this, and at this time this is the object obj. It can be seen as the emancipation of the mind, fn have the right to choose marriage, more freedom and happiness.

Having said that then you should understand, call () and apply () function is to provide a method of application, they make this point when the function executes more flexible.

 Triple ❀ call and apply

Standing on the perspective of function application we know that the use of call and apply, and that these two methods, what difference does it make, in fact, the difference is a little different way of passing parameters.

call方法中接受的是一个参数列表,第一个参数指向this,其余的参数在函数执行时都会作为函数形参传入函数

fn.call(this, arg1, arg2, ...);

而apply不同的地方是,除了第一个参数作为this指向外,其它参数都被包裹在一个数组中,在函数执行时同样会作为形参传入。

fn.apply(this, [arg1, arg2, ...]);

除此之外,两个方法的效果完全相同:

let o = {
    a: 1
};

function fn(b, c) {
    console.log(this.a + b + c);
};
fn.call(o, 2, 3); // 6
fn.apply(o, [2, 3]); //6

 肆 ❀ 关于bind

bind之所以要拿出来单独说,是因为它与call,apply又存在一些不同。call与apply在改变this的同时,就立刻执行,而bind绑定this后并不会立马执行,而是返回一个新的绑定函数

let o = {
    a: 1
};

function fn(b, c) {
    console.log(this.a + b + c);
};

let fn1 = fn.bind(o, 2, 3);

fn1();//6

还记得文章开头我同事提的问题吗,我之所以觉得bind多次后执行,this会指向最后一次bind的对象,是因为没能正确理解bind返回函数的含义。

尝试打印返回的新函数fn1,可以看到它并不是一个普通的function,而是一个bound function,简称绑定函数:

它的TargetFunction指向了bind前的的函数,BoundThis就是绑定的this指向,BoundArgs便是传入的其它参数了。

当我们执行fn1时,就有点类似于TargetFunction.apply(BoundThis,BoundArgs)

我们可以得出一个结论,当执行绑定函数时,this指向与形参在bind方法执行时已经确定了,无法改变。

let o1 = {
    a: 1
};
let o2 = {
    a: 2
};

function fn(b, c) {
    console.log(this.a + b + c);
};

let fn1 = fn.bind(o1, 2, 3);
//尝试再次传入形参
fn1(4, 4); //6

//尝试改变this
fn1.call(o2); //6

其实很好理解,当执行fn1时,本质上等于window.fn1(),如果this还能被改变,那this岂不是得指向window,那bind方法就没太大意义了。

 伍 ❀ 应用

说到这,我们大概知道了这三个方法的作用与区别,那这三个方法有啥用?其实很常用。

我们都知道Math.max()方法能取到一组数字中的最大值,比如:

Math.max(1, 10); //10
Math.min(1, 10); //1

那我们如何利用此方法求数组中最大最小呢,这里就可以利用apply的特性了:

Math.max.apply(null, [1, 2, 10]); //10
Math.max.min(null, [1, 2, 10]); //1

在非严格模式下,当我们让this指向null,或者undefined时,this本质上会指向window,不过这里的null就是一个摆设,我们真正想处理的其实是后面的数组。

还记得在考虑兼容情况下怎么判断一个对象是不是数组吗?再或者是不是一个函数?利用Object.prototype.toString()结合call方法就能解决这个问题:

let a = [];
let b = function () {};
Object.prototype.toString.call(a) === "[object Array]";//true
Object.prototype.toString.call(b) === "[object Function]";//true

 陆 ❀ 总

 那么到这里,我们一起理解了我同事提出的奇葩问题,为何bind多次后执行,函数this还是指向第一次bind的对象。

其次,除了函数调用,我们理解了函数应用的概念,也知道如何使用call和apply去实现一个函数应用,顺便通过bind还知道了绑定函数(bound function)的概念。

所以到这里,你知道call、apply与bind的区别了吗?

Guess you like

Origin www.cnblogs.com/echolun/p/11210659.html