遇事不决看源码

tech2024-07-10  70

js常用源码实现

简介实现一个new源码实现Object.create实现instanceofbind实现call实现apply实现结束语

简介

手撕常用源码为面试中必备的技能,欢迎各位大佬一起探讨指正~

实现一个new源码

首先了解new对实例化构造函数时内部实现了啥:

创建一个控对象将构造函数的原型对象添加到这个对象的隐形属性__proto__执行构造函数当函数返回对象的时候,返回对象当函数返回非对象的时候返回这个ob j

具体代码实现逻辑如下

// es5写法 function newp(Con,...args){ const obj = Object.create(Con.prototype); const res = Con.apply(obj, args) return res instanceof Object ? res : obj } // es3 function newP(){ const obj = new Object(); const args = Array.prototype.slice.call(arguments, 1); const Con = Array.prototype.shift.call(arguments); obj.__proto__ = Con.prototype; const res = Con.apply(obj, args); return res instanceof Object ? res : obj; }

实现Object.create

上面new的例子在es5的写法中用到了Object.create的写法,因此我们了解到Object.create的作用是创建一个新对象,使用现有的对象作为新创建对象的prototype。:

先生成一个空对象将传入的对象添加到这个对象的隐形属性__proto__中最后的生成的对象的原型对象的constructor属性要指向创建的对象

具体代码实现逻辑如下

function create(object){ const obj = new Object(); obj.__prototype = object; obj.__prototype.constructor = obj; return obj }

实现instanceof

学习过原型链的都知道判断一个对象是否在某个原型链上,以及判别引用类型的方法不能用typeof, 而是instanceof 那么手撕一波:

// 1. 检测构造函数的 prototype 属性是否出现在某个实例对象的原型链 // 2. Object.getPrototypeOf(obj(要返回其原型的对象)) 方法返回指定对象的原型(内部[[Prototype]]属性的值)。 // 3. 返回值:给定对象的原型。L.__proto__.__proto__ 直到 proto 为 null,则返回 null 。 // 4. 函数中的while(true){return} 不会无限循环,当出发return结束循环 function instanceofP(L, R){ if(typeof(L) !== 'object'){ return false } let l = L.getPrototypeOf(L); const r = R.prototype; while(l !== null){ if(l === r){ return true } l = l.getPrototypeOf(l) } }

bind实现

bind做了啥

bind是Function原型链中的Function.prototype的一个属性,它是一个函数,修改this指向,合并参数传递给原函数,返回值是一个新的函数。bind返回的函数, 可以通过new调用,返回原函数的实例,但是不改变this指向指向了new生成的全新对象。内部模拟实现了new操作符。 /* eslint-disable no-extend-native */ Function.prototype.bind3 = function () { if (!(this instanceof Function)) { throw new Error('is not a function'); } const func = this; const args = Array.prototype.slice.call(arguments, 1); const Content = Array.prototype.shift.call(arguments); return function F() { const argp = Array.prototype.slice.call(arguments); const Arg = args.concat(argp); const selfp = this; // this instanceof f 正常情况下这种情况返回的是纯粹函数,this指向的是全局当用new时this指向的时F, 否则指向的原来的构造函数的原型对象 if (selfp.__proto__ === F.prototype) { return new func(...Arg); } return func.apply(Content, Arg); }; };

call实现

call() 方法使用一个指定的 this 值和单独给出的一个或多个参数来调用一个函数。这是也是利用函数this指向对象的套路同apply

// 参数你也可以指定(self, ... agrs)我这里用arguments只是单纯为了装b Function.prototype.callp = function () { // 这里还是我想玩一下原型链的骚操作 // 可以用!(this.instanceof Function),或者typeof(this) === 'function if (this.__proto__ !== Function.prototype) { throw new Error('is not function'); } const args = Array.prototype.slice.call(arguments, 1); const content = this; // 为什么用shift, 问就是为了装b const self = Array.prototype.shift.call(arguments) || {}; self.fuc = content; const res = self.fuc(...args); // 这里一定要记的删掉this中添加的函数属性 delete self.fuc; return res; };

apply实现

apply() 方法调用一个具有给定this值的函数,以及以一个数组(或类数组对象)提供的参数, 返回修改this指向的函数结果, 利用this指向(obj)特性实现apply源码

/* eslint-disable no-extend-native */ // apply改变函数this指向, 返回改变指向的函数的结果 Function.prototype.applyp = function (self, args) { if (!(this instanceof Function)) { throw new Error('is not function'); } const content = this; const selfp = self || {}; selfp.content = content; const res = self.content(...args); // 一定要将添加到修改函数this指向中的函数去掉 delete self.content; return res; };

结束语

如果各位大佬觉得还不错请给个素质3连,欢迎各位大佬提出更好的写法~

最新回复(0)