关于call,bind,apply

关于call,bind,apply的作用

这三个方法都是只有函数才可以调用,作用就是改变函数执行时this的指向。

代码中用到的一些知识的说明

rest

  • rest是es6的一个新语法,参数接受函数的多余参数,组成一个数组,放在形参的最后
    1
    2
    3
    4
    5
    let one=function(...rest){
    console.log(rest instanceof Arrary); // true
    console.log(rest);// [1,2,3]
    };
    one(1,2,3);

…<一个数组>

  • 解构赋值,他是一种针对数组或者对象进行模式匹配,然后对其中的变量进行赋值
    1
    2
    3
    4
    5
    6
    let arr=[1,2,3];
    console.log(arr);// [1, 2, 3]
    console.log(...arr);// 1 2 3
    let brr=[...arr];
    // 很方便的复制arr的值到brr
    console.log(brr);// [1, 2, 3]

如何使用?

call

参数(obj,arg1,arg2,…)

  • 第一个参数是要绑定的目标对象,后面的参数就是要传入函数内的参数,可以是任何类型
  • 代码示例
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    let one = {
    name: 'one',
    sayhi(...rest) {
    console.log(`这是${this.name}的函数,这是传递进来的参数:${rest[0]},${rest[1]}`);
    }
    };
    // 这是one的函数,这是传递进来的参数:参数一,参数二
    one.sayhi('参数一', '参数二');
    let two = {
    name: 'two'
    };
    // 这是two的函数,这是传递进来的参数:参数1,参数2
    one.sayhi.call(two, '参数a', '参数b');

bind

参数(obj,arg1,arg2,…)()

  • 第一个参数是要绑定的目标对象,后面的参数就是要传入函数内的参数,可以是任何类型
  • 使用时,需要在调用一次,因为bind返回的是一个函数
  • 代码示例
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    let one = {
    name: 'one',
    sayhi(...rest) {
    console.log(`这是${this.name}的函数,这是传递进来的参数:${rest[0]},${rest[1]}`);
    }
    };
    // 这是one的函数,这是传递进来的参数:参数一,参数二
    one.sayhi('参数一', '参数二');
    let two = {
    name: 'two'
    };
    // 这是two的函数,这是传递进来的参数:参数1,参数2
    one.sayhi.bind(two, '参数a', '参数b')();

apply

参数(obj,[arg1,arg2,…])

  • 第一个参数时要绑定的目标对象,后面的参数,都以数组形式传入
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    let one = {
    name: 'one',
    sayhi(...rest) {
    console.log(`这是${this.name}的函数,这是传递进来的参数:${rest[0]},${rest[1]}`);
    }
    };
    // 这是one的函数,这是传递进来的参数:参数一,参数二
    one.sayhi('参数一', '参数二');
    let two = {
    name: 'two'
    };
    // 这是two的函数,这是传递进来的参数:参数1,参数2
    one.sayhi.apply(two, ['参数a', '参数b']);

总结三者不同

传参数不同

  • call和bind在参数传递时,都是以多参数传递,只是bind使用是需要再调用一次返回的函数;
  • apply在传递参数时,都是以数组形式传递;

使用不同

  • call和apply改变了函数的this上下文后便执行该函数
  • bind则是返回改变了上下文后的一个函数。

三者的应用

将伪数组转换成数组

  • 啥是伪数组?就是长得像数组,但是不是数组,是一个对象;以及含有length的对象
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    // 函数内部的 arguments 就是一个伪数组
    let one = function () {
    console.log(arguments); //Arguments(3) [1, 2, 3, callee: ƒ, Symbol(Symbol.iterator): ƒ]
    console.log(typeof arguments); //object
    console.log(arguments instanceof Array); // false
    let arr = Array.prototype.slice.call(arguments);
    console.log(arr); //  [1, 2, 3]
    console.log(typeof arr); // object
    console.log(arr instanceof Array); //true
    };
    one(1, 2, 3);

利用call和apply实现继承

1
2
3
4
5
6
7
8
9
10
11
12
function Person(name) {
this.name = name;
this.sayhi = function () {
console.log(`${this.name}向您问好`);
}
}

function Man(name) {
Person.call(this, name);
}
let shuaxin = new Man('刷新');
shuaxin.sayhi();

来动手实现一下call、bind、apply

call

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 通过rest来接受参数
Function.prototype.mycall = function (...rest) {
// 判断调用该函数的是不是函数
if (typeof this === 'function') {
// 获取要绑定的对象
var obj = rest.splice(0, 1)[0];
// 给目标对象添加当前调用的函数
obj[this.name] = this;
// 并将要传递参数再一次传入进去
obj[this.name](...rest);
// 删除目标对象的该方法
delete obj.sayhi;
} else {
console.log('该函数只可以被函数调用');
}
return obj[this.name];
};

bind

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Function.prototype.mybind = function (...rest) {
if (typeof this === 'function') {
// 获取要绑定的对象
var obj = rest.splice(0, 1)[0];
var fname = this.name;
// 给该函数绑定当前调用的函数
obj[fname] = this;
} else {
console.log('该函数只可以被函数调用');
}
return function () {
// 将要传递参数再一次传入进去
obj[fname](...rest);
// 删除该方法
delete obj[fname];
}
};

apply

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
 Function.prototype.myapply = function (...rest) {
if (typeof this === 'function') {
// 获取要绑定的对象
var obj = rest.splice(0, 1)[0];
// 给该函数绑定当前调用的函数
obj[this.name] = this;
// 将要传递参数再一次传入进去
if (rest[0] instanceof Array) {
obj[this.name](...rest[0]);

} else {
obj[this.name](rest[0]);
}
// 删除该方法
delete obj.sayhi;
} else {
console.log('该函数只可以被函数调用');
}
return obj[this.name];
};

参考链接

JavaScript 中 call()、apply()、bind() 的用法

JavaScript深入之call和apply的模拟实现

让你弄懂 call、apply、bind的应用和区别


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!