重点来了,我认为这一章值得好好地反复地看。看第一遍 还是懵懵懂懂,现在看第二遍,终于能看出点意思了。
function createPerson(name, age, job){ var o = new Object(); o.name = name; o.age = age; o.job = job; o.sayName = function(){ alert(this.name); }; return o;}var person1 = createPerson("Nicholas", 29, "Software Engineer");var person2 = createPerson("Greg", 27, "Doctor");
优点:解决了Object构造函数或对象字面量创建多个对象代码重复的问题
缺点:无法识别对象.
function Person(name, age, job){ this.name = name; this.age = age; this.job = job; this.sayName = function(){ alert(this.name); };}var person1 = new Person("Nicholas", 29, "Software Engineer");alert(person1.constructor == Person);alert(person1 instanceof Object);alert(person1 instanceof Person);
优点:可以将它的实例识别为一种特定的对象
缺点:每个方法都要在每个实例上重新创建一遍,增加不必要的内存开支
function Person(){}Person.PRototype.name = "Nicholas";Person.prototype.age = 29;Person.prototype.job = "Software Engineer";Person.prototype.sayName = function(){ alert(this.name);};var person1 = new Person();person1.sayName();var person2 = new Person();person2.sayName();alert(person1.sayName === person2.sayName);
原型模式创建的属性对象是由所有实例共享的。
缺点:原型模式在包含引用类型时,实例共享会引起比较严重的问题。
在所有实现中都无法直接访问到prototype,只通通过isPrototypeOf()来检验对象之间是否存在这种关系。例:Person.prototype.isPrototypeOf(person1)
在实例中添加一个与原型中的同名属性,会在实例中创建该属性,而不会改变原型的值
var person1 = new Person();var person2 = new Person();person1.name = "Greg";alert(person1.name); //"Greg"——来自实例alert(person2.name); //"Nicholas"——来自原型
hasOwnProperty()检测一个属性是否在实例中;in 检测是否能访问到访属性,可能是在实例中,也可能是在原型中;
/*检测属性是否存在于原型中*/function hasprototypeProperty(object, name){return !object.hasOwnProperty(name) && (name in object);}
更简单的原型:
function Person(){}Person.prototype = { constructor : Person, /*用字面量定义prototype时,要设置它的constructor,不然它的constructor会指向Object*/ name : "Nicholas", age : 29, job : "Software Engineer", sayName : function (){ alert(this.name); }};/*这样设置有一点不足,会使constructor变为可枚举的,如果是支持ECMAScript5的浏览器,可用Object.defineProperty()是方法来设置constructor*/ /*Object.defineProperty(Person.prototype, "constructor",{ enumerable:false, value:Person});*/
实例中的指针仅指向原型,而不指向构造函数
构造函数模式用于定义实例属性,原型模式用于定义方法和共享属性。
function Person(name,age,job){ this.name = name; this.age = age; this.job = job; this.friends = ["Shelby","Court"];}Person.prototype = { constructor : Person, sayName : function(){ alert(this.name); }}
把所有信息封装到构造函数中,在构造函数中初始化原型。
优点:解决了独立的构造函数模式和原型模式独立的问题,又同时保持了两者的优点。
使用这种方法创建对象,不能用对象字面量重字原型。
function Person(name, age, job){ this.name = name; this.age = age; this.job = job; //方法 if(typeof this.sayName != "function"){ Person.prototype.sayName = function(){ alert(this.name); }; }}
除了用new操作符并把使用的包装函数叫做构造函数外,这个方法与工厂模式是一样的
例:具有额外方法的特殊数组,不又直接修改Array的构造函数function SpecialArray(){ //创建数组 var values = new Array(); //添加值 values.push.apply(values, arguments); //添加方法 values.toPipedString = function(){ return this.join("|"); }; return values;}var colors = new SpecialArray("red","blue","green");alert(colors.toPipedString());
使用这种模式,建议不要与其他模式混用
实现方法:SubType.prototype = new SuperType();
注1:子类型需要重写超类方法或添加超类中不存在的方法,需要在实现继承语句之后,这样才能屏蔽超类方法
注2:在通过原型链实现继承时,不能使用对象字面量方法创建原型方法,因为这样做会重写原型链
在子类型构造函数的内部调用超类型构造函数SuperType.call(this);
比原型链继承的优点是,解决了实例共享的问题,并可以传递参数
缺点同实例相同,也具有方法不能共享的问题
function SuperType(name){ this.name = name; this.colors = ["red","blue","green"];}SuperType.prototype.sayName = function(){ alert(this.name);};function SubType(name, age){ SuperType.call(this,name); this.age = age;}SubType.prototype = new SuperType();SubType.prototype.sayAge = function(){ alert(this.age);};var instance1 = new SubType("Nicholas",29);instance1.colors.push("black");alert(instance1.colors);instance1.sayName();instance1.sayAge();var instance2 = new SubType("Greg",27);alert(instance2.colors);instance2.sayName();instance2.sayAge();
function object(o){ function F(){} F.prototype = o; return new F();}
实现对传入对象o的浅复制,IE9+的Object.create(o)有相似功能
新闻热点
疑难解答