new和instanceof的内部机制

关于newinstanceof的内部机制

1.创建一个新对象,同时继承对象类的原型。,即Person.prototype

2.执行对象类的构造函数,同时该实例的属性和方法被this所引用,即this指向新构造的实例

3.如果构造函数return了一个新的’对象’,那么这个对象就会取代整个new出来的结果。如果构造函数没有return对象,那么就会返回步骤1所创建的对象,即隐式返回this。(一般情况下构造函数不会返回任何值)

Code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
function Person(name) {
this.name = name
}

// let p = new Person()
let p = (function() {
let obj = {}
obj.__proto__ = Person.prototype

// 其他赋值语句

return obj
})();

// or
function create() {
// 创建一个空的对象(准确的来说是克隆了Object.prototype对象)
let obj = new Object()
// 获得构造函数,赋值给变量Con
let Con = [].shift.call(arguments)
// 链接到原型
obj.__proto__ = Con.prototype
// 绑定this,执行构造函数
let result = Con.apply(obj, arguments)
// 确保new出来的是一个对象
return typeof result === 'object' ? result : obj
}

img

  • Object是所有对象的爸爸,所有的对象都可以通过__proto__找到它
  • Function是所有函数的爸爸,所有函数都可以通过__proto__找到它
  • Function.prototypeObject.prototype是两个特殊的对象,他们由引擎来创建
  • 除了以上的两个对象,其他所有的对象都是通过构造器new出来的
  • 函数的prototype是一个对象,也就是原型
  • 对象的__proto__指向原型,__proto__将对象和原型连接起来组成了原型链

下面代码阐述instanceof的内部机制,假设现在有x instanceof y的一条语句,其内部实际上做了如下判断:

来自MDN的instanceof的解释

instanceof运算符用于测试构造函数的prototype属性是否出现在对象的原型链中的任何位置

1
2
3
4
5
6
7
8
9
10
11
function instance_of(L, R) {
var O = R.prototype
L = L.__proto__
while (true) {
if (L === null)
return false
if (L === O)
return true
L = L.__proto__
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
function Rocker(name){
this.name = name;
};
Rocker.prototype.getName = function(){
return this.name;
}

var createObject = function(){
var obj = new Object(), //(1)
Constructor = [].shift.call(arguments); //(2)取出了`arguments`里面的第一项,也就是第一个参数`createObject(父类)`,此时父类就是第一个参数
obj.__proto__ = Constructor.prototype; //(3)
var ret = Constructor.apply(obj, arguments); //(4)
return typeof ret === 'object' ? ret : obj; //(5)
};
var Freak = createObject(Rocker, 'Freak');
console.log(Freak.name); //Freak
console.log(Freak.getName()); //Freak
console.log(Object.getPrototypeOf(Freak) === Rocker.prototype); //true

// 地址
https://rockjins.js.org/2017/01/18/2017-01-18-new-object/

(1)处,我们创建了一个空对象(准确的说是克隆了Object.prototype对象)

(2)处取到构造函数,赋值给Constructor变量(通过[].shift.call(arguments)arguments对象转换为数组),也就是说Rocker构造函数变为Constructor的一个引用了

(3)将Constructor.prototype(也就是Rocker.prototype)赋值给刚刚创建的obj的原型链,或者说obj的原型链指向Constructor的原型

(4)我们用apply来改变this的指向,用obj代替Constructor构造函数内部的this,并把arguments作为参数传入(在第2步时已经用shift把第一个参数去除了),此时的ret已经是一个合格的实例了!)

(5)返回时判断ret是否是对象,如果不是就返回一个空对象

来自MDN上的解释:

prototype是用于类的(Person),而Object.getPropertyOf()是作用于实例的(instances),两者的功能一致。

1
function Foo () {}

因此当执行var o = new Foo()

JavaScript实际执行的是:

1
2
3
var o = new Object()
0.__proto__ = Foo.prototype
Foo.call(o)
0%