了解下this的指向

  • 普通函数当中的this指向window
  • 对象身上的方法指向这个对象
  • 箭头函数的this执行上层作用域下的this

手写call

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

Function.prototype.myCall = function(context,...arg){
context = context!== undefined && context !== null ? Object(context) : window;
let callFn = this;//获取call
let symbolTemp = Symbol('临时');//临时存储
context[symbolTemp] = callFn;
let result = context[symbolTemp](...arg);
delete context[symbolTemp];//用后删除
console.log(context[symbolTemp]);//undefine
return result;
}
const testExample = {
x: 42,
getX: function (a,b,c) {
console.log('传入的参数',a,b,c);
return this.x;
},
};
const test = testExample.getX;
// console.log( test.call(testExample)); 相当于变为了testExample.test();
console.log(test.myCall(testExample,10,20,30));

手写apply

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
 Function.prototype.myApply = function(context,argArray){
context = context !== undefined && context !== null ? Object(context) : window;
argArray = argArray?.length ? argArray : [];
let callFn = this;
let symbolTemp = Symbol('临时存储');
context[symbolTemp] = callFn;
return context[symbolTemp](...argArray)
}
const testExample = {
x: 42,
getX: function (a,b,c,d) {
console.log('查看参数',a,b,c,d);
return this.x;
},
};
const test = testExample.getX;
// console.log(test.apply(testExample,[10,20,30,40])); //官方用法 相当变为了testExample.test(10,20,30,40);
console.log(test.myApply(testExample,[10,20,30,40]));

手写bind

  • 最简单版本
    • 利用了对象身上的方法被执行的时候指向的是这个对象的原理
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
Function.prototype.myBind = function(context,...args){
context = context !== undefined && context !== null ? Object(context) : window;
const callFn = this;
const symbolTemp = Symbol('临时对象')
context[symbolTemp] = callFn;
return function(...argArray){
let result = context[symbolTemp](...argArray,...args);
delete context[symbolTemp];//用后删除
console.log(context[symbolTemp]);//undefine
return result
}
}
const testExample = {
x: 42,
getX: function () {
return this.x;
},
};
const test = testExample.getX;
// console.log(test.bind(testExample)()); //官方用法
console.log( test.myBind(testExample) ());

chat-gpt修改意见-以apply为例

  • 首先,对于传入的 context 参数,您已经考虑了一些边界情况,例如 undefinednull,并使用 Object(context) 将其转换为对象。但是,您的实现并没有考虑传递非对象的原始值(例如字符串或数字),在这种情况下,您的代码将抛出 TypeError。您可以通过使用 Object(context) 来强制将原始值转换为其包装对象,以避免这种情况。

  • 其次,对于传入的 argArray 参数,您使用了可选链式调用 ?. 来检查它是否为 null 或 undefined,并且使用 length 属性来检查其是否为空数组。这是一个很好的实践,但是如果您的代码要在较早的 JavaScript 版本中运行,则可能会出现问题。在这种情况下,您可以使用更传统的 if 语句来进行检查,例如 if (!argArray || argArray.length === 0) { argArray = []; }

  • 最后,您的实现使用了一个唯一的 Symbol 来存储函数,并将其存储在上下文对象中,然后使用调用运算符 () 来调用该函数并传递参数数组。这是一种非常聪明和安全的方法来确保不会意外覆盖上下文对象中的现有属性。但是,如果您的代码需要在旧版本的 JavaScript 中运行,则可能需要使用字符串键来存储函数,例如 context['__myApply_temp_fn'] = callFn;

  • 下面是经过改进的代码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    Function.prototype.myApply = function(context, argArray) {
    context = Object(context);
    argArray = (argArray && argArray.length) ? argArray : [];
    let callFn = this;
    let tempKey = '__myApply_temp_fn';
    context[tempKey] = callFn;
    let result = context[tempKey](...argArray);
    delete context[tempKey];
    return result;
    };