|| 运算符在左侧操作数为真时,返回左侧操作数;否则,返回右侧操作数。
context = context || window;
箭头函数没有自己的 this,它捕获了定义它时的上下文 this。
箭头函数的这一特性意味着在实现 call 和 apply 方法时,它们不会影响箭头函数的 this 绑定。
这也是为什么我们通常不会在箭头函数上使用 call 和 apply 方法,因为这些方法的主要作用是改变函数调用时的 this 指向,而箭头函数已经在定义时锁定了 this。
Function.prototype.myCall = function(context, ...args) {
if (typeof context !== 'object' || context === null) {
console.log('Wrong argment!');
return;
}
const key = Symbol();
context[key] = this;
const res = context[key](...args);
delete context[key];
return res;
}
Function.prototype.myApply = function(context, argsArr) {
if (typeof context !== 'object' || context === null) {
console.log('Wrong argment!');
return;
}
const key = Symbol();
context[key] = this;
const res = context[key](...argsArr);
delete context[key];
return res;
}
Function.prototype.myBind = function(context, ...args) {
if (typeof context !== 'object' || context === null) {
console.log('Wrong argment!');
return;
}
const fn = this;
return function (...newArgs) {
const key = Symbol();
context[key] = fn;
const res = context[key](...args, ...newArgs);
delete context[key];
return res;
}
}
Function.prototype.myBind_call = function(context, ...args) {
if (typeof context !== 'object' || context === null) {
console.log('Wrong argment!');
return;
}
const fn = this;
return function (...newArgs) {
return fn.call(context, ...args, ...newArgs);
}
}
Function.prototype.myBind_apply = function(context, ...args) {
if (typeof context !== 'object' || context === null) {
console.log('Wrong argment!');
return;
}
const fn = this;
return function (...newArgs) {
return fn.apply(context, args.concat(newArgs));
// return fn.apply(context, [...args, ...newArgs]);
}
}
// 用例:
const obj1 = {
name: 'John',
greet: function(greeting) {
console.log(greeting + ', ' + this.name);
}
};
function greet(greeting) {
console.log(greeting + ', ' + this.name);
}
obj1.greet.myCall({ name: 'Alice' }, 'Hello');
greet.myCall({ name: 'Bob' }, 'Hi');
obj1.greet.myApply({ name: 'Alice' }, ['Hello']);
greet.myApply({ name: 'Bob' }, ['Hi']);
const boundGreet1 = obj1.greet.myBind_apply({ name: 'Alice' });
const boundGreet2 = greet.myBind_apply({ name: 'Bob' });
const boundGreet3 = obj1.greet.myBind_call({ name: 'Carole' });
const boundGreet4 = greet.myBind_call({ name: 'Decare' });
boundGreet1('Hello');
boundGreet2('Hi');
boundGreet3('Hello');
boundGreet4('Hi');
const obj2 = {
name: 'John',
greet: function(greeting, punctuation) {
console.log(greeting + ', ' + this.name + punctuation);
}
};
obj2.greet.myCall({ name: 'Alice' }, 'Hello', '!');
greet.myCall({ name: 'Bob' }, 'Hi');
obj2.greet.myApply({ name: 'Alice' }, ['Hello', '!']);
greet.myApply({ name: 'Bob' }, ['Hi']);
const boundGreet = obj2.greet.myBind({ name: 'Alice' }, 'Hello', '!');
boundGreet();
const partialBoundGreet = obj2.greet.myBind({ name: 'Bob' }, 'Hi');
partialBoundGreet('!');
const partialBoundGreet2 = obj2.greet.myBind({ name: 'Bob' }, undefined);
partialBoundGreet2('!');
// 一个普通对象
const person = {
name: 'Alice',
regularFunction: function() {
console.log(this.name); // this 指向 person 对象
},
arrowFunction: () => {
console.log(this.name); // this 指向定义时的上下文(这里是全局对象或 undefined) // 在全局上下文中定义的箭头函数,this 是全局对象(浏览器中是 window,在严格模式下是 undefined)。
}
};
// 正常调用
person.regularFunction(); // 输出: Alice
person.arrowFunction(); // 输出: undefined 或抛出错误
// 使用 call 方法
person.regularFunction.call({ name: 'Bob' }); // 输出: Bob
person.arrowFunction.call({ name: 'Bob' }); // 输出: undefined 或抛出错误 // 使用 call 方法调用箭头函数并不会改变其 this 值,因为箭头函数不会重新绑定 this。