1.在js中,所有对象都有自己的原型对象(prototype)。一方面,任何一个对象,都可以充当其他对象的原型;另一方面,由于原型对象也是对象,所以它也有自己的原型。因此,就会形成一个“原型链”:对象到原型,再到原型的原型...直到null为止。
function fn() {
this.eye = 2
this.life = 1
}
function fm() {
this.name = "xiaozhang"
this.age = 21
}
var f1 = new fn()
//将f1对象作为fm的原型对象
fm.prototype = f1
// 上一步执行之后,再通过fm创建的对象就具有f1的属性
var f2 = new fm()
console.log(f2)
console.log(f2.life)
console.log(f2.eye)
结果:
2.当读取某个对象的属性时,先在对象本身查找,如果没有就到对象的原型对象上查找,如果对象的原型对象也没有,就到原型对象的原型对象上找,以此类推......
function fn() {
age = 20
}
fn.prototype.name = "xiaozhang"
var f1 = new fn()
console.log(f1.name)
直到找到null都没有,那么就返回undefined
function fn() {
age = 20
}
fn.prototype.name = "xiaozhang"
var f1 = new fn()
console.log(f1.a)
3.如果对象本身和它的原型对象都定义了一个同名属性,读取时优先读取对象本身的属性。
function fn() {
this.age = 20
}
fn.prototype.age = 30
var f1 = new fn()
console.log(f1.age)
4.对象给一个成员存值时 ,无论其原型链上是否有这个成员 都会把更新或者添加这个成员在对象自己的内存中 ,不会操作原型对象
function fn() {
this.name = "xiaozhang"
}
fn.prototype = {age:30}
var f1 = new fn()
f1.age = 20
console.log(f1)
5.系统内置构造函数:Object、 Function、 Array、 Date等; 系统内置的构造函数的原型属性不可以直接替换(代码会被静默) 但是可以添加或者重写其原型对象的成员;自定义的构造函数的原型属性可以随便操作
// 代码不会报错,但是不会执行这一句
Array.prototype = {a:20}
// 在Array的原型对象中添加了一个age属性,值为22
Array.prototype.age = 22
// 此后创建的数组都能访问到age属性
var arr = [1,2,3]
console.log(arr.__proto__)
console.log(arr.age)
6.笔试题1
Object.prototype.life = 1
Function.prototype.life = 2
function fn() {
this.name = "karen"
}
var f1 = new fn()
console.log(f1.name,f1.life)
console.log(fn.life,fn.name)
结果:
分析:第一步,最开始就给系统内置构造函数Object和Function的原型对象添加了一个life属性,值分别为1和2;所以之后创建的对象和函数都能访问到life属性。
第二步,创建了一个函数fn,添加一个name属性为karen
第三步,使用new关键字:1.创建空对象 2.函数中的this指向创建的空对象 3.函数的返回值为基本数据,所以表达式的值就是创建的对象
第四步,因为this指向的是创建的对象,因此f1.name=karen;由于表达式得到的是对象,所以f1能访问的是Object的原型对象,所以f1.life=1
第五步,因为fn是定义的一个函数,而一开始就为所有函数的原型对象添加了life属性,值为2,所以fn.life=2;而函数有默认的name属性,就是函数名,因此fn.name=fn
7.笔试题2
function Parent() {
this.a = 1;
this.b = [1, 2, this.a];
this.c = {
demo: 5
};
this.show = function() {
console.log(this.a, this.b, this.c.demo);
}
}
function Child() {
this.a = 2;
this.change = function() {
this.b.push(this.a);
this.a = this.b.length;
this.c.demo = this.a++;
}
}
Child.prototype = new Parent();
var parent = new Parent();
var child1 = new Child();
var child2 = new Child();
child1.a = 11;
child2.a = 12;
parent.show();
child1.show();
child2.show();
child1.change();
child2.change();
parent.show();
child1.show();
child2.show();
结果:
分析:
1.Child.prototype = new Parent();将new Parent()作为Child函数的原型对象,也就是用Child函数创建的对象都能访问到new Parent()的属性;Child.prototype={a:1,b:[1,2,1],c:{demo:5},show:function(){console.log(this.a,this.b,this.c.demo)},__proto__:{}}
2.var parent = new Parent();通过new关键字使用Parent函数创建一个新对象,this指向创建的对象,创建的对象能够访问到Parent的属性
3.var child1 = new Child();var child2 = new Child();分别使用new关键字使用Child函数分别创建child1和child2对象,this指向新创建的对象,并且这两个对象的原型对象是new Parent()
4.child1.a = 11; 在child1中添加一个属性a,并赋值为11.
child2.a = 12;在child2中添加一个属性a,并赋值为12.
5.parent.show();调用parent对象中的show方法,打印出1 [1,2,1] 5
6.child1.show();由于child1对象中没有show方法,所以到其原型对象new Parent()中找;并打印a,b,c.demo的值,但是由于child1里面有a属性,所以就打印它本身的a的值,其余没有的就打印原型对象中对应的值;因此打印 11 [1,2,1] 5
child2.show()同理可得 ,打印12 [1,2,1] 5
7.child1.change();执行change方法,this指向的是child1。this.b.push(this.a);由于原型对象不能修改但是可以操作,且这一步并没有修改原型对象,只是向原型对象的b属性中添加了一个数据,此时b就变为了[1,2,1,11]。this.a = this.b.length;给child1自己添加/更新a属性 值为child1的原型对象的属性b的长度,为4。this.c.demo = this.a++;先取a的值为4,再赋值给原型对象中的c.demo,最后a再加1变为5.
child2.change();同理,先再向原型对象的b中增加了a的值12,b就变为了[1,2,1,11,12];并且a又重新赋值为b.length的值,为5;然后再a再加1变为6.
8.parent.show(); 还是打印 1 [1,2,1] 5
child1.show(); 打印 5 [1,2,1,11,12] 5
child2.show(); 打印 6 [1,2,1,11,12] 5