new的原理

54 阅读3分钟

原型链

首先需要讲一下原型链:全局变量分为两种:

一种是 ECMAScript 规定的,比如:global.parseInt,global.parseFloat,global.Number

一种是浏览器自己加的属性,比如:window.alert,window.prompt,window.comfirm

所有 API 都可以在 MDN 里找到详细的资料。这里我主要说的是第一种。

每当我们建一个新的对象时,我们似乎总是能用一大堆原先并没有定义的方法,这是为啥呢?因为有原型这个神奇的东西存在,每当我们申明的时候,他就会自动建立一个__proto__属性与所对应的方法的原型相连,这样我们就共用了原型的方法

image.png 简单的来说,我们要搞清楚原型链的架构,首先就要明白js的内置方法如何被构建起来的,由于js的垃圾回收机制,当一个对象未被引用的时候,就会被视作垃圾,于是就会被清除,但是我们发现Number,String这些方法都没有被清除,这就让人啧啧称奇了。这其实就是在每个对象内部加上了一个prototype属性,叫做该对象的原型属性,又给每个对象加上__proto__,叫做原型链指针,他指向本对象的原型对象,用这种方法使得每个对象相互连接。每当我们声明一个对象时,它就会去找到他所对应的方法的原型,然后予以连接,这也就能在建立一个对象以后,他能拥有许多你本身并没有定义的方法的原因,如图:

image.png 此时,我声明了变量a,但是我并没有给a定义方法,但我toString却没有错,就是因为我的__proto__属性已经有了这个方法,所以不报错。

那么每个对象的原型链指针(__proto__)指向谁呢?内置对象的原型对象指向Function的原型,包括内置对象Function自己的,如图:

image.png 但是,内置对象的原型对象(Function.prototype)的原型对象是谁呢?因为他本身就是个对象啊,于是他就指向对象的原型对象,于是

image.png 也就是说,我们以后看见一个兑现,就判断他是属于啥方法,接着就归到啥方法的原型中去就好了

给出公式:

Object.__proto__ === 对应方法的原型.prototype;

再举一个例子,还是那个空对象a,a的原型链指向应该是Object的原型,因为他就是Object方法构造出来的,而a.__proto__.__proto__(a的原型的原型链指向)就应该是null,因为他就是object.prototype.__proto__,值为null

image.png 以上就是我对原型链的全部理解。

new

使用new命令时,js做了以下事情:
1.创建了一个空对象,作为要返回的对象
2.将空对象的__proto__指向了构造函数的prototype,这样就有了构造函数的方法
3.将空对象的地址值赋值为构造函数内部的this
4.开始执行赋值构造函数内部的代码
以下是new实现的基本代码:

function _new(/* 构造函数 */ constructor, /* 构造函数参数 */ params) {
  // 将 arguments 对象转为数组
  var args = [].slice.call(arguments);
  // 取出构造函数
  var constructor = args.shift();
  // 创建一个空对象,继承构造函数的 prototype 属性
  var context = Object.create(constructor.prototype);
  // 执行构造函数
  var result = constructor.apply(context, args);
  // 如果返回结果是对象,就直接返回,否则返回 context 对象
  return (typeof result === 'object' && result != null) ? result : context;
}

这就是new的原理和实现思路