call,apply,bind的使用方法
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<script>
var name = 'tc'
const obj = {
name: 'ljr',
say: function (val, hobby) {
return this.name + val + hobby
},
}
console.log(obj.say('你好', '喜欢打球')) //ljr你好喜欢打球
const f = obj.say
console.log(f('你好', '喜欢打球')) //tc你好喜欢打球
console.log(f.call(obj, '是美女', '喜欢唱歌')) //ljr是美女喜欢唱歌
console.log(f.apply(obj, ['是小仙女', '喜欢唱歌'])) //ljr是小仙女喜欢唱歌
console.log(f.bind(obj, '是宝藏女孩,', '喜欢唱周杰伦的歌')()) //ljr是宝藏女孩,喜欢唱周杰伦的歌
</script>
</body>
</html>
三者的区别
call与apply的唯一区别
传给fun
的参数写法不同:
apply
是第2个参数,这个参数是一个数组:传给fun
参数都写在数组中。call
从第2~n的参数都是传给fun
的。
call/apply与bind的区别
执行:
- call/apply改变了函数的this上下文后马上执行该函数
- bind则是返回改变了上下文后的函数,不执行该函数
返回值:
- call/apply 返回
fun
的执行结果 - bind返回fun的拷贝,并指定了fun的this指向,保存了fun的参数。
原理:
手写 call
Function.prototype.myCall = function(context = globalThis) {
// 设置 fn 为调用 myCall 的方法
context.fn = this;
// 获取剩余参数
const otherArg = Array.from(arguments).slice(1);
// 调用这个方法,将剩余参数传递进去
context.fn(otherArg);
// 将这个方法的执行结果传给 result
let result = context.fn();
// 删除这个变量
delete context.fn;
// 返回 result 结果
return result;
};
this.a = 1;
const fn = function() {
this.a = 2;
console.log(this.a);
}
fn.myCall(fn);
手写apply
Function.prototype.myApply = function(context = globalThis, arr) {
// 设置 fn 为调用 myCall 的方法
context.fn = this;
let result;
// 如果存在参数,则传递进去
// 将结果返回给 result
if (arr) {
result = context.fn(arr);
} else { // 否则不传
result = context.fn();
}
// 删除这个变量
delete context.fn;
// 返回 result 结果
return result;
};
this.a = 1;
const fn = function() {
this.a = 2;
console.log(this.a);
}
fn.myApply(fn);
手写bind
Function.prototype.myBind = function(context = globalThis) {
// 设置 fn 为调用 myCall 的方法
const fn = this;
// 获取该方法剩余参数
const otherArg = [...arguments].slice(1);
// 设置返回的一个新方法
const result = function() {
// 获取返回方法体的参数
const resultArg = [...arguments];
// 如果是通过 new 调用的,绑定 this 为实例对象
if (this instanceof result) {
fn.apply(this, otherArg.concat(resultArg));
} else { // 否则普通函数形式绑定 context
fn.apply(context, otherArg.concat(resultArg));
}
}
// 绑定原型链
result.prototype = Object.create(fn.prototype);
// 返回结果
return result;
};
this.a = 1;
const fn = function() {
this.a = 2;
console.log(this.a);
}
fn.myBind(fn);
fn();
函数的Arguments 对象
arguments
是一个对应于传递给函数的参数的类数组对象。
function fun(a, b, c) {
console.log(arguments[0]); // 1
console.log(arguments[1]); // 2
console.log(arguments[2]); // 3
}
复制代码
arguments
对象不是一个 Array
。
它类似于 Array
,但除了 length
属性和索引元素之外没有任何 Array
属性。
将 arguments
转为数组:
// ES5
var arg1 = Array.prototype.slice.call(arguments);
var arg2 = [].slice.call(arguments);
// ES6
var arg3 = Array.from(arguments);
var arg4 = [...arguments];
复制代码
在手写 call/bind/apply
过程中,会用到 arguments
来获取方法体的传参,就好比手写 call
过程中,通常我们通过 Array.from(arguments).slice(1)
来获取第二个及后面的参数。