JavaScript的prototype关键字
我们在写JavaScript代码时,会有这样的需求:
一:我要将某个对象的内容提取出来,使他成为公共部分,这就类似于我们在Java当中,把一个类的某个方法或变量声明为静态static,使得这个类的实例化对象都具有这个内容,不需要额外占据内存,内存对客户端浏览器来说更为重要,但是我们的JavaScript语言是基于对象的,类和对象在JavaScript中没有什么太大的区别,所以我们也没有在JavaScript中过多强调类这个概念。所以如何实现对象之间的数据共享问题呢?这时,prototype关键字就发挥作用了!
我们先讲它的使用:
var person(name,age){
this.name=name;
this.age=age;
}
person.prototype.talk(){
window.alert("I am a person.");
}
var user_1=new person();
var user_2=new person();
这样,我们创建的所有对象user_1,user_2都有talk()方法,这个和Java里面的类似,talk()保存在方法区,并不是在user_1,user_2中都封装了一份,节省内存!
二:我们有时也会需要给对象添加属性,添加方法。并且这在没有修改对象的代码字段的前提下。同样我们用代码介绍它的使用:
var person(name,age){
this.name=name;
this.age=age;
}
person.prototype.hobby="sleep";
var user_1=new person();
var user_2=new person();
window.alert(user_1.hobby);//sleep;window.alert(user_2.hobby);//sleep;
是的,我们在创建对象时并没有声明这个hobby属性,但是我们通过user.hobby调用发现这就是上面person.prototype.hobby="sleep";中的“sleep”。但这个属性或方法是person对象共享的。
通过现象看本质:那JavaScript当中,这个prototype关键字的实质是什么呢?我们结合内存来分析:类似Java中的静态代码块
我们的认识不能局限于此:prototype其实是person对象的原型对象,另外还有_proto_.他们的区别就在于prototype是显示的,而_proto_是隐示的。对于我们来说,先认识到这里即可。接着说我们的重点:
对象的属性和方法,有可能是定义在自身,也有可能是定义在它的原型对象。由于原型本身也是对象,又有自己的原型,所以形成了一条原型链(prototype chain)。比如,a对象是b对象的原型,b对象是c对象的原型,以此类推。 如果一层层地上溯,所有对象的原型最终都可以上溯到Object.prototype,即Object构造函数的prototype属性指向的那个对象。那么,Object.prototype对象有没有它的原型呢?回答可以是有的,就是没有任何属性和方法的null对象,而null对象没有自己的原型。并且这个原型类是可以覆盖的:
function A() {}
var a = new A();
a instanceof A // true
function B() {}
A.prototype = B.prototype;
a instanceof A // false
JavaScript间接实现了继承关系:
“原型链”的作用是,读取对象的某个属性时,JavaScript引擎先寻找对象本身的属性,如果找不到,就到它的原型去找,如果还是找不到,就到原型的原型去找。这就像Java当中的继承关系那样,由派生类一直找到基类object。如果直到最顶层的Object.prototype还是找不到,则返回undefined。如果对象自身和它的原型,都定义了一个同名属性,那么优先读取对象自身的属性,这叫做“覆盖”(overiding)。需要注意的是,一级级向上,在原型链寻找某个属性,对性能是有影响的。所寻找的属性在越上层的原型对象,对性能的影响越大。如果寻找某个不存在的属性,将会遍历整个原型链。
内存分析: