1.原型
- 原型:用来生产实例对象;在JS中原型就是prototype对象,用来表示类型之间的关系。
- 所有引用类型都有一个proto(隐式原型)属性,属性值是一个普通的对象.
- 所有函数都有一个prototype(原型)属性,属性值是一个普通的对象。
- 所有引用类型的proto属性指向它构造函数的prototype。
var a = [1,2,3];
a.__proto__ === Array.prototype
2. 原型链
-
原型链:JS中对象和对象之间是有联系的,通过prototype对象指向父类对象,在指向Object对象。而通过的方式就是_proto_连接,而_proto_最终指向null。
-
当访问一个对象的某个属性时,会先在这个对象本身属性上查找,如果没有找到,则会去它的proto隐式原型上查找,即它的构造函数的prototype,如果还没有找到就会再在构造函数的prototype的proto中查找,这样一层一层向上查找就会形成一个链式结构,我们称为原型链。
function Parent(month){
this.month = month;
}
var child = new Parent('Ann');
console.log(child.month); // Ann
console.log(child.father); // undefined
通过四个全局对象来了解原型和原型链
- 这四个全局对象为:Number()、String()、Boolean()、Object。
- 上述四个对象都可以通过下边两种方法实现:
var n1=1
var n2=new Number(1)
var s1='1'
var s2=new String('1')
var b1=true
var b2=new Boolean(true)
var o1={}
var o2=new Object
-
上述的两种方法区别在内存上的区别。 我们知道1.toString() 会报错,但是这里我们通过n1.toString() 返回的就是字符串 '1' 。n1.toString() 方法不会报错,但是n1只是通过赋值的方法的来的,并没有 .toString() 方法。这个时候就是JS通过创建临时对象var temp=new Number(1) 在这个临时对象中对n1的值进行 .toString() 方法,再将得到的返回给n1.toString() ,临时对象用完就自动抹杀。
-
还有一个例子,我们对n1进行n1.xxx=2这是也不会报错,就是用临时方法在heap内存上创建的,但是再取n1.xxx时为undefined。就验证了用完就抹杀,即不存在的原理。 为什么new Number() 有.toString() 方法呢?我们打印出n2看看他有没有这个属性。
5. 可以看到除了打印出n2的值还有一个proto:Number,点开这个属性可以看到萝莉了很多属性,其中就包括 .toString() ,所以n2可以调用 .toString() 方法。
- proto:Number所表示的就是number共有的属性。
7. 此时在图中我们看到n2.proto===Number.prototype的结果为true。就是指n2的proto指向了Number.prototype,即Number的共有属性中去,可以从第一张图中可以看到n2的proto中还有一个proto:Object的隐藏属性。点开就可以看到关于Object的共有属性。
8. 综上:我们可以总结出来,当我们new出来一个对象的时候,再去使用一个方法时,会首先从它自身的构造函数(或者系统自带函数)的原型对象(函数 .prototype)中去找,如果没有改属性是就会通过proto属性去下一个Object共有属性中去寻找,直到最后为null。可以画图理解为:
9. 上图中prototype对象就是原型,用过proto将他们连接就是原型链。
-
即:对象 .proto===函数.prototype其中proto是每个对象都有的一个属性,而prototype是函数才由的属性。 对象具有proto,可以成为隐式原型,一个对象的隐式原型指向该对象的构造函数的原型。 综上有:
var n = new Number(); n.__proto__===Number.prototype//true n.__proto__.__proto__===Object.prototype//true n.__proto__.__proto__.__proto__===null//true
- String()、Boolean() 同理,而Object则是比其他三种少了一个函数 .prototype环节。
- 易踩坑小知识
var f=false
var f1=new Boolean(false)
if(f){console.log(1)}//无
if(f1){console.log(2)}//2
因为f2可以看做是对象,对象的Boolean值为true。所以只会输出2,没有1。