我要经营快乐工厂
时间:2018-05-27 02:10:52来源:杰瑞文章网点击:作文字数:600字
作文导读:一、理解对象 1.创建 ①构造函数 new Object ②对象字面量 var o = {}; 2.属性类型 ①数据属性,对象属性有4个属性特征,默认都为true,可以通过Object.defineProperty()来修改属性特征 a.[[Configurable]] 表示能否通过delete删除重新定义,能否修改属性的特征,能否修改为访问权属性 b.[[Enumerable]] 表示能否通过for-in枚举 c.[[Writable]] 表示能否修改属性的值 d.[[Value]] 表示属性值 eg: var o = { name : [1, 2, 3] } Object.defineProperty(o, "name", { configurable : false, // 不能delete,不能修改,不能设置为访问器属性 enumerable : false, // 不能枚举 writable : false, // 不能修改 value : [100, 200] // 把值变成[100, 200] }); // for(var v in o.name) { // alert(o.name[v]); // 100, 200, 能枚举 // } alert(o.propertyIsEnumerable("name")); // false // o.name = "li"; // alert(o.name); // 100, 200 不能修改 // delete o.name; // alert(o.name); // 100, 200 不能删除 ②访问器属性,4个访问器属性特征,可以通过Object.defineProperty()来修改属性特征 a.[[Configurable]] 表示能否通过delete删除重新定义,能否修改属性的特征,能否修改为访问权属性 b.[[Enumerable]] 表示能否通过for-in枚举 c.[[Get]] 表示在读取属性时调用的函数,默认为undefined d.[[Set]] 表示在设置属性时调用的函数,默认为undefined eg: var o = { name : [1, 2, 3] } Object.defineProperty(o, "name", { get : function () { alert("get"); }, set : function() { alert("set"); } }); o.name = "li"; // set,设置name值时,自动调用o.set() o.name; // get,读取name时,自动调用o.get() ③定义多个属性 Object.defineProperties()来同时定义多个属性 eg: var o = {} Object.defineProperties(o, { name : { configurable : false, value : "zhang" }, age : { get : function () { alert("get"); }, set : function() { alert("set"); } } }); alert(o.name); // zhang o.age; // get o.age = "li"; // set ④读取属性的特征 Object.getOwnPropertyDescriptor(objectName, propertyName) eg: var o = {} Object.defineProperties(o, { age : { get : function () { alert("get"); }, set : function() { alert("set"); } } }); var descriptor = Object.getOwnPropertyDescriptor(o, "age"); for(var v in descriptor) { alert(v + " = " + descriptor[v]); // 弹出访问器属性的4个属性特征 }二、创建对象 1.工厂模式 ①抽象了创建对象的具体过程 eg: function createObject (name, age) { var object = new Object(); object.name = name; object.age = age; object.sayName = function () { return object.name; } return object; } var p1 = createObject("zhang", 23); var p2 = createObject("li", 33); alert(p1.sayName()); // zhang alert(p2.sayName()); // li // 无法识别p1和p2 alert(p1); // [object Object] alert(p2); // [object Object] ②弊端 没有解决对象识别的问题 ③解决方法 构造函数模型 2.构造函数模式 ①创建模式 eg: function Person(name, age) { this.name = name; this.age = age; this.getName = function () { return this.name; } } var p1 = new Person("zhang", 34); var p2 = new Person("li", 23); alert(p1.getName()); // zhang alert(p2.getName()); // li alert(p1 instanceof Person); // true alert(p2 instanceof Person); // true, 解决了工厂模式的对象识别问题 ②问题 每个方法都要在每个实例上创建一遍,从而形成不同的作用域链,从而导致不相同 eg: alert(p1.getName == p2.getName); // false 我们也可以将方法部分提取到构造函数之外,但这样就没有什么封装性可言了。 eg: function Person(name, age) { this.name = name; this.age = age; this.getName = getName; } function getName () { return this.name; } ③解决方法 原型模型 3.原型模式 ①创建模式 原型对象(构造函数的prototype属性指向它)的好处:可以让所有对象实例共享它包含属性和方法 eg: function Person(name, age) { this.name = name; this.age = age; } Person.prototype.getName = function () { return this.name; } var p1 = new Person("zhang", 34); var p2 = new Person("li", 23); alert(p1.getName == p2.getName); // true,解决了方法共享的问题 ②理解原型 a.函数Person.prototype指向原型 b.Person.prototype.constructor指回构造函数 c.p1、p2的prototype指向原型,且可调用原型中的方法,用Person.prototype.isPrototypeOf(p1)判断,也可以用Object.getPrototypeOf(p1)来获取原型 d.我们可以用原型访问属性的值,但是不能通过实例重写原型的值,因为对象实例的值会屏蔽原型属性的值。当我们用实例对象重写了原型中的值,只有删除实例对象的值,才能访问原型属性的值。 e.同样我们可以通过[实例.hasOwnProperty(propertyName)]来检测实例是否定义了自己的属性值 eg: function Person() {} Person.prototype.name = "zhang"; Person.prototype.getName = function () { return this.name; } var p1 = new Person(); alert(p1.name); // zhang p1.name = "li"; alert(p1.name); // li,实例中的值覆盖了原型中的值 alert(p1.hasOwnProperty("name")); // 判断实例p1是否定义了自己的属性name的值,true delete p1.name; // 删除实例对象中的属性值 alert(p1.name); // zhang ③原型与in操作符 a.无论是属性值存在于原型中,还是实例对象中都返回true eg: function Person() {} Person.prototype.name = "zhang"; Person.prototype.getName = function () { return this.name; } // 判断是否为原型中的属性 function hasPrototypeProperty(object, propertyName) { return propertyName in object && !object.hasOwnProperty(propertyName); } var p1 = new Person(); p1.name = "li"; alert(hasPrototypeProperty(p1, "name")); // false delete p1.name; alert(hasPrototypeProperty(p1, "name")); // true b.枚举所有可枚举的属性和方法,用Object.key(原型/实例) eg: function Person() {} Person.prototype.name = "zhang"; Person.prototype.age = 11; Person.prototype.getName = function () { return this.name; } alert(Object.keys(Person.prototype)); // 枚举原型中的属性和方法 var p1 = new Person(); p1.name = "li"; p1.getName = function () {} // 枚举实例对象中的属性和方法 alert(Object.keys(p1)); c.枚举所有的属性和方法,无论是否隐藏,用hasOwnPropertyNames(原型); eg: alert(Object.getOwnPropertyNames(Person)); // prototype,length,name ④更简单的原型方法 a.源码 eg: function Person() {} Person.prototype = { constructor : Person, name : "zhang", getName : function () {} } b.问题 这样做可能会导致原型中的constructor属性的[Enumerable]为true,默认为false c.解决方法 用Object.defineProperty()方法重新定义 eg: Object.defineProperty(Person.prototype, constructor, { enumerable : false}); e.实例化对象一定要后于对象的定义完毕 ⑤原型对象的问题 共享性,针对方法很好,针对属性也说的过去,但是针对那些包含了引用类型则不可 eg: function Person() {} Person.prototype = { constructor : Person, friends : [1, 2] // 引用类型 } var p1 = new Person(); var p2 = new Person(); p1.friends.push(3); alert(p1.friends); alert(p2.friends); // 同时返回1,2,3 ⑥解决方法 取长补短,用构造函数模式定义属性,用原型模式定义方法 3.组合构造模式和原型模式 ①模式 取长补短,用构造函数模式定义属性,用原型模式定义方法 eg: function Person(name) { this.name = name; this.friends = [1, 2] // 引用类型 } Person.prototype = { constructor : Person, name : "zhang", } var p1 = new Person("li"); var p2 = new Person("wang"); p1.friends.push(3); alert(p1.friends); // 1,2,3 alert(p2.friends); // 1,2 ②小问题 感觉构造函数和原型分离,破坏了封装性 ③解决方法 使用动态原型模式 4.动态原型模式(基本完美) 将原型中方法封装到构造函数中去 eg: function Person(name) { this.name = name; this.friends = [1, 2]; // 引用类型 if (typeof this.getName != "function") { Person.prototype.getName = { return this.name; } } } 5.寄生构造模式 ①基本思想:创建一个函数(对象),该函数用来封装代码,然后返回函数(对象) ②模式 eg: function Person(name, age) { var o = new Object(); o.name = name; o.age = age; o.getName = function () { return o.name; }; return o; } var p1 = new Person("zhang", 34); alert(p1.getName()); // zhang alert(p1 instanceof Person);// false ③问题:由于实例对象和构造函数完全分离,因此无法识别对象 ④案例:对于Array类型,我们可能在特殊情况在,对它进行添加属性和方法 eg: function NewArray() { var array = new Array(); array.push.apply(array, arguments); array.addFun = function () { return this.join("|"); } return array; } var a1 = new NewArray("zhang", 22); alert(a1.addFun()); // zhang|22 6.稳妥构造函数模型 没有公共属性,不使用this和new,只能定义获取值的方法 ①用途:安全性 ②源码 eg: function Person(name, age) { var o = new Object(); o.getName = function () { return name; } return o; } var p = Person("zhang", 3); p.name = 'li'; // 无效 alert(p.getName()); // zhang ③特点 函数名首字母大写、对象里只定义方法且不用this、实例化时不用new ④问题:由于实例对象和构造函数完全分离,因此无法识别对象三、继承 1.原型链 ①将父类的实例赋值给子类的原型。因为父类的实例指向父类的原型,因此子类的原型也指向父类的原型。 ②基本源码: eg: function SuperType(){ this.property = true; } SuperType.prototype.getSuperValue = function(){ return this.property; }; function SubType(){ this.subproperty = false; } //继承了SuperType SubType.prototype = new SuperType(); // 将父类的实例赋值给子类的原型 SubType.prototype.getSubValue = function (){ return this.subproperty; }; var instance = new SubType(); alert(instance.getSuperValue()); //true,调用父类SuperType的方法getSuperValue() ③别忘记了父类同样基础了祖类Object ③确定原型和实例的关系 用instanceof和对象.isPrototypeOf(实例) ④在子类重新或者添加父类的方法时,必须要在父类定义之后 ⑤原型链的问题 原型链中不能存在引用类型 eg: function SuperType(){ this.friends = [1,2]; } function SubType(){} //继承了SuperType SubType.prototype = new SuperType(); var s1 = new SubType(); var s2 = new SubType(); s1.friends.push(3); alert(s1.friends); // 1, 2, 3 alert(s2.friends); // 同上 ⑥解决方法 借用构造函数 2.借用构造函数 对于原型链中包含引用类型,我们可以在子类的构造函中调用父类的构造函数 ①源码案例, 即可以使用引用类型,还可以传递参数 eg: function SuperType(name){ this.name = name; this.friends = [1,2]; } function SubType(){ SuperType.call(this, "abc"); // 传递参数 } //继承了SuperType SubType.prototype = new SuperType(); var s1 = new SubType(); var s2 = new SubType(); s1.friends.push(3); alert(s1.friends); // 1, 2, 3 alert(s2.friends); // 1, 2 alert(s1.name); // abc ③问题 由于是在构造函数中定义,所以方法不能够共享 ④解决方法 组合继承 3.组合继承(虽然两次调用了父类,但是基本ok) ①基本思想 将借用构造和原型链结合起来,借用构造定义属性,原型链定义方法 eg: function SuperType(name){ this.name = name; this.friends = [1,2]; if (typeof this.getName != "function") { SuperType.prototype.getName = function () { return this.name; } } } function SubType(name, age){ SuperType.call(this, name); // 第二次调用父类 this.age = age; if (typeof this.getAge != "function") { SuperType.prototype.getAge = function () { return this.age; } } } //继承了SuperType SubType.prototype = new SuperType(); // 第一次调用父类 var s1 = new SubType("zhang", 23); var s2 = new SubType("li", 24); s1.friends.push(3); alert(s1.friends); // 1, 2, 3 alert(s2.friends); // 1, 2 alert(s1.getName()); // zhang alert(s2.getAge()); // 24 4.原型式继承 ①基本思想 借助原型可以基于已有的对象创建新对象,从而不必自定义对象 eg: function object(o) { function F() {}; F.prototype = o; return new F(); } var person = { name : "zhang", friends : [1, 2] } var p1 = object(person); p1.name = "li"; p1.friends.push(3); alert(p1.name); // li alert(p1.friends); // 1,2,3 var p2 = object(person); p1.name = "wang"; p1.friends.push(4); alert(p2.name); // wang alert(p2.friends); // 1,2,3,4 ②ECMAScript 5发展了道格拉斯·克罗克福德的原型链继承,用Object.create()方法 eg: 其中第二个参数和defineProperty()方法一致 var person = { name : "zhang", friends : [1, 2] } var p1 = Object.create(person, { name : { value : "zhang" } }); p1.friends.push(3); alert(p1.name); // li alert(p1.friends); // 1,2,3 var p2 = Object.create(person, { name : { value : "wang" } }); p1.friends.push(4); alert(p2.name); // wang alert(p2.friends); // 1,2,3,4 ③问题: 原型链共享问题,引用类型 5.寄生式继承 ①思想 基于原型式继承,创建一个新函数对象,添加新方法 eg: function object(o) { function F() {}; F.prototype = o; return new F(); } function createAnother(original) { // 继承原来的对象原型 var clone = object(original); // 添加新方法 clone.newFun = function () { return "new function"; } return clone; } var person = { name : "zhang", friends : [1, 2] } var p = createAnother(person); alert(p.name); // zhang alert(p.newFun()); // new function ②问题 原型链共享问题,引用类型 6.寄生组合式继承 ①思想 在组合继承和原型式继承的基础上,不在子类的内部调用父类的构造函数,而是创建父类原型的副本 eg: function object(o) { function F() {}; F.prototype = o; return new F(); } function inheritPrototype(subType, superType) { // 赋值proto为superType的原型 var proto = object(superType.prototype); // 原型的contructor属性指向构造函数 proto.contructor = subType; // superType的构造函数指向原型 subType.prototype = proto; } function SuperType(name){ this.name = name; this.friends = [1,2]; if (typeof this.getName != "function") { SuperType.prototype.getName = function () { return this.name; } } } inheritPrototype(SubType, SuperType); function SubType(name, age){ SuperType.call(this, name); this.age = age; if (typeof this.getAge != "function") { SuperType.prototype.getAge = function () { return this.age; } } } var s1 = new SubType("zhang", 23); var s2 = new SubType("li", 24); s1.friends.push(3); alert(s1.friends); // 1, 2, 3 alert(s2.friends); // 1, 2 alert(s1.getName()); // zhang alert(s2.getAge()); // 24
一、理解对象 1.创建 ①构造函数 new Object ②对象字面量 var o = {}; 2.属性类型 ①数据属性,对象属性有4个属性特征,默认都为true,可以通过Object.defineProperty()来修改属性特征 a.[[Configurable]] 表示能否通过delete删除重新定义,能否修改属性的特征,能否修改为访问权属性 b.[[Enumerable]] 表示能否通过for-in枚举 c.[[Writable]] 表示能否修改属性的值 d.[[Value]] 表示属性值 eg: var o = { name : [1, 2, 3] } Object.defineProperty(o, "name", { configurable : false, // 不能delete,不能修改,不能设置为访问器属性 enumerable : false, // 不能枚举 writable : false, // 不能修改 value : [100, 200] // 把值变成[100, 200] }); // for(var v in o.name) { // alert(o.name[v]); // 100, 200, 能枚举 // } alert(o.propertyIsEnumerable("name")); // false // o.name = "li"; // alert(o.name); // 100, 200 不能修改 // delete o.name; // alert(o.name); // 100, 200 不能删除 ②访问器属性,4个访问器属性特征,可以通过Object.defineProperty()来修改属性特征 a.[[Configurable]] 表示能否通过delete删除重新定义,能否修改属性的特征,能否修改为访问权属性 b.[[Enumerable]] 表示能否通过for-in枚举 c.[[Get]] 表示在读取属性时调用的函数,默认为undefined d.[[Set]] 表示在设置属性时调用的函数,默认为undefined eg: var o = { name : [1, 2, 3] } Object.defineProperty(o, "name", { get : function () { alert("get"); }, set : function() { alert("set"); } }); o.name = "li"; // set,设置name值时,自动调用o.set() o.name; // get,读取name时,自动调用o.get() ③定义多个属性 Object.defineProperties()来同时定义多个属性 eg: var o = {} Object.defineProperties(o, { name : { configurable : false, value : "zhang" }, age : { get : function () { alert("get"); }, set : function() { alert("set"); } } }); alert(o.name); // zhang o.age; // get o.age = "li"; // set ④读取属性的特征 Object.getOwnPropertyDescriptor(objectName, propertyName) eg: var o = {} Object.defineProperties(o, { age : { get : function () { alert("get"); }, set : function() { alert("set"); } } }); var descriptor = Object.getOwnPropertyDescriptor(o, "age"); for(var v in descriptor) { alert(v + " = " + descriptor[v]); // 弹出访问器属性的4个属性特征 }二、创建对象 1.工厂模式 ①抽象了创建对象的具体过程 eg: function createObject (name, age) { var object = new Object(); object.name = name; object.age = age; object.sayName = function () { return object.name; } return object; } var p1 = createObject("zhang", 23); var p2 = createObject("li", 33); alert(p1.sayName()); // zhang alert(p2.sayName()); // li // 无法识别p1和p2 alert(p1); // [object Object] alert(p2); // [object Object] ②弊端 没有解决对象识别的问题 ③解决方法 构造函数模型 2.构造函数模式 ①创建模式 eg: function Person(name, age) { this.name = name; this.age = age; this.getName = function () { return this.name; } } var p1 = new Person("zhang", 34); var p2 = new Person("li", 23); alert(p1.getName()); // zhang alert(p2.getName()); // li alert(p1 instanceof Person); // true alert(p2 instanceof Person); // true, 解决了工厂模式的对象识别问题 ②问题 每个方法都要在每个实例上创建一遍,从而形成不同的作用域链,从而导致不相同 eg: alert(p1.getName == p2.getName); // false 我们也可以将方法部分提取到构造函数之外,但这样就没有什么封装性可言了。 eg: function Person(name, age) { this.name = name; this.age = age; this.getName = getName; } function getName () { return this.name; } ③解决方法 原型模型 3.原型模式 ①创建模式 原型对象(构造函数的prototype属性指向它)的好处:可以让所有对象实例共享它包含属性和方法 eg: function Person(name, age) { this.name = name; this.age = age; } Person.prototype.getName = function () { return this.name; } var p1 = new Person("zhang", 34); var p2 = new Person("li", 23); alert(p1.getName == p2.getName); // true,解决了方法共享的问题 ②理解原型 a.函数Person.prototype指向原型 b.Person.prototype.constructor指回构造函数 c.p1、p2的prototype指向原型,且可调用原型中的方法,用Person.prototype.isPrototypeOf(p1)判断,也可以用Object.getPrototypeOf(p1)来获取原型 d.我们可以用原型访问属性的值,但是不能通过实例重写原型的值,因为对象实例的值会屏蔽原型属性的值。当我们用实例对象重写了原型中的值,只有删除实例对象的值,才能访问原型属性的值。 e.同样我们可以通过[实例.hasOwnProperty(propertyName)]来检测实例是否定义了自己的属性值 eg: function Person() {} Person.prototype.name = "zhang"; Person.prototype.getName = function () { return this.name; } var p1 = new Person(); alert(p1.name); // zhang p1.name = "li"; alert(p1.name); // li,实例中的值覆盖了原型中的值 alert(p1.hasOwnProperty("name")); // 判断实例p1是否定义了自己的属性name的值,true delete p1.name; // 删除实例对象中的属性值 alert(p1.name); // zhang ③原型与in操作符 a.无论是属性值存在于原型中,还是实例对象中都返回true eg: function Person() {} Person.prototype.name = "zhang"; Person.prototype.getName = function () { return this.name; } // 判断是否为原型中的属性 function hasPrototypeProperty(object, propertyName) { return propertyName in object && !object.hasOwnProperty(propertyName); } var p1 = new Person(); p1.name = "li"; alert(hasPrototypeProperty(p1, "name")); // false delete p1.name; alert(hasPrototypeProperty(p1, "name")); // true b.枚举所有可枚举的属性和方法,用Object.key(原型/实例) eg: function Person() {} Person.prototype.name = "zhang"; Person.prototype.age = 11; Person.prototype.getName = function () { return this.name; } alert(Object.keys(Person.prototype)); // 枚举原型中的属性和方法 var p1 = new Person(); p1.name = "li"; p1.getName = function () {} // 枚举实例对象中的属性和方法 alert(Object.keys(p1)); c.枚举所有的属性和方法,无论是否隐藏,用hasOwnPropertyNames(原型); eg: alert(Object.getOwnPropertyNames(Person)); // prototype,length,name ④更简单的原型方法 a.源码 eg: function Person() {} Person.prototype = { constructor : Person, name : "zhang", getName : function () {} } b.问题 这样做可能会导致原型中的constructor属性的[Enumerable]为true,默认为false c.解决方法 用Object.defineProperty()方法重新定义 eg: Object.defineProperty(Person.prototype, constructor, { enumerable : false}); e.实例化对象一定要后于对象的定义完毕 ⑤原型对象的问题 共享性,针对方法很好,针对属性也说的过去,但是针对那些包含了引用类型则不可 eg: function Person() {} Person.prototype = { constructor : Person, friends : [1, 2] // 引用类型 } var p1 = new Person(); var p2 = new Person(); p1.friends.push(3); alert(p1.friends); alert(p2.friends); // 同时返回1,2,3 ⑥解决方法 取长补短,用构造函数模式定义属性,用原型模式定义方法 3.组合构造模式和原型模式 ①模式 取长补短,用构造函数模式定义属性,用原型模式定义方法 eg: function Person(name) { this.name = name; this.friends = [1, 2] // 引用类型 } Person.prototype = { constructor : Person, name : "zhang", } var p1 = new Person("li"); var p2 = new Person("wang"); p1.friends.push(3); alert(p1.friends); // 1,2,3 alert(p2.friends); // 1,2 ②小问题 感觉构造函数和原型分离,破坏了封装性 ③解决方法 使用动态原型模式 4.动态原型模式(基本完美) 将原型中方法封装到构造函数中去 eg: function Person(name) { this.name = name; this.friends = [1, 2]; // 引用类型 if (typeof this.getName != "function") { Person.prototype.getName = { return this.name; } } } 5.寄生构造模式 ①基本思想:创建一个函数(对象),该函数用来封装代码,然后返回函数(对象) ②模式 eg: function Person(name, age) { var o = new Object(); o.name = name; o.age = age; o.getName = function () { return o.name; }; return o; } var p1 = new Person("zhang", 34); alert(p1.getName()); // zhang alert(p1 instanceof Person);// false ③问题:由于实例对象和构造函数完全分离,因此无法识别对象 ④案例:对于Array类型,我们可能在特殊情况在,对它进行添加属性和方法 eg: function NewArray() { var array = new Array(); array.push.apply(array, arguments); array.addFun = function () { return this.join("|"); } return array; } var a1 = new NewArray("zhang", 22); alert(a1.addFun()); // zhang|22 6.稳妥构造函数模型 没有公共属性,不使用this和new,只能定义获取值的方法 ①用途:安全性 ②源码 eg: function Person(name, age) { var o = new Object(); o.getName = function () { return name; } return o; } var p = Person("zhang", 3); p.name = 'li'; // 无效 alert(p.getName()); // zhang ③特点 函数名首字母大写、对象里只定义方法且不用this、实例化时不用new ④问题:由于实例对象和构造函数完全分离,因此无法识别对象三、继承 1.原型链 ①将父类的实例赋值给子类的原型。因为父类的实例指向父类的原型,因此子类的原型也指向父类的原型。 ②基本源码: eg: function SuperType(){ this.property = true; } SuperType.prototype.getSuperValue = function(){ return this.property; }; function SubType(){ this.subproperty = false; } //继承了SuperType SubType.prototype = new SuperType(); // 将父类的实例赋值给子类的原型 SubType.prototype.getSubValue = function (){ return this.subproperty; }; var instance = new SubType(); alert(instance.getSuperValue()); //true,调用父类SuperType的方法getSuperValue() ③别忘记了父类同样基础了祖类Object ③确定原型和实例的关系 用instanceof和对象.isPrototypeOf(实例) ④在子类重新或者添加父类的方法时,必须要在父类定义之后 ⑤原型链的问题 原型链中不能存在引用类型 eg: function SuperType(){ this.friends = [1,2]; } function SubType(){} //继承了SuperType SubType.prototype = new SuperType(); var s1 = new SubType(); var s2 = new SubType(); s1.friends.push(3); alert(s1.friends); // 1, 2, 3 alert(s2.friends); // 同上 ⑥解决方法 借用构造函数 2.借用构造函数 对于原型链中包含引用类型,我们可以在子类的构造函中调用父类的构造函数 ①源码案例, 即可以使用引用类型,还可以传递参数 eg: function SuperType(name){ this.name = name; this.friends = [1,2]; } function SubType(){ SuperType.call(this, "abc"); // 传递参数 } //继承了SuperType SubType.prototype = new SuperType(); var s1 = new SubType(); var s2 = new SubType(); s1.friends.push(3); alert(s1.friends); // 1, 2, 3 alert(s2.friends); // 1, 2 alert(s1.name); // abc ③问题 由于是在构造函数中定义,所以方法不能够共享 ④解决方法 组合继承 3.组合继承(虽然两次调用了父类,但是基本ok) ①基本思想 将借用构造和原型链结合起来,借用构造定义属性,原型链定义方法 eg: function SuperType(name){ this.name = name; this.friends = [1,2]; if (typeof this.getName != "function") { SuperType.prototype.getName = function () { return this.name; } } } function SubType(name, age){ SuperType.call(this, name); // 第二次调用父类 this.age = age; if (typeof this.getAge != "function") { SuperType.prototype.getAge = function () { return this.age; } } } //继承了SuperType SubType.prototype = new SuperType(); // 第一次调用父类 var s1 = new SubType("zhang", 23); var s2 = new SubType("li", 24); s1.friends.push(3); alert(s1.friends); // 1, 2, 3 alert(s2.friends); // 1, 2 alert(s1.getName()); // zhang alert(s2.getAge()); // 24 4.原型式继承 ①基本思想 借助原型可以基于已有的对象创建新对象,从而不必自定义对象 eg: function object(o) { function F() {}; F.prototype = o; return new F(); } var person = { name : "zhang", friends : [1, 2] } var p1 = object(person); p1.name = "li"; p1.friends.push(3); alert(p1.name); // li alert(p1.friends); // 1,2,3 var p2 = object(person); p1.name = "wang"; p1.friends.push(4); alert(p2.name); // wang alert(p2.friends); // 1,2,3,4 ②ECMAScript 5发展了道格拉斯·克罗克福德的原型链继承,用Object.create()方法 eg: 其中第二个参数和defineProperty()方法一致 var person = { name : "zhang", friends : [1, 2] } var p1 = Object.create(person, { name : { value : "zhang" } }); p1.friends.push(3); alert(p1.name); // li alert(p1.friends); // 1,2,3 var p2 = Object.create(person, { name : { value : "wang" } }); p1.friends.push(4); alert(p2.name); // wang alert(p2.friends); // 1,2,3,4 ③问题: 原型链共享问题,引用类型 5.寄生式继承 ①思想 基于原型式继承,创建一个新函数对象,添加新方法 eg: function object(o) { function F() {}; F.prototype = o; return new F(); } function createAnother(original) { // 继承原来的对象原型 var clone = object(original); // 添加新方法 clone.newFun = function () { return "new function"; } return clone; } var person = { name : "zhang", friends : [1, 2] } var p = createAnother(person); alert(p.name); // zhang alert(p.newFun()); // new function ②问题 原型链共享问题,引用类型 6.寄生组合式继承 ①思想 在组合继承和原型式继承的基础上,不在子类的内部调用父类的构造函数,而是创建父类原型的副本 eg: function object(o) { function F() {}; F.prototype = o; return new F(); } function inheritPrototype(subType, superType) { // 赋值proto为superType的原型 var proto = object(superType.prototype); // 原型的contructor属性指向构造函数 proto.contructor = subType; // superType的构造函数指向原型 subType.prototype = proto; } function SuperType(name){ this.name = name; this.friends = [1,2]; if (typeof this.getName != "function") { SuperType.prototype.getName = function () { return this.name; } } } inheritPrototype(SubType, SuperType); function SubType(name, age){ SuperType.call(this, name); this.age = age; if (typeof this.getAge != "function") { SuperType.prototype.getAge = function () { return this.age; } } } var s1 = new SubType("zhang", 23); var s2 = new SubType("li", 24); s1.friends.push(3); alert(s1.friends); // 1, 2, 3 alert(s2.friends); // 1, 2 alert(s1.getName()); // zhang alert(s2.getAge()); // 24

我要经营快乐工厂一文由杰瑞文章网免费提供,本站为公益性作文网站,此作文为网上收集或网友提供,版权归原作者所有,如果侵犯了您的权益,请及时与我们联系,我们会立即删除!
杰瑞文章网友情提示:请不要直接抄作文用来交作业。你可以学习、借鉴、期待你写出更好的作文。
说说你对这篇作文的看法吧