在JavaScript中,如果我们声明一个变量var a = 1
与var b = new Number(1)
是不一样的,前者会将变量a直接存放在stack(栈)内存中,而后者是在stack中建立一个引用,引用的是heap(堆)内存中的对象,该对象拥有两个key:
Number {1}
__proto__: Number
[[PrimitiveValue]]: 1
其中key:PrimitiveValue的值就是number的值1,今天就重点总结一下对象的另一个key:__proto__
。
1.原型
如果我们用new的方式创建对象,一般有下面四种数据类型:
1.Number
var n = new Number(1) 创建一个 Number 对象
2.String
var s = new String('hello') 创建一个 String 对象
3.Boolean
var b = new Boolean(true) 创建一个 Boolean 对象
4.Object
var o1 = {}
var o2 = new Object()
o1 和 o2 没区别
创建数据之后,以对象n为例,对象n会拥有诸多方法:
比如:toString()、toFixed()。
对象n怎么拥有这些方法的呢?
重点就是
__proto__
这个属性,每当我们使用new
语法的时候,对象就会拥有__proto__
这个属性,该属性会指向new之后对应函数(也就是Number)的prototype属性,这个属性是Number共有属性,该共有属性会拥有诸多共有方法,也就是说:
n.__proto__ === Number.prototype
// true
2.原型的原型
仍然以对象n为例,如果对象n的方法在共有的Number属性中找不到,怎么办呢?那么会继续向上一层去寻找,就像数据结构一样。也就是说会向Number.prototype.__proto__
中继续寻找,该对象对应的就是另一个对象:Object.prototype。
如果还找不到再继续向上一层找呢?那么就是
Object.prototype.__proto__
,它的值为null,也就是在JS的数据结构中,这是顶层了。3.原型链与总结
用一个简答的内存图作为总结:
只要是使用new方法得到的对象,不管是string还是Number或者Boolean,这三种数据类型都有其函数对应的prototype方法,而他们三种数据的prototype方法的上一层(
prototype.__proto__
)就是object对象的prototype方法。如上图所示。简单总结为一句代码就是:
var 对象 = new 函数()
对象.__proto__ === 函数.prototype
而.__proto一层一层的指向就可以被称为原型链。
由此也可以引出以下几个推论:
// 推论
var number = new Number()
number.__proto__ = Number.prototype
Number.__proto__ = Function.prototype // 因为 Number 是 Function 的实例
var object = new Object()
object.__proto__ = Object.prototype
Object.__proto__ = Function.prototype // 因为 Object 是 Function 的实例
var function = new Function()
function.__proto__ = Function.prototype
Function.__proto__ == Function.prototye // 因为 Function 是 Function 的实例!
参考链接:
1.JavaScript深入之从原型到原型链
2.写代码啦