function HiClass() { this.sayHi = function(){ alert("hi"); }}var obj = new HiClass(); alert(HiClass.prototype);//outputs [object, object]alert(obj.prototype);//outputs undefined
在用prototype的方式实现继承一个类的时候,要注意其可能覆盖别的prototype方式添加的属性和方法。如果是HiClass.prototype.prop = 'value';
在HiClass.prototype = new HelloClass();之前,执行HiClass.prototype = new HelloClass();之后,HiClass的实例中不会有prop属性,这个应该很好理解。但是要注意代码中不要不小心存在这样的bug。function HiClass() { this.sayHi = function(){ alert("hi"); }}function HelloClass() { this.sayHello = function(){ alert("hello"); } }//HiClass.prototype.prop = 'value';HiClass.prototype = new HelloClass();HiClass.prototype.prop = 'value';var obj = new HiClass();obj.sayHello();alert(obj.prop);
在JavaScript中有一个prototype链,在对一个对象实例上调用方法或者获取属性的时候,先看实例对应的类有没有对应的定义,没有的话会沿着prototype链一直找,找不到则为undefined。
function Object2() {this.sayHi = function(){alert("hi Object2");}}function Object3() {this.sayHi = function(){alert("hi Object3");this.sayHello = function(){alert("hello Object3");}}Object2.prototype = new Object3();var obj = new Object2();obj.sayHi();obj.sayHello();Object.prototype.foo = function(){alert("f00 Object");};obj.foo();
调用obj.sayHi();的时候,sayHi在Object2里已经定义,则调用本身的定义。
调用obj.sayHello();的时候,sayHello在Object2里没有定义,但是由于prototype指向了Object3,则从Object3找,找到了执行。
调用obj.foo();的时候,sayHello在Object2和Object3里没有定义,但是由于JS中所有实例都会继承Object,所以可以在Object的prototype找到foo,然后执行。
如果在实例里添加的属性和方法与prototype里的属性和方法重名,相对于实例和prototype都有这个属性和方法,只是由于prototype链的访问顺序,先访问到实例中的属性和方法。使用hasOwnProperty()方法可以检测一个属性是否存在于实例中还是存在于原型中,如下面的例子说明了这一点:
function Test(){};Test.prototype.prop1 = 'prop value';var obj = new Test();obj.prop1 = 'instance value';alert(obj.prop1 );//outputs instance valuealert(obj.hasOwnProperty("prop1"));//outputs truedelete obj.prop1;alert(obj.prop1 ); //outputs prop valuealert(obj.hasOwnProperty("prop1"));//outputs falsealert("prop1" in obj);//outputs truedelete Test.prototype.prop1;alert(obj.prop1 );//outputs undefined
function TestCls(){ }TestCls.prototype = { prop1:'value1', prop2:'value2'};myObj = new TestCls();alert(myObj.prop2);
原型与in操作符
有两种方式使用IN操作符,单独使用和for-in循环中使用,单独使用时,in操作符会在通过对象访问属性时返回true 无论该属性存在于原型还是实例中:
function Person(){}Person.prototype.name="jerry";Person.prototype.age=29;Person.prototype.sayName=function(){ alert(this.name) } var person1=new Person(); var person2=new Person(); alert(person1.hasOwnProperty("name")) // false alert("name" in person1) //true person1.name="fdsfdsf"; alert(person1.property("name")) ;// true alert("name" in person1); // true
通过以上代码可以看出,name属性要么是直接在对象上访问到的,要没是通过原型访问到的,所以,使用IN访问对象属性始终返回TRUE,所以只要in操作符 只要通过对象能够访问到的属性就返回true,再通过harOwnProperty 如果返回的是false,可以确定属性是原型中的属性。
function hasPrototypePropetype(object,name) //对象名称,属性名称{ return !object.hasOwnPropetype(name)&&(name in object);}