JS中new到底发生了什么
outline
prototype
与__proto__
function
与object
new
到底发生了什么
prototype
与__proto__
首先说下在JS中比较容易让人困惑的prototype
和__proto__
__proto__
就是JavaScript中所谓的原型.
一个对象的
__proto__
属性和自己的内部属性[[Prototype]]指向一个相同的值 (通常称这个值为原型),原型的值可以是一个对象值也可以是null(比如说Object.prototype.__proto__
的值就是null).该属性可能会引发一些错误,因为用户可能会不知道该属性的特殊性,而给它赋值,从而改变了这个对象的原型. 如果需要访问一个对象的原型,应该使用方法Object.getPrototypeOf.
firefox、chrome等浏览器把对象内部属性[[Prototype]]用__proto__
的形式暴露了出来.(老版本的IE并不支持__proto__
,IE11中已经加上了__proto__
属性)
prototype
是function中特有的.什么意思呢?举个例子:1
2
3
4function A(name){
this.name = name;
}
console.dir(A);
我们得到如下结果:
首先看A是一个函数,自然A的原型链就应该指向一个函数对象.
其次我们还看到当我们定义了function A的时候,A上会有一个prototype
的属性.这个属性是我们定义function的时候就默认带上的.A的prototype
指向一个对象,这个对象的包含一个constructor
属性以及一个__proto__
(__proto__
指向Object表示这是一个对象).默认的constructor属性指向function A.
看起来有点混乱是不?这边只要记住一点:__proto__
是原型,prototype是函数默认的一个属性,它指向一个对象,这个对象的constructor属性指向函数本身.
function与object
首先看一个例子1
2
3
4
5
6
7
8
9
10
11
12function A(name){
this.name = name;
this.getName = function(){
console.log(this.name);
}
var b = 'test';
console.log(b);
}
var a = new A('testa');
A('TESTA');
当执行var a = new A('testa');
得到的a是这样的:
而我们执行A('TESTA');
相当于:1
2//window.name = 'TESTA'(由于非strict模式下,this默认指向window)
//window.getName = function(){console.log(this.name);}
我们的函数A既可以直接执行,又可以new一下返回一个对象.function和object到底是什么关系,new的时候发生了什么?
new到底发生了什么
还是我们上面的问题,当我们执行var a = new A('testa')
到底发生了什么.MDN上是这么说的
对于var o = new Foo();
1
2
3
4//JavaScript 实际上执行的是:
var o = new Object();
o.[[Prototype]] = Foo.prototype;
Foo.call(o);
这样大概就明白了,当我们执行new A('testa')
的时候
JS会这样做
- var o = new Object();
- o.
__proto__
= A.prototype;//这里还记得之那个function里面的默认的属性么? - A.call(o)//由于这里this是指向o,可以把什么this.name/getName绑定到o上.
- 把这个o返回给a;//完成var a = new A()的过程.
这里注意下,上面所谓的第4步其实是一个简化的说法.真正的过程是在第3步之后,如果发现A返回是一个Object类型(非primitive类型,即非string,boolean,number,null,undefined类型就是Object类型),则直接返回A的返回值,否则把第1步new的Object返回出去.(默认情况下,JS中函数默认返回值是undefined)
举个例子
1 | function A(name){ |
这里我们把A函数的返回值设置为一个Object类型,则这个时候执行new A返回的就是A函数的返回值{}.如果我们把A的返回值设置为return [];那么我们在new A的时候也相应的得到一个空数组.
用stackoverflow上一个人的回答来总结下就是:
In JavaScript, most functions are both callable and instantiable: they have both a [[Call]] and [[Construct]] internal methods.
在JS中,绝大多数的函数都是既可以调用也可以实例化的.我们既可以直接执行函数得到函数的返回值.也可以通过new操作符得到一个对象.