老生常谈的问题:原型是什么
几乎每个JavaScript对象都有另一个与之关联的对象。
这另一个对象被称为原型(prototype),第一个对象从这个原型继承属性。
1.通过对象字面量创建的所有对象都有相同的原型对象使用Object.prototype
作为其原型
对象和数组初始化程序也是一种表达式,其值为新创建的对象或数组。这些初始化程序表达式有时候也被称为对象字面量和数组字面量。
let hsiao =[1,2,3] //数组初始化程序
let hsiao2 = {x:2 , y:3} //对象初始化程序
我们可以通过控制台调试,发现有这个[[Prototype]]
,而他的值
和Object.prototype
,就是同一个东西
2.使用new关键字和构造函数调用创建的对象,使用构造函数prototype
属性的值作为它们的原型。
换句话说,使用new Object()
创建的对象继承自Object.prototype
,与通过{}
创建的对象一样。
类似地,通过new Array()
创建的对象以Array.prototype
为原型,通过new Date()
创建的对象以Date.prototype
为原型。
引出原型链
对于我这种JavaScript初学者,这一块很容易迷惑。
几乎所有对象都有原型,但只有少数对象有prototype
属性。正是这些有prototype
属性的对象为所有其他对象定义了原型。
(用人话来说:这些少数对象作为小boss的
prototype
拿来共享给别的对象用)
Object.prototype
是为数不多的没有原型的对象,因为它不继承任何属性。
(用人话来说:它是最大BOSS)
很好理解吖:其他的原型对象都是都是常规对象,由它而来的,所以才有自己的原型Object.prototype
//比如我简单创建一个a空数组
let hsiao =new Array()
console.log(hsiao)
//控制台得到的结果
[]
//打开数组
length:0
[[prototype:Array(0)]]
//打开[[prototype:Array(0)]]
at: ƒ at()
concat: ƒ concat()
...
[[Prototype]]: Object
//打开 [[Prototype]]: Object
...
//没有出现下一个[[Prototype]]
代码没法全部展现这个“链子”,画个图更直观一点
多数内置构造函数(和多数用户定义的构造函数)的原型都继承自Object.prototype
。例如,Date.prototype
从Object.prototype
继承属性,因此通过new Date()
创建的日期对象从Date.prototype
和Object.prototype
继承属性。
这种原型对象链接起来的序列(套娃)被称为原型链。
浅尝原型链
-
instanceof
操作符:期待左侧操作数是对象,右侧操作数是对象类的标识。这个操作符在左侧对象是右侧类的实例时求值为true
,否则求值为false
。所以我们可以利用这个特性来加深一下对原型链的理解。let hsiao = new Date() //用D构造函数创建一个新对象 hsiao instanceof Date //true hsiao instanceof Object //true hsiao instanceof Math //false
如果
instanceof
的左侧操作数不是对象,它会返回false
。如果右侧操作数不是对象的类,它会抛出TypeError
。 -
要确定一个对象是不是另一个对象的原型(或原型链中的一环),可以使用
isPrototypeOf()
方法:let p = {x:1}//定义一个原型对象 let o = Object.create(p) //用该原型创建一个对象 p.isPrototypeOf(o) //true o继承p Object.prototype.isPrototypeOf(p) //true p继承Object.prototype Object.prototype.isPrototypeOf(o) //true o继承Object.prototype
总结
原型和原型链没有想象中那么简单,但也不会很复杂。
重要是理清楚其中的prototype
,[[prototype]]
,__proto__
之间到底有什么关系,举个最简单的例子:
-
对象test 的构造函数Test有个自己的属性
prototype
-
对象test 本身有个属性
__proto__
或者叫[[prototype]]
-
两者相同
利用这层关系将上一级的属性归下一级的对象所用,这才能发挥原型链的作用。