要实现更高的数据代码共享,则应使用原型模式。
1.原型对象
在javascript中,我们创建函数时,都会有一个prototype属性即原型属性。这个属性是一个指针,指向一个对象,这个对象的用途就是实现实例的属性、方法共享。
在默认情况下,所有的原型对象都会自动获得一个constructor属性即构造函数属性,该属性指向原对象。
这个神马内存指向的图我是不会画。话说Visio能不能画这种图哇。有木有大神讲解一下~
反正就是:
Dog.prototype.constructor==Dog;//true dog1.prototype.constructor==Dog;//true
也可以使用:
Dog.prototype.isPrototypeOf(dog1);//true Object.getPrototypeOf(dog1)==Person.prototype;//true
虽然可以通过对象实例访问保存在原型中的值,但却不能通过实例重写原型中的值,如果我们在实例中添加了一个同名属性,则可以理解为同名覆盖(此处开辟内存)。
2.原型函数
function Dog(){} Dog.prototype.age=11; Dog.prototype.size=22; Dog.prototype.toAge=function() { alert(this.age); }; var dog1=new Dog(); var dog2=new Dog(); dog1.age=20; dog1.toAge();//20,来自实例 dog2.toAge();//11,来自原型
delete操作符可以删除实例属性,从而让我们能够重新访问原型中的属性。
再提一句,hasOwnProperty()方法只有在实例重写属性之后才能访问。
而in操作符单独使用时,无论属性存在于实例中还是原型中,都可以访问。
除此之外,还有hasPrototypeProperty()函数用于访问原型中的属性。
要取得对象上所有可枚举的实例属性,可以使用Object.keys()方法。例如:
function Dog(){} Dog.prototype.age=11; Dog.prototype.size=33; Dog.prototype.toAge() { alert(this.age); }; var keys=Object.keys(Dog.prototype); alert(keys);//"age,size,toAge" var p1=new Dog(); p1.age=10; p1.size=44; var p1keys=Object.keys(p1); alert(p1keys);//"age,size"
如果你想得到所有实例属性可以使用Object.getOwnPropertyNames()方法。用法如下:
var keys=Object.getOwnPropertyNames(Dog.prototype); alert(keys);//"constructor,age,size,toAge"
获取属性的方法就介绍到这里。//都闪开,都闪开,后面这段我要吹牛逼了,大家看看就行......
其实更简单的原型语法如下:
function Dog(){} Dog.prototype={ age:12, size:44, toAge:function(){ alert(this.age); } }; var dog=new Dog;
但是这里实际上,完全重写了prototype对象,所以此时的原型对象的constructor属性已经不指向Dog函数了。例如:
alert(dog instanceof Object);//true alert(dog instanceof Dog);//true alert(dog.constructor==Object);//true alert(dog.constructor==Dog);//false
虽然使用instanceof还能返回正确结果,但是constructor已经无法确定对象的类型。但是依然可以为constructor设置为Dog。例如这样编写:
Dog.prototype={ constructor:Dog };
注意,重设构造函数只适用于ECMAScript5兼容浏览器。并且重设构造函数 会使默认的constructor变为可枚举的,您可以使用Object.defineProterty()函数改变。
Object.defineProterty(Dog.prototype,"constructor",{ enumerable:false;//设置为不可枚举 value:Dog });
在重写原型对象后,在重写之前的实例,属性即不可访问。
仔细理解:实例中的指针,仅指向原型,而不指向构造函数。重写了原型,则切断了函数与初始原型间的联系。实例依然指向初始原型,实例不可访问重写后原型的属性。
我这还有个问题,有木有大神帮忙解答,就是我能否访问实例的原型。为什么我是用dog1.prototype输出undefined。
顺便说一句,原生对象的方法也是在原型中定义的,如(Object,Array,String,等)。
原型对象的问题:对于包含引用类型值的属性来说,修改其属性值会导致,所有实例的值发生变化。所以很少有人单独使用原型模式。
引用类型值:指的是那些保存在堆内存中的对象,意思是,变量中保存的实际上只是一个指针,这个指针执行内存中的另一个位置,由该位置保存对象。
后记:上面的问题“为什么我是用dog1.prototype输出undefined”已经在知乎解决:使用dog1.__proto__访问。下面有附图我觉得很高大上的样子,可惜不太搞得懂。详情见知乎: