new,blind,call,apply实现 发表于 2020-05-12 | 分类于 前端 , 自省系列 , JS new实现 创建一个对象 将构造函数的作用域赋给新对象 给新对象添加属性 返回新对象 123456789101112131415161718/** * 1.创建一个空对象 * 2.改变this的指向 * 3.给新对象新增属性 * 4.返回新对象 */function MyNew() { //创建一个空对象 let newObj = {}, //获取传入的构造函数 targetConstructor = [].shift.call(arguments); //实例继承 通过create 可以避免newObj和targetConstructor共享引用 newObj = Object.create(targetConstructor.prototype); //借用外部传入的构造器给obj设置属性 const ret = targetConstructor.apply(newObj, arguments); //避免null的情况返回 return typeof ret === "object" ? ret || newObj : newObj;} call 将函数设为对象的属性 执行该函数 从对象上删除该函数 1234567891011121314151617/** * 1. 将函数设置为对象的属性 * 2. 执行该对象上新增的函数 * 3. 删除该属性 */Function.prototype.myCall = function (context = window) { context.fn = this; const args = []; for (let i = 1, len = arguments.length; i < len; i++) { //执行后 args为 ["arguments[1]", "arguments[2]", "arguments[3]"] args.push("arguments[" + i + "]"); } //eval()中的参数必须为字符串,才会计算成JS代码 const result = eval("context.fn(" + args + ")"); delete context.fn; return result;}; apply123456789101112131415161718/** * * apply和call区别在于第二个参数格式不同 */Function.prototype.myApply = function (context = window, arr) { context.fn = this; let result; if (!arr) { result = context.fn(); } else { for (let i = 0, len = arr.length; i < len; i++) { args.push("arr[" + i + "]"); } result = eval("context.fn(" + args + ")"); } delete context.fn; return result;}; bind bind() 方法会创建一个新函数。当这个新函数被调用时,bind() 的第一个参数将作为它运行时的 this,之后的一序列参数将会在传递的实参前传入作为它的参数。(来自于 MDN ) 传入一个绑定的对象和参数 返回一个函数 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748/** * 1. 传入一个对象和参数 * 2. 更改this的指向到调用的函数上,如果是new绑定的,则绑定到实例化的对象上 */Function.prototype.myBind = function (context) { //调用bind的函数 const self = this; //调用bind时传入的参数 const argument = [].slice.call(arguments, 1); let fBind = function () { //调用函数时或实例化时传入的参数 const args = [].slice.call(arguments); // 作为构造函数时,this不能再指向context 此处的this指向实例 // 如果不是当做构造函数,那么将调用bind的函数指向context self.apply(this instanceof fBind ? this : context, argument.concat(args)); }; // 将函数fBind的prototype指向调用bind的函数,这样就可以继承到绑定函数原型中的值 const fNOP = function () {}; fNOP.prototype = this.prototype; fBind.prototype = new fNOP(); return fBind;};var foo = { value: 1,};function bar(name, age) { this.habit = "shopping"; console.log(this.value, "实例化的时候,无法获取到该值"); console.log(name); console.log(age);}// 此处为原型上的属性,如果没有更改绑定函数的prototype的话,无法获取到该值bar.prototype.friend = "kevin";var bindFoo = bar.myBind(foo, "daisy");const obj = new bindFoo("18");console.log(obj.friend);console.log(obj.habit);//undefined 实例化的时候,无法获取到该值//daisy//18//kevin//shopping 参考资料再此感谢冴羽大佬的深入系列