Bootstrap

call-apply-bind浅析

一. 前言

此篇文档主要用来对call,apply以及bind的学习成果进行汇总。

bind是返回对应函数,便于稍后调用;call,apply则是立即调用。

二. 先来学习一下call,apply

在JavaScript中,call以及apply都是为了改变某个函数运行时的上下文(context),换句话说就是为了改变函数内部this的指向而存在的。

JavaScript的一大特点就是,函数存在定义时上下文运行时上下文以及上下文可以改变这样的概念。

function Fruits() { };
Fruits.prototype = {
    color: 'red',
    say: function () {
        console.log(this);
        console.log('my color is' + this.color);
    }
}

var apple = new Fruits();
// this 指向 Fruits{}
apple.say(); // my color is red

现有banana想要也想实现say()方法,但是我们不想重新定义,就可以通过call或apply使用apple的say()方法

const banana = {
    color: 'yellow'
}
// this 指向 banana{color:'yellow'}
apple.say.apply(banana);  // my color is yellow

由此可见:

cally以及apply都是为了动态改变this而出现的,当一个object没有某个方法而另外一个object有的时候,就可以借助call或apply来实现了!

三. call、apply的区别

对于call、apply来说,作用完全是一样的,只是接受的参数格式不同。

var func = function(arg1, arg2) { ... }

// this是你想要指定的上下文,可以是任何一个JavaScript对象。
func.call(this, arg1, arg2); // call需要把参数按照顺序传递进去
func.apply(this, [arg1, arg2]) // apply则是把参数放到数组里面                           

四. 使用call、apply的例子

数组追加

var array1 = [12, "foo", { name: "Joe" }, -2458];
var array2 = ["Doe", 555, 100];
Array.prototype.push.apply(array1, array2);
console.log(array1); // [12, "foo", {…}, -2458, "Doe", 555, 100]

获取数组中的最大值与最小值

var numbers = [5, 34, 56, 23];
var maxNumber = Math.max.apply(Math, numbers);
console.log(maxNumber); // 56

验证是否是数组

function isArr(arr) {
    return Object.prototype.toString.call(arr) === '[object Array]'
}
const array = [1, 2, 3, 4];
console.log(isArr(array));  // true

类(伪)数组使用数组的方法

var domNodes = Array.prototype.slice.call(document.getElementsByTagName('div'));

关于伪数组:

JavaScript中存在一种名为伪数组的对象结构,像:arguments对象,还有像调用getElementsByTagName…,它们返回的都是NodeList对象,都是伪数组。这类是无法使用数组的push…等方法的。

但是,我们可以通过使用 Array.prototype.slice.call() 转化为真正的数组。

四. bind

bind()方法和call、apply很相似,都是为了改变函数体内this的指向。

var write = document.write;
// write函数改变this的指向为全局window!
write('王晓雯');  // Illegal invocation

// 使用bind纠正
write.bind(document)('wxw');
write.call(document, 'wxw');
this.num = 9;
var myMoudle = {
    num: 80,
    getNum: function () {
        console.log(this.num, this);
    }
}

myMoudle.getNum(); // 80 myModle{... }

var getNum = myMoudle.getNum;
getNum();  // 9 window

// 使用bind 可以纠正this的指向为原来的的对象!
getNum.bind(myMoudle)(); // 80 myModle{... }

五. call、apply、bind的区别

var obj = {
    x: 90
}
var foo = {
    getX: function() {
        return this.x
    }
}
console.log(foo.getX()); // undefined
console.log(foo.getX.bind(obj)());  // 90
console.log(foo.getX.call(obj)); // 90	
console.log(foo.getX.call(obj)); // 90

call、apply、bind都能改变this的指向,区别是:当你希望改变上下文环境后而非立即执行,而是回调执行的时候,就可以使用bind()方法,而call、apply则会立即执行。

再总结一下:

call、apply、bind三者都是用来改变函数体内this的指向的

call、apply、bind三者的第一个参数都是this要指向的对象,也就是想指定的上下文

call、apply、bind三者都可以利用后续的参数传真

bind是返回对应的函数,方便后续调用;apply、call则是立即执行

六. 参考链接

[JS中的call、apply、bind方法详解

;