◆
JavaScript apply、call 和 bind 用法详解
apply
apply() 方法调用一个具有给定 this 值的函数,以及以一个数组(或类数组对象)的形式提供的参数。
语法:func.apply(thisArg, [argsArray])
thisArg:在func函数运行时使用的this值argsArray: 一个数组或者类数组对象
返回值:调用有指定 this 值和参数的函数的结果。
实用方法
通过 apply,push 整个数组元素
直接使用
push会把整个数组push成一个元素,用apply可以避免这种情况
var array = ['a', 'b'];
var elements = [0, 1, 2];
array.push.apply(array, elements);
console.info(array); // ["a", "b", 0, 1, 2]
const numbers = [5, 6, 2, 3, 7];
const max = Math.max.apply(null, numbers);
const min = Math.min.apply(null, numbers);
console.log(max); // 7
console.log(min); // 2
call
call() 方法使用一个指定的 this 值和单独给出的一个或多个参数来调用一个函数。
- 该方法的语法和作用与
apply()方法类似,只有一个区别,就是call()方法接受的是一个参数列表,而apply()方法接受的是一个包含多个参数的数组。
bind
bind() 方法创建一个新的函数,在 bind() 被调用时,这个新函数的 this 被指定为 bind() 的第一个参数,而其余参数将作为新函数的参数,供调用时使用。
bind与apply和call都是用来绑定this,bind与 其他两个的区别是,bind是创建一个函数,但不会直接调用,其他两个绑定this指向后会直接调用函数。
返回值 返回一个原函数的拷贝,并拥有指定的 this 值和初始参数。
回调函数中使用 bind
var obj = {
name: 'fx',
};
setTimeout(
function () {
console.log(this.name); // fx
}.bind(obj),
1000,
);
var name = 'fnn';
不用 bind 绑定
var obj = {
name: 'fx',
};
setTimeout(function () {
console.log(this.name); // fnn
}, 1000);
var name = 'fnn';
模拟实现 call 方法
- 思路是在
context(在函数运行时使用的this值)对象上增加一个函数属性,其属性值就是调用的函数,执行时,使用对象中的函数属性执行,执行完毕后删除此对象的属性。 Object(context):为了避免context传入的不是一个对象,如传入了一个基本类型的字符串,字符串.属性会产生语法错误,所以使用Object包裹一下,将基本类型转为其对应的包装类型const symbolKey = Symbol(): 使用Symbol的作用,如果不使用Symbol,就需要随机定义一个属性名,这个属性名在context对象上可能存在,所以使用Symbol保持其唯一性eval('context.fn(' + args +')')这种写法,可以将 args 中的数组,变成一个一个的单个参数,如[1, 2, 3]变成1, 2, 3,虽然下面的示例也可以通过ES6的扩展运算符去解决
Function.prototype.copyCall = function (context) {
context = context ? Object(context) : window;
const symbolKey = Symbol();
context[symbolKey] = this;
var args = [];
for (var i = 1, len = arguments.length; i < len; i++) {
args.push('arguments[' + i + ']');
}
var result = eval('context[symbolKey](' + args + ')');
delete context.fn;
return result;
};
测试代码
var fnn = 2;
var obj = {
fnn: 888,
};
function bar(name, age) {
console.log(this.fnn, name, age);
}
bar.copyCall(null, 'fnn', '18.5'); // 2 'fnn' '18.5'
bar.copyCall(obj, 'fx', '18'); // 888 'fx' '18'
eval 测试
const arr = [12, 3123, 213];
function test(a, b, c) {
console.log(a, b, c);
}
eval('test(' + arr + ')'); // 输出 12 3123 213
eval('test(arr)'); // 输出 [12, 3123, 213] undefined undefined
模拟实现 apply 方法
思路和 call 一样
Function.prototype.copyApply = function (context, arr) {
context = context ? Object(context) : window;
const symbolKey = Symbol();
context[symbolKey] = this;
var result;
if (!arr) {
result = context[symbolKey]();
} else {
var args = [];
for (var i = 0, len = arr.length; i < len; i++) {
args.push('arr[' + i + ']');
}
result = eval('context[symbolKey](' + args + ')');
}
delete context[symbolKey];
return result;
};
测试代码
var fnn = 2;
var obj = {
fnn: 888,
};
function bar(name, age) {
console.log(this.fnn, name, age);
}
bar.copyApply(null, ['fnn', '18.5']); // 2 'fnn' '18.5'
bar.copyApply(obj, ['fx', '18']); // 888 'fx' '18'

还没有留言,来发表第一条吧~