Appearance
手写
new
javascript
function myNew(Func, ...args) {
const instance = {};
if (Func.prototype) {
Object.setPrototypeOf(instance, Func.prototype);
}
const res = Func.apply(instance, args);
if (typeof res === "function" || (typeof res === "object" && res !== null)) {
return res;
}
return instance;
}
// 测试
function Person(name) {
this.name = name;
}
Person.prototype.sayName = function () {
console.log(`My name is ${this.name}`);
};
const me = myNew(Person, "Jack");
me.sayName();
console.log(me);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
bind
javascript
Function.prototype.myBind = function (context = globalThis) {
const fn = this;
const args = Array.from(arguments).slice(1);
const newFunc = function () {
const newArgs = args.concat(...arguments);
if (this instanceof newFunc) {
// 通过 new 调用,绑定 this 为实例对象
fn.apply(this, newArgs);
} else {
// 通过普通函数形式调用,绑定 context
fn.apply(context, newArgs);
}
};
// 支持 new 调用方式
newFunc.prototype = Object.create(fn.prototype);
return newFunc;
};
// 测试
const me = { name: "Jack" };
const other = { name: "Jackson" };
function say() {
console.log(`My name is ${this.name || "default"}`);
}
const meSay = say.myBind(me);
meSay();
const otherSay = say.myBind(other);
otherSay();
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
call
javascript
Function.prototype.myCall = function (context = globalThis) {
// 关键步骤,在 context 上调用方法,触发 this 绑定为 context,使用 Symbol 防止原有属性的覆盖
const key = Symbol("key");
context[key] = this;
// es5 可通过 for 遍历 arguments 得到参数数组
const args = [...arguments].slice(1);
const res = context[key](...args);
delete context[key];
return res;
};
// 测试
const me = { name: "Jack" };
function say() {
console.log(`My name is ${this.name || "default"}`);
}
say.myCall(me);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
apply
javascript
Function.prototype.myApply = function (context = globalThis) {
// 关键步骤,在 context 上调用方法,触发 this 绑定为 context,使用 Symbol 防止原有属性的覆盖
const key = Symbol("key");
context[key] = this;
let res;
if (arguments[1]) {
res = context[key](...arguments[1]);
} else {
res = context[key]();
}
delete context[key];
return res;
};
// 测试
const me = { name: "Jack" };
function say() {
console.log(`My name is ${this.name || "default"}`);
}
say.myApply(me);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20