js的原型系统中,有三个很重要的属性,constructor,proto,prototype,做了一张图,梳理一下它们之间的关系。
javascipt中的数据类型分为原始类型和对象类型。
原始类型包括
- 字符串
- 数字
- 布尔值
- undefined
- null
除了这五种,其余的都是对象类型了。对象类型中包含一个特殊的类型 —— 函数。 而通过构造函数又可以生成对象。
原始类型与对象类型的联系
在读写字符串,数字,布尔值的时候,它们都是原始值,既然如此,它们就不应该有属性和方法,但事实却并非如此。
var x = 'abcde';
var y = x.substring(2); // cde
这里x是一个原始类型,但是它确可以调用方法。why? 这是因为为了方便操作原始类型,js中引入了包装对象。 它可以通过String(), Number(), Boolean()这三个构造函数显式的创建 在操作一个原始类型的时候,js会默默地调用上面三个构造函数,产生一个包装对象,然后它会从原型上继承一些方法,一旦操作完成,这个包装对象就会被销毁。拿上面的例子来说 **var y = x.substring(2);**相当于
var temp = new String('abcde');
var y = temp.substring(2);
关键属性
- constructor指向对象实例的构造函数
__proto__
以前是一个没有标准化的属性,但是在ECMAScript 2015里已经标准化了,各大现代浏览器也支持,它指向对象的原型对象- prototype 这个属性只有函数才有,当一个构造函数实例化了一个对象以后,这个对象的原型就是由这个构造函数的prototype
系统
原始类型
原始类型不是对象,所以它不会有属性和方法,但是按照前文提到过的包装对象,我们可以像操作对象一样去操作原始类型,除了undefined和null这两者不能创造包装对象,其余原始类型的原型链结构差不多。
- 字符串
constructor -> String()__proto__
-> String.prototype
没有prototype - 数字
constructor -> Number()
__proto__
-> Number.prototype
没有prototype - 布尔值
constructor -> Boolean()
__proto__
-> Boolean.prototype
没有prototype
函数
使用new Function()来定义的函数:
显而易见,这种函数的constructor就是它
使用变量赋值或者关键字定义的函数
看起来这种函数并没有构造函数,但它情况与原始值会创建包装对象是一样的,js会使用new Function()隐式的生成一个包装对象,所以这种函数的constructor也是Function ();
这两者的prototype对象不同,但是 __proto__
是一样的,并且都指向Function的prototype
对象
构造函数生成的对象
它的constructor是这个构造函数,它没有prototype,他的__proto__
指向构造函数的prototype
字面量生成的对象
由于隐式调用了new Object(),所以它constructor是Object(),它的__proto__
是Object.prototype
function man (name, age) {
this.name = name;
this.age = age;
}
var person1 = new man('peter', 22);
var person2 = {
name: 'tim',
age: 33
}
person1.constructor // function man (name, age) {...}
person2.constructor // function Object() {...}
内置构造函数
Function 是一个特例
Function ()的constructor是它本身
他的__proto__
和prototype相同,并且都指向一个匿名函数,这个函数的表现在不同的浏览器内核下不同
这里匿名函数的的__proto__
指向了Object.prototype
Object也是一个特例
它的constructor是Function,因为本质上它也是个函数
它的prototype是一个特殊的原型对象,这个原型对象的__proto__
是null
它的的__proto__
和Function一样
其他的几个内置构造函数的constructor是Function(), __proto__
是Function的prototype,也就是说都是那个匿名函数