原型与原型链封装(点击打开链接)构造函数的继承(点击打开链接)非构造函数的继承(点击打开链接) Javascript规定,每一个构造函数都有一个prototype属性,指向另一个对象。这个对象的所有属性和方法,都会被构造函数的实例继承。这意味着,我们可以把那些不变的属性和方法,直接定义在prototype对象上。 function Cat(name,color){ this.name = name; this.color = color; } Cat.prototype.type = "猫科动物"; Cat.prototype.eat = function(){alert("吃老鼠")}; 然后,生成实例。 var cat1 = new Cat("大毛","黄色"); var cat2 = new Cat("二毛","黑色"); alert(cat1.type); // 猫科动物 cat1.eat(); // 吃老鼠 这时所有实例的type属性和eat()方法,其实都是同一个内存地址,指向prototype对象,因此就提高了运行效率。alert(cat1.eat == cat2.eat); //true Prototype模式的验证方法为了配合prototype属性,Javascript定义了一些辅助方法,帮助我们使用它。,isPrototypeOf()这个方法用来判断,某个proptotype对象和某个实例之间的关系。 alert(Cat.prototype.isPrototypeOf(cat1)); //true alert(Cat.prototype.isPrototypeOf(cat2)); //true hasOwnProperty()每个实例对象都有一个hasOwnProperty()方法,用来判断某一个属性到底是本地属性,还是继承自prototype对象的属性。 alert(cat1.hasOwnProperty("name")); // true alert(cat1.hasOwnProperty("type")); // false in运算符in运算符可以用来判断,某个实例是否含有某个属性,不管是不是本地属性。 alert("name" in cat1); // true alert("type" in cat1); // true in运算符还可以用来遍历某个对象的所有属性。for(var prop in cat1) { alert("cat1["+prop+"]="+cat1[prop]); } 继承 function Animal(){ this.species = "动物"; } function Cat(name,color){ this.name = name; this.color = color; } 构造函数绑定使用call或apply方法,将父对象的构造函数绑定在子对象上,即在子对象构造函数中加一行: function Cat(name,color){ Animal.apply(this, arguments);//Animal.call(this);(两种写法都可以输出) this.name = name; this.color = color; } var cat1 = new Cat("大毛","黄色"); alert(cat1.species); // 动物 prototype模式第二种方法更常见,使用prototype属性。function Action() {} Action.prototype.Cando=function(){ console.log("saddd"); } function ben(){} ben.prototype=new Action(); var aas=new ben(); console.log(aas); 浅拷贝 var Chinese = { nation:'中国' }; var Doctor ={ career:'医生' } 这两个对象都是普通对象,不是构造函数,无法使用构造函数方法实现"继承"。 除了使用"prototype链"以外,还有另一种思路:把父对象的属性,全部拷贝给子对象,也能实现继承。 function extendCopy(p) { var c = {}; for (var i in p) { c[i] = p[i]; } c.uber = p; return c; } var Doctor = extendCopy(Chinese); Doctor.career = '医生'; alert(Doctor.nation); // 中国 这样的拷贝有一个问题。那就是,如果父对象的属性等于数组或另一个对象,那么实际上,子对象获得的只是一个内存地址,而不是真正拷贝,因此存在父对象被篡改的可能。 现在给Chinese添加一个"出生地"属性,它的值是一个数组 Chinese.birthPlaces = ['北京','上海','香港']; 通过extendCopy()函数,Doctor继承了Chinese。 var Doctor = extendCopy(Chinese); 我们为Doctor的"出生地"添加一个城市: Doctor.birthPlaces.push('厦门'); Chinese的"出生地"也被改掉了! alert(Doctor.birthPlaces); //北京, 上海, 香港, 厦门 alert(Chinese.birthPlaces); //北京, 上海, 香港, 厦门 extendCopy()只是拷贝基本类型的数据,我们把这种拷贝叫做"浅拷贝"。这是早期jQuery实现继承的方式。 深拷贝就是能够实现真正意义上的数组和对象的拷贝。它的实现并不难,只要递归调用"浅拷贝"就行了。 function deepCopy(p, c) { var c = c || {}; for (var i in p) { if (typeof p[i] === 'object') { c[i] = (p[i].constructor === Array) ? [] : {}; deepCopy(p[i], c[i]); } else { c[i] = p[i]; } } return c; } var Doctor = deepCopy(Chinese); Chinese.birthPlaces = ['北京','上海','香港']; Doctor.birthPlaces.push('厦门'); jQuery库使用的就是这种继承方法。 alert(Doctor.birthPlaces); //北京, 上海, 香港, 厦门 alert(Chinese.birthPlaces); //北京, 上海, 香港