Call

  1. Function.prototype.myCall = function(thisArg, ...args) {
  2. thisArg = thisArg || window;
  3. thisArg.func = this;
  4. const result = thisArg.func(...args); // args 为数组
  5. delete thisArg.func;
  6. return result;
  7. }
  1. Function.prototype.myCall = function(thisArg, ...args) {
  2. thisArg = thisArg || window;
  3. const func = Symbol(); // Symbol
  4. thisArg[func] = this;
  5. const result = thisArg[func](...args);
  6. Reflect.deleteProperty(thisArg, func); // Reflect
  7. return result;
  8. }

测试

  1. const obj = {};
  2. obj.hasOwnProperty('toString') // false
  3. // 覆盖掉继承的 hasOwnProperty 方法
  4. obj.hasOwnProperty = function () {
  5. return true;
  6. };
  7. obj.hasOwnProperty('toString') // true
  8. Object.prototype.hasOwnProperty.call(obj, "toString") // false
  9. Object.prototype.hasOwnProperty.myCall(obj, "toString") // false

apply

  1. Function.prototype.myApply = function(thisArg, arr) {
  2. thisArg = thisArg || window;
  3. arr = arr ? Array.from(arr) : []; // 考虑null和undefined
  4. thisArg.func = this;
  5. const result = thisArg.func(...arr);
  6. delete thisArg.func;
  7. return result;
  8. }
  1. Function.prototype.myApply = function(thisArg, arr) {
  2. thisArg = thisArg || window;
  3. arr = arr ? Array.from(arr) : [];
  4. const func = Symbol(); // Symbol
  5. thisArg[func] = this;
  6. const result = thisArg[func](...arr);
  7. Reflect.deleteProperty(thisArg, func); // Reflect
  8. return result;
  9. }

测试

  1. const a = [10, 2, 4, 15, 9];
  2. Math.max.apply(null, a) // 15
  3. Math.max.myApply(null, a) // 15
  4. Array.prototype.slice.apply({0: 1}) // []
  5. Array.prototype.slice.apply({0: 1, length: 2}) // [1, empty]
  6. Array.prototype.slice.myApply({0: 1}) // []
  7. Array.prototype.slice.myApply({0: 1, length: 2}) // [1, empty]

补充测试

  1. Math.max.apply(null, {}) // -Infinity
  2. Math.max.myApply(null, {}) // -Infinity

bind

补充特性

一个绑定函数也能使用 new 操作符创建对象:这种行为就像把原函数当成构造器,提供的 this 值被忽略,同时调用时的参数被提供给模拟函数。

  1. Function.prototype.myBind = function (thisArg, ...args) {
  2. thisArg = thisArg || window;
  3. const self = this;
  4. const fBound = function (...rest) {
  5. if (this instanceof self) {
  6. return new self(...args.concat(rest));
  7. }
  8. return self.apply(thisArg, args.concat(rest));
  9. }
  10. fBound.prototype = Object.create(self.prototype);
  11. fBound.prototype.constructor = fBound;
  12. return fBound;
  13. }
  14. // 或者
  15. Function.prototype.myBind = function(thisArg, ...args) {
  16. thisArg = thisArg || window;
  17. const self = this;
  18. return function fBound(...rest) {
  19. if (this instanceof fBound) {
  20. return new self(args.concat(rest));
  21. }
  22. return self.apply(obj, args.concat(rest));
  23. }
  24. }

测试1

  1. const counter = {
  2. count: 0,
  3. inc: function () {
  4. this.count++;
  5. }
  6. };
  7. const func = counter.inc.myBind(counter);
  8. func();
  9. counter.count // 1

测试2

  1. let value = 2;
  2. let foo = {
  3. value: 1
  4. };
  5. function bar(name, age) {
  6. this.habit = 'shopping';
  7. console.log(this.value);
  8. console.log(name);
  9. console.log(age);
  10. }
  11. bar.prototype.friend = 'kevin';
  12. // let bindFoo = bar.bind(foo, 'Jack');
  13. let bindFoo = bar.myBind(foo, 'Jack');
  14. let obj = new bindFoo(20);
  15. // undefined
  16. // Jack
  17. // 20
  18. obj.habit
  19. // shopping
  20. obj.friend
  21. // kevin

补充测试(无法正常实现)

  1. // const push = Function.prototype.call.myBind(Array.prototype.push);
  2. const push = Function.prototype.call.bind(Array.prototype.push);
  3. const a = [1 ,2 ,3];
  4. push(a, 4)
  5. a // [1,2,3,4]
  6. const d = new Date();
  7. d.getTime() // 1656683945486
  8. const print = d.getTime.bind(d)()
  9. print() // 1656683945486
  10. // d.getTime.myBind(d)()
  11. // Uncaught TypeError: Object prototype may only be an Object or null: undefined