遇事不决看源码

js常用源码实现

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

简介

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

实现一个new源码

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

  1. 创建一个控对象
  2. 将构造函数的原型对象添加到这个对象的隐形属性__proto__
  3. 执行构造函数当函数返回对象的时候,返回对象
  4. 当函数返回非对象的时候返回这个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。:

  1. 先生成一个空对象
  2. 将传入的对象添加到这个对象的隐形属性__proto__中
  3. 最后的生成的对象的原型对象的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做了啥

  1. bind是Function原型链中的Function.prototype的一个属性,
  2. 它是一个函数,修改this指向,合并参数传递给原函数,返回值是一个新的函数。
  3. bind返回的函数, 可以通过new调用,返回原函数的实例,但是不改变this指向
  4. 指向了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连,欢迎各位大佬提出更好的写法~

你可能感兴趣的:(js,js,nodejs,javascript)