apply、call和bind的区别?
https://segmentfault.com/a/1190000018017796
都是可以改变 this 的指向的。
- apply 和 call 基本类似,他们的区别只是传入的参数不同。
- apply第二个对象是数组
- call多个参数平铺
- bind 是创建一个新的函数,必须要手动去调用。
func.apply(thisArg, [argsArray])
func.call([thisArg[, arg1, arg2, ...argN]])
let boundFunc = func.bind(thisArg[, arg1[, arg2[, ...argN]]])
执行结果/call
下面代码的输出是什么?
const person = { name: "Lydia" };
function sayHi(age) {
console.log(`${this.name} is ${age}`);
}
sayHi.call(person, 21);
sayHi.bind(person, 21);
A: undefined is 21
Lydia is 21
B: function
function
C: Lydia is 21
Lydia is 21
D: Lydia is 21
function
答案:D 原因:.call
方法会立即执行!.bind
方法会返回函数的拷贝值,
手写apply和call
myCall
Function.prototype.myCall = function (content) {
const cxt = content || window;
const args = Array.from(arguments).slice(1); // 类数组转换成数组
const key = Symbol();
cxt[key] = this; // 函数内部的this指向content
let res = cxt[key](...args);
delete cxt[key];
return res;
}
myApply
Function.prototype.myApply = function (context, args) {
context = context || window
args = args ? args : []
const key = Symbol() //给context新增一个独一无二的属性以免覆盖原有属性
context[key] = this
const result = context[key](...args) //通过隐式绑定的方式调用函数
delete context[key] //删除添加的属性
return result
}
手写bind
https://github.com/mqyqingfeng/Blog/issues/12
⚠️ 返回function
Function.prototype.myBind = function (context, ...args) {
const fn = this
args = args ? args : []
return function newFn(...newFnArgs) {
if (this instanceof newFn) {
return new fn(...args, ...newFnArgs)
}
return fn.apply(context, [...args,...newFnArgs])
}
}
this的绑定方式优先级:箭头函数 -> new绑定 -> 显示绑定call/bind/apply -> 隐式绑定 -> 默认绑定
bind1:针对void 函数,简单的改变this指向
Function.prototype.ebind = function(obj) {
const func = this;
return function () {
return func.call(obj);
}
}
// 测试
let obj = {
name: 'Jack',
};
let myFunc = function () {
console.log(`${this.name}`);
};
let newFunc = myFunc.ebind(obj)
newFunc() // Jack
bind2: 针对多个参数函数,改变this指向
Function.prototype.ebind = function() {
const func = this;
const args = [...arguments];
return function () {
return func.call(...args);
}
}
// 测试
let obj = {
name: 'Jack',
};
let myFunc = function (id) {
console.log(`${this.name}, ${id}`);
};
let newFunc = myFunc.ebind(obj, 1287)
newFunc() // Jack, 1287
bind3:
Function.prototype.ebind = function() {
const func = this;
const args = [...arguments];
return function () {
const _args = [...arguments];
return func.call(...args, ..._args);
}
}
// 测试
let obj = {
name: 'Jack',
};
let myFunc = function (...args) {
console.log(`${this.name}, ${args.join(', ')}`);
};
myFunc.ebind(obj, 1278)('Cheng Du', '天府一街')
// Jack, 1278, Cheng Du, 天府一街
bind4: 支持
Function.prototype.ebind = function() {
const func = this;
const args = [...arguments];
return function Fn () {
const _args = [...arguments];
if (this instanceof Fn) {
return new func(...args.slice(1), ..._args);
}
return func.call(...args, ..._args);
}
}
// 测试
let obj = {
name: 'Jack',
};
let myFunc = function (...args) {
console.log(`${this.name}, ${args.join(', ')}`);
};
let test1 = myFunc.ebind(obj, 1278);
console.log(new test1('Cheng Du'));
// Jack, 1278, Cheng Du