手写call
<script>
//将自己的myCall方法绑定在原型链上
Function.prototype.myCall = function (thisArgs = {},...args){
//如果传入的是 null 或 undefined,则将其设置为全局对象(这里假设了全局对象可能是 window 或 global)
//这样做可以避免在尝试访问 null 或 undefined 的属性时抛出错误
if (thisArgs === null || thisArgs === undefined) {
thisArgs = typeof window !== "undefined" ? window : global;
}
//为了不与其他属性重名,选择ES6又名(ECMAScript2015)中的新的原始数据类型Symbol,用于表示独一无二的值
let key = Symbol('key');
//这里的this表示fun1,由于是fun1
//注意这里是使用[],不可以使用thisArgs.key进行赋值,使用thisArgs.key就是key属性而不是Symbol('key')了
thisArgs[key] = this;
// 使用展开运算符将 args 数组展开为参数列表,并调用函数
let res = thisArgs[key](...args)
// 清理:删除临时属性
delete thisArgs[key]
// 返回结果
return res
}
let obj = {
name:'222'
}
function fun1 (num1,string1){
console.log(num1)
console.log(string1)
return num1+string1
}
console.log(fun1.myCall(obj,11,'ddd'))
</script>
手写apply
<script>
//将自己的myApply方法绑定在原型链上
Function.prototype.myApply = function (thisArgs = null, args = []){
// 如果 thisArgs 是 null 或 undefined,则根据是否在严格模式下设置 this 的值
if (thisArgs === null || thisArgs === undefined) {
// 注意:在非严格模式下,全局对象是 window(浏览器环境)或 global(Node.js 环境)
// 这里为了简单起见,我们假设非严格模式,并且是浏览器环境
thisArgs = typeof window !== "undefined" ? window : (typeof global !== "undefined" ? global : this);
// 但在严格模式下,我们应该让 this 保持为 undefined
if (new.target === undefined) { // 这里的检查可能不完全准确,但可以用来模拟严格模式
thisArgs = undefined;
}
}
// 为了不与其他属性重名,选择使用 Symbol
const key = Symbol('key');
// 将当前函数(this)作为 thisArgs 的一个属性
thisArgs[key] = this;
// 使用展开运算符将 args 数组展开为参数列表,并调用函数
const res = thisArgs[key](...args);
// 清理:删除临时属性
delete thisArgs[key];
// 返回结果
return res;
}
let obj = {
name:'222'
}
function fun1 (num1,string1){
console.log(num1)
console.log(string1)
return num1+string1
}
console.log(fun1.myApply(obj,[11,'ddd']))
</script>
小小记忆点:call和apply很相似,一个是传入多个参数,一个是传入数组,怎么记住呢?传入数组的是apply,数组的英文是array,他们都是a开头!