/** * call实现 * 实现原理:方法内部的this一般在调用时确定,将fn赋值给thisArg的一个方法, * 然后执行,之后再将thisArg上的fn删除,最后返回结果 * apply与此相似 */// fn.call(thisArg, 其他参数)Function.prototype.myCall = function () { // 判断拥有myCall的方法是不是函数 if (typeof this !== 'function') { throw new TypeError(`${this} is not a function`) } const args = [...arguments] const thisArg = args.shift() || window // 方法内部的this指向在方法调用时确定,指向方法所属的对象thisArg thisArg.fn = this const result = thisArg.fn(...args) // 删除fn delete thisArg.fn return result}/** * aplly实现 */Function.prototype.myApply = function () { // 判断拥有myApply的方法是不是函数 if (typeof this !== 'function') { throw new TypeError(`${this} is not a function`) } const args = [...arguments] const thisArg = args.shift() || window // 方法内部的this指向在方法调用时确定,指向方法所属的对象thisArg thisArg.fn = this const result = thisArg.fn(...args[0]) // 删除fn delete thisArg.fn return result}/** * bind实现 * 注意:bind最终返回一个函数,作为构造函数使用new调用时,不应该改变this指向, * 因为new绑定优先级高于显示绑定和硬绑定, * new > 显示绑定 > 隐式绑定 > 默认绑定 * * 实现原理:bind实现依赖于call或者apply,绑定过程分三个步骤 * 1、返回一个函数 * 2、参数绑定 * 3、使用new * */// 效果function foo(x, y) { console.log(this) this.x = x this.y = y}const obj = { props: '007'}const bindFoo = foo.bind(obj, 'hello')foo(1, 2) // windowbindFoo('world') // objnew bindFoo('newWorld')// 解释:// a步骤:const bindFoo = foo.bind(obj)相当于指定foo内部的this为obj,并返回一个函数// b步骤:new bindFoo(),因为new的优先级高于aplly,所以a步骤绑定的this失效,this现在指向new创建的实例// 实现Function.prototype.myBind = function () { if (typeof this !== 'function') { throw new TypeError('Bind must be called on a function') } const args = [...arguments] const thisArg = args.shift() console.log('外层', args) const selfFn = this return function F(...innerArgs) { const concatArgs = [...args, ...arguments] console.log(this instanceof F) return this instanceof F ? new selfFn(...concatArgs) : selfFn.apply(thisArg, concatArgs) }}// 测试代码function foo(x, y) { this.x = x this.y = y}const obj = { props: '007'}const bindFoo = foo.myBind(obj, 'hello')foo(1, 2) // windowbindFoo('world') // objnew bindFoo('newWorld')