JS面向对象的程序设计 - 高设
1 //工厂模式 2 function createPerson (name, age, job){ 3 var o = new Object(); 4 o.name = name; 5 o.age = age; 6 o.job = job; 7 8 o.sayName = function (){ 9 alert(this.name); 10 } 11 return o; 12 } 13 14 var sam = createPerson("sam", 18, "web front"); 15 16 17 //构造函数模式 18 function Person (name, age, job){ 19 this.name = name; 20 this.age = age; 21 this.job = job; 22 this.sayName = function (){ 23 alert(this.name); 24 } 25 } 26 27 var david = new Person("david",18,"student"); 28 var sam= new Person("sam",18,"student"); 27 alert(david.constructor == Person) // true;
27 alert(sam.constructor == Person) // true;
原型模式
我们创建的每一个函数都有一个自带的 prototype(原型属性) 属性,它是一个对象(也叫原型对象),这个 prototype属性默认拥有一个 constructor(构造器)属性, constructor属性指向 prototype属性所在的函数的指针(相当于指针等同于构造函数中的this);
缺点:构造函数创建的每一个实例都会创建每一个实例的function实例,而每一个实例的function实例都不相等;(解决方法:高射147页,第三版)
function Person (name, age){ this.name = name; this.age = age; this.getName = function (){ return this.name; } // this.getName = new Function("return this.name"); 等同于这种形式,所以构造函数每生成一个实例,实例都会自己创建一个function,所以各实例的getName方法都是不同的函数; 我们可以将公共的 方法 或 属性 放入 prototype对象来实现 实例共同访问一个成员; } Person.prototype.name = "狼哥哥"; Person.prototype.country = "中国"; Person.prototype.getCountry = function (){ alert(this.country); }; alert(Person.prototype.constructor === Person); // true; var sam = new Person("sam", 18); var david = new Person("david", 18); alert(sam.getName === david.getName); // false; 构造函数中的方法是各不相同分别创建的; alert(sam.getCountry === david.getCountry); // true; 原型对象中的方法为共享的方法,只在此方法添加进原型对象时创建一次, 所以实例如果是继承原型对象的方法,那么各实例为同一个方法; alert(sam.hasOwnProperty("name")); // true; 来自构造函数; delete sam.name; // 删除构造函数中的name属性,这时候 sam,name === "狼哥哥"; 来自构造函数的 prototype对象; alert(sam.hasOwnProperty("name")); // false; 构造函数无 name属性; 但构造函数的 prototype对象有; sam.name = "sam"; //为实例添加 Own property; // 这是一个判断实例的属性或方法是否来自于 prototype对象的方法; function hasPrototypeProperty(obj, property){ return !obj.hasOwnProperty(property) && property in obj; // 构造函数没有此成员可 prototype对象有此成员 则返回 true } alert(hasPrototypeProperty(sam, "name")); // false; sam.name 为实例自身的成员; alert(hasPrototypeProperty(sam, "country")); // true; sam.country 继承于 prototype对象; delete sam.name; alert(hasPrototypeProperty(sam, "name")); // true; sam.name 继承于 prototype对象;
构造函数
构造函数其实也是普通的函数对象,构造函数与其他函数唯一的区别就是:当它通过 new操作符调用时,它就可以变成构造函数
将构造函数当作普通函数使用时,构造函数会将构造函数的参数添加给全局对象的属性(window);
hasOwnProperty()方法 如果对象拥有独有的属性,它将返回true, 此方法不会检查原型链
1 function Person2(){ 2 } 3 4 Person2.prototype.name = "sam"; 5 Person2.prototype.age = 18; 6 Person2.prototype.sayName = function (){ 7 alert(this.name); 8 } 9 10 var person1 = new Person2(); 11 var person2 = new Person2(); 12 13 alert(person1.age === person2.age); //true 14 alert(person1.hasOwnProperty('name')); // false; 15 16 person1.name = "david"; 17 alert(person1.name); // "david" ----来自实例; 18 alert(person1.hasOwnProperty('name')); // true; 19 20 alert(person2.name); // "sam" ----来自原型; 21 alert(person2.hasOwnProperty('name')); // false; 22 23 delete person1.name; 24 alert(person1.name); // "sam" ----来自原型 25 alert(person1.hasOwnProperty('name')); // false; 实例自身的属性已被删除,现在的属性继承自原型对象; 26 alert(person2.hasOwnProperty('name')); // true;
组合使用构造函数模式和原型模式
用构造函数定义实例属性,用原型模式来定义方法和共享属性,结果每个实例都会有一份属于自己的实例属性的副本,但同时又共享着对方法的引用,最大限度地节省了内存。
另外,这种模式还支持向构造函数传递参数,可谓是集两种模式之长。
function Person (name, age){ this.name = name, this.age = age, this.friends = [] } Person.prototype = { constructor : Person,
country : "China", getName : function (){ return this.name; }, getAge : function (){ return this.age; }, getFriends : function (){ var names = ""; for (var i=0; i<this.friends.length; i++){ if (this.friends[i]){ names += this.friends[i].getName(); }else{ break; } } return names; }, newFriend : function (name){ if (this.friends){ this.friends.push(name) } } }; var sam = new Person("sam", 18); var allen = new Person("Allen", 18); var douya = new Person("豆芽菜", 18); sam.newFriend(allen); sam.newFriend(douya); alert(sam.getFriends()); // Allen, 豆芽菜
寄生构造函数模式
这个模式可以在特殊的情况下用来为对象创建构造函数。 假设我们想创建一个具有额外方法的特殊数组。 由于不能直接修改 Array 构造函数,因此可以使用这个模式。
缺点:通过此模式返回的对象与构造函数或者与构造函数的原型对象之间没有一点关系,所以无法用 instanceof 操作符来确定对象类型。 所以我们建议在可以使用其他模式的情况下,不要使用这种模式。
function Person (name, age){ var o = new Object(); o.name = name; o.age = age; return o; // return 语句可以重写调用构造函数时返回的值; 此构造模式返回的对象与此构造函数以及此构造函数的 prototype属性没有一点关系,因此无法使用 instanceof 操作符来确定对象类型; 可以使用其他模式的情况下,不建议使用此模式。 } var sam = new Person("sam", 18); //这个模式可以在特殊的情况下用来为对象创建构造函数。架设我们想创建一个具有额外方法的特殊数组。由于不能直接修改Array构造函数,因此可以使用这个模式。 function SpecialArray (){ var arr = new Array(); //添加值 arr.push.apply(arr, arguments); arr.toPipedString = function (){ return this.join(" | "); }; return arr; } var colors = new SpecialArray("red","black","yellow","lightblue"); alert(colors.toPipedString()); // "red | black | yellow | lightblue";
稳妥构造函数模式
....奇妙的玩意