Call
Function.prototype.myCall = function(thisArg, ...args) {thisArg = thisArg || window;thisArg.func = this;const result = thisArg.func(...args); // args 为数组delete thisArg.func;return result;}
Function.prototype.myCall = function(thisArg, ...args) {thisArg = thisArg || window;const func = Symbol(); // SymbolthisArg[func] = this;const result = thisArg[func](...args);Reflect.deleteProperty(thisArg, func); // Reflectreturn result;}
测试
const obj = {};obj.hasOwnProperty('toString') // false// 覆盖掉继承的 hasOwnProperty 方法obj.hasOwnProperty = function () {return true;};obj.hasOwnProperty('toString') // trueObject.prototype.hasOwnProperty.call(obj, "toString") // falseObject.prototype.hasOwnProperty.myCall(obj, "toString") // false
apply
Function.prototype.myApply = function(thisArg, arr) {thisArg = thisArg || window;arr = arr ? Array.from(arr) : []; // 考虑null和undefinedthisArg.func = this;const result = thisArg.func(...arr);delete thisArg.func;return result;}
Function.prototype.myApply = function(thisArg, arr) {thisArg = thisArg || window;arr = arr ? Array.from(arr) : [];const func = Symbol(); // SymbolthisArg[func] = this;const result = thisArg[func](...arr);Reflect.deleteProperty(thisArg, func); // Reflectreturn result;}
测试
const a = [10, 2, 4, 15, 9];Math.max.apply(null, a) // 15Math.max.myApply(null, a) // 15Array.prototype.slice.apply({0: 1}) // []Array.prototype.slice.apply({0: 1, length: 2}) // [1, empty]Array.prototype.slice.myApply({0: 1}) // []Array.prototype.slice.myApply({0: 1, length: 2}) // [1, empty]
补充测试
Math.max.apply(null, {}) // -InfinityMath.max.myApply(null, {}) // -Infinity
bind
补充特性
一个绑定函数也能使用 new 操作符创建对象:这种行为就像把原函数当成构造器,提供的 this 值被忽略,同时调用时的参数被提供给模拟函数。
Function.prototype.myBind = function (thisArg, ...args) {thisArg = thisArg || window;const self = this;const fBound = function (...rest) {if (this instanceof self) {return new self(...args.concat(rest));}return self.apply(thisArg, args.concat(rest));}fBound.prototype = Object.create(self.prototype);fBound.prototype.constructor = fBound;return fBound;}// 或者Function.prototype.myBind = function(thisArg, ...args) {thisArg = thisArg || window;const self = this;return function fBound(...rest) {if (this instanceof fBound) {return new self(args.concat(rest));}return self.apply(obj, args.concat(rest));}}
测试1
const counter = {count: 0,inc: function () {this.count++;}};const func = counter.inc.myBind(counter);func();counter.count // 1
测试2
let value = 2;let foo = {value: 1};function bar(name, age) {this.habit = 'shopping';console.log(this.value);console.log(name);console.log(age);}bar.prototype.friend = 'kevin';// let bindFoo = bar.bind(foo, 'Jack');let bindFoo = bar.myBind(foo, 'Jack');let obj = new bindFoo(20);// undefined// Jack// 20obj.habit// shoppingobj.friend// kevin
补充测试(无法正常实现)
// const push = Function.prototype.call.myBind(Array.prototype.push);const push = Function.prototype.call.bind(Array.prototype.push);const a = [1 ,2 ,3];push(a, 4)a // [1,2,3,4]const d = new Date();d.getTime() // 1656683945486const print = d.getTime.bind(d)()print() // 1656683945486// d.getTime.myBind(d)()// Uncaught TypeError: Object prototype may only be an Object or null: undefined
