6.2创建对象
使用Object构造函数和对象字面量创建多个对象时,会产生大量重复代码,所以产生了各种模式
1:工厂模式
function createPerson(name,age,job){ var o = new Object(); o.name = name; o.sayName = function(){ alert(this.name); }; return o; } var person1 = createPerson("Nicholas",29,"Software Engineer");
优点:解决了创建多个相似对象的问题
缺点:没有解决对象识别的问题(怎样知道一个对象的类型)
2:构造函数模式
function CreatePerson(name,age,job){ this.name = name; this.say = function(){ alert(this.name); }; } var person1 = new createPerson("Nicholas",29,"Software Engineer");
//这里的new不是new Fuction对象,而是object对象
//var sum = new Function("num1","num2","return num1+num2");才是new一个Function对象 (见P110)
特点:①没有显式创建对象②直接将属性和方法赋给了this③没有return④有new⑤首字母大写(OO语言对于构造函数的习惯)
优点:解决了对象识别的问题
alert(person1 instanceof Object); //true alert(person1 instanceof Person); //true
①将构造函数当作普通函数
//当作构造函数使用 var person = new Person("Wang","29","Software"); person.sayName(); //作为普通函数使用 Person("Wang","29","Software"); //添加在window中 window.sayName(); //在另一个对象的作用域中调用 var o =new Object(); Person.call(o,"Wang","29","Software"); o.sayName();
②构造函数的缺点
//以这种方法创建的不同实例上的同名函数是不相等的 alert(person1.sayName == person2.sayName); //false //并且相同的方法在每个实例中都要重新创建很不好,所以采用下面的方法 function Person(name,age,job){ this.name = name; this.age = age; this.job = job; this.sayName = sayName; } function sayName(){ alert(this.name); } var person1 = new Person("Wang1",29,"student"); var person2 = new Person("Wang2",30,"student");
3:原型模式
var Person = function(name,age){ Person.prototype.name = "hehe"; Person.prototype.age = "23"; Person.prototype.sayName = function(){ alert(this.name); } } var person1 = new Person(); var person2 = new Person(); alert(person1.sayName == person2.sayName); //true
①无论什么时候只要创建一个新函数,就会为该函数创建一个prototype属性,这个属性指向函数的原型对象。
②原型对象最初只包含constructor属性——这个属性也是共享的,所以构造函数也可以通过对象实例访问。
③当为对象添加一个属性时,这个属性会屏蔽原型对象中保存的同名属性。
④使用delete操作符则可以完全删除实例属性,从而可以访问到原型中的属性。
delete person1.name;
⑤使用hasOwnProperty()方法对一个属性究竟是实例属性还是原型属性进行检测。
⑥in操作符的两个作用:
//①在单独使用时,in操作符会在对象能够访问给定属性时返回true(无论是实例属性还是原型属性) function Person(name,age){ }; Person.prototype.name="wang"; Person.prototype.sayName() = function(){ alert(this.name); } var person1 = new Person(); alert("name" in person1); //true //两个重点1:原型模式也是首字母大写 // 2:属性加双引号
//②在使用for-in循环时,返回的是所有能够通过对象访问的,可枚举的属性(包括实例和原型中) var o = { toString :function(){ return "My Name"; } }; for(var prop in o){ if(prop == "toString"){
alert("hehe");
} }
⑦除了for-in方法外,还有Object.key()方法可以用来枚举所有可枚举的实例属性——Object.keys() 方法会返回一个由给定对象的所有可枚举自身属性的属性名组成的数组,数组中属性名的排列顺序和使用for-in
循环遍历该对象时返回的顺序一致(两者的主要区别是 for-in 还会遍历出一个对象从其原型链上继承到的可枚举属性)。
⑧更简单的原型语法
Person.prototype = { name : "wang", age :"23", sayName : function () { alert(this.name); } } //这种写法的缺点是相当于重写了默认的prototype对象,即constructor属性指向了Object构造函数,如果需要constructor可以附加一条
Person.prototype = { constructor : Person, name : "wang", age :"23", sayName : function () { alert(this.name); } }
⑨原型的动态性
//当我们不用简单的原型语法覆盖prototype对象时,即使我们在创建实例之后修改原型,也可以准确找到
function Person(){
}
var friend = new Person(); Person.prototype.sayHi = function(){ alert("hi"); }; friend.sayHi();
//当用简单的原型语法时,如果在创建实例之后修改原型,那么会报错。只能在修改之后创建实例。
function Person(){
}
var friend = new Person(); Person.prototype = { name : "wang", age :"23", sayName : function () { alert(this.name); } }; Person.prototype.sayHi = function(){ alert("hi"); }; friend.sayHi();
总结6.2:
构造函数和原型模式混合的模式,是目前使用最广泛,认同度最高的一种创建自定义类型的方法!