Function.prototype.myBind = function (context, ...args) {
if (!context || context === null) {
context = window;
}
// 创造唯一的key值 作为我们构造的context内部方法名
let fn = Symbol();
context[fn] = this;
let _this = this;
// bind情况要复杂一点
const result = function (...innerArgs) {
//进入里面后 这里的this和外面的this不一样了,现在是指向new result的this
//this是通过result构造函数生成的一个实例对象,不是一个函数,所以可以this instanceof _this
//而_this是Person这个构造函数对象
// 第一种情况 :若是将 bind 绑定之后的函数当作构造函数,通过 new 操作符使用,则不绑定传入的 this,而是将 this 指向实例化出来的对象
// 此时由于new操作符作用 this指向result实例对象 而result又继承自传入的_this 根据原型链知识可得出以下结论
// this.__proto__ === result.prototype //this instanceof result =>true
// this.__proto__.__proto__ === result.prototype.__proto__ === _this.prototype; //this instanceof _this =>true
if (this instanceof _this === true) {
// 此时this指向指向result的实例 这时候不需要改变this指向
this[fn] = _this; //result 得到person构造方法
//这里的...args还用到了闭包!!所以返回后还存在不会消失
//得到一个函数 等着输入innerages就可以和args结合去干事了
this[fn](...[...args, ...innerArgs]); //这里使用es6的方法让bind支持参数合并
delete this[fn];
} else {
// 如果只是作为普通函数调用 那就很简单了
// 直接改变this指向为传入的context
//执行
context[fn](...[...args, ...innerArgs]);
delete context[fn];
}
};
//上面的result返回了,但是100行存参不执行(闭包),这里下面的这句执行了,为
//if (this instanceof _this === true)做了铺垫了
// 如果绑定的是构造函数 那么需要继承构造函数原型属性和方法
// 实现继承的方式: 使用Object.create
result.prototype = Object.create(this.prototype);//this是person的
//右边创了一个原型对象实例
//实现继承 (其实就是new Person())
//这样后,result构造函数指向的原型对象t,t的_proto_就是Person构造函数的原型对象
//通过result new 出来的_proto_指向了t
//所以instanceof里可以找到用result new出来的
function instanceOf(left, right) {
let proto = left.__proto__
while (true) {
if (proto === null) return false
if (proto === right.prototype) {
return true
}
proto = proto.__proto__
}
}
return result;
};
//用法如下
function Person(name, age) {
console.log(name); //'我是参数传进来的name'
console.log(age); //'我是参数传进来的age'
console.log(this); //构造函数this指向实例对象
}
// 构造函数原型的方法
Person.prototype.say = function () {
console.log(123);
}
let obj = {
objName: '我是obj传进来的name',
objAge: '我是obj传进来的age'
}
// 普通函数
function normalFun(name, age) {
console.log(name); //'我是参数传进来的name'
console.log(age); //'我是参数传进来的age'
console.log(this); //普通函数this指向绑定bind的第一个参数 也就是例子中的obj
console.log(this.objName); //'我是obj传进来的name'
console.log(this.objAge); //'我是obj传进来的age'
}
// 先测试作为构造函数调用
// let bindFun = Person.myBind(obj, '我是参数传进来的name')
//到上面这一步还不能确定是构造函数,到下面的result才会得到那些instanceof信息
//只能得到一个函数展开就是那样的,没调用呢,把参数存进去而已,得到一个有参数的函数
//对象
//返回的是一个obj去调用的Person构造函数
// let a = new bindFun('我是参数传进来的age')//function (...innerArgs)
// a.say() //123
// 再测试作为普通函数调用
let bindFun = normalFun.myBind(obj, '我是参数传进来的name');
//生成一个函数bindFun
// 两个参数得去合并啊
bindFun('我是参数传进来的age');
手写js系列之 bind 看不懂注解打死我
最新推荐文章于 2024-03-29 11:39:08 发布