Skip to content
On this page

手写

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

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

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

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
沪ICP备20006251号-1