js只有函数对象具备类的概念,要创建对象,必须使用函数对象,函数对象内部的[[constructor]]
用于构造对象,[[call]]
用于调用对象。
1. var obj = new Object()
使用内置的Object函数实例化对象。
2. var obj = {}
或者var obj = []
使用js引擎触发Object和Array的构造过程。
3. function fn() {};var obj = new fn{}
使用用户自定义类型实例化对象。
new创建的对象和函数的prototype对象之间存在继承关系
function A(){
this.a = 'a in A func';
};
A.prototype.b = 'b in A prototype';
var i = new A();
i.b;//'b in A prototype';
i instanceof A;//true;
A.prototype = {};
i.b;//'b in A prototype';
i instanceof A;//false;
i.__proto__;
// {b: "b in A prototype", constructor: ƒ}
从上面代码看出,将A
的prototype
置为{}
空对象后,i instanceof A;
返回false,可见继承关系是通过prototype
实现的。
由于new
创建对象时将构造函数的prototype
属性赋值给实例的__proto__
属性,因此__proto__
属性和prototype
指向同一引用,如果将prototype
同对象字面量方式赋值为其他对象的话,则切断了__proto__
和prototype
之间的联系,因为prototype
和其最初的引用之间没有关系了,这里考虑引用类型的存储即可明白,__proto__
依旧指向之前prototype
的引用,所以__proto__
属性上存在的属性不会消失。
将A
的prototype
置为{}
空对象后对A
的实例i来说,i
的隐式__proto__
属性并未改变,即i被实例化后__proto__
不受prototype
的影响,相当于实例化后,通过父类prototype
继承来的属性和方法都会保存在自身的__proto__
属性上,与父类没有关系,因此也不能通过实例更改父类原型上的方法。如下:
i.b = 123
//123
i.__proto__.b
//"b in A prototype"
Object
,Function
,Number
,String
,等的构造器constructor
都是Function
,实例对象的构造器会从原型链上继承自父类。
Number.constructor === Function;//true
Number.__proto__ === Function.prototype;//true
Function
是最顶层的构造器,他具有自举性,
typeof Function.prototype;//"function"
Function.constructor === Function;//true
Function.__proto__ === Function.prototype;//true
所有函数的__proto__
属性都指向Function.prototype,Function
的__proto__
也指向Function.prototype
,
function A(){}
A.__proto__ === Function.prototype
//true
Function.__proto__ === Function.prototype;//true