前言
不能使用ES6的语法糖来实现,比如(解构赋值,symbol)
call方法
想要对call 的重写,前提是需要知道 call 的几个特点:(假设有一个 函数 test)
- test 调用 call() ,那么就会执行 text。
- test 中的this 指向 call 的第一个参数。
- call 的第二个参数开始,都在test函数的参数列表中
1 2 3 4 5
| function test() { console.log(this,arguments); }
test.call({a:1,b:2},'张三','李四')
|
重写call
在重写call前,我需要知道一个知识:
谁调用这个函数,这个函数内的this就指向谁
上述的 test 函数,默认是window调用它的,所以 test函数的this就指向 window
代码实现
1 2 3 4 5 6 7 8 9 10 11 12 13
| Function.prototype.myCall = function (context) { context = context ? Object(context) : window; let uniqueKey = new Date().getTime().toString(); context[uniqueKey] = this; let args = []; for (let i = 1; i < arguments.length; i++) { args.push('arguments[' + i + ']'); }
const result = eval('context[uniqueKey](' + args + ')'); delete context[uniqueKey]; return result; };
|
重写 apply
它和 call 的区别就在于第二个参数是数组.
但还是需要注意一下:
- apply 的 第二个参数接收 数组
- apply 只取到第二个参数,从第三个参数开始到最后直接被忽略
- apply 的 第二个参数,如果是 object/funciton/null/undefined ,那么 arguments.length 直接为 0
- apply 的 第二个参数, 如果是 number/string/boolean,会报错
代码实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| Function.prototype.myApply = function (context, args) { context = context ? Object(context) : window; let uniqueKey = new Date().getTime().toString(); context[uniqueKey] = this; if (typeof args === 'number' || typeof args === 'string' || typeof args === 'boolean') { throw new TypeError('CreateListFromArrayLike called on non-object'); } if (!args || Array.isArray(args) === false) { return context[uniqueKey](); }
let result = context[uniqueKey](...args); delete context[uniqueKey]; return result; };
|
重写bind
写之前,先看一看bind都有哪些特点:(假设有一个 函数 test)
- 使用 bind() 时,test 不会执行,而是返回一个新的函数
- bind 的第一个参数和 call,apply 一样的特点
- bind 可以分离 text 的参数 (函数柯里化)
- bind 可以接收一部分参数,返回的新函数也可以接收一部分参数
- 返回的新函数可以作为构造函数,而this指向的是 test 构造出来的实例
根据以上特点来实现一下
代码实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| Function.prototype.myBind = function (context) { let _this = this, args = [].slice.call(arguments, 1), _tempFn = function () {}; let newFn = function () { let newArgs = [].slice.call(arguments); return _this.apply(this instanceof newFn ? this : context, args.concat(newArgs)); }; _tempFn.prototype = this.prototype; newFn.prototype = new _tempFn(); return newFn; };
|