JavaScript基础知识整理(ES5创建对象)
创建对象
我们开始可以用Object构造函数或者对象字面量来快速创建对象,但使用这种方式创建多个对象时会产生大量重复代码,所以我们有了以下几种创建对象的方式。
(1)工厂模式
function createPerson(name, age,sex){ //传入的参数可以类比成送入工厂的原材料 var o = new Object(); o.name = name; o.age = age; o.sex = sex;
o.sayName(){
alert(this.name);
}
return o; //返回出的对象可以类比成工厂加工完成的产品 } var person1 = createPerson("Jack",18,"男"); var person2 = createPerson("Rose",18,"女");
当我们使用工厂模式的函数时,并不知道自己所创建的是哪一类对象,也就是说对象之间的辨识度太低,在这基础上我们有了构造函数模式。
(2)构造函数模式
function Person(name, age,sex){ this.name = name; //这里的this在创建对象时会指向新创建的对象 this.age = age; this.sex = sex; this.sayName = function{ alert(this.name); } } var person1 = new Person("Jack",18,"男"); var person2 = new Person("Rose",18,"女");
构造函数名可以作为对象的标识符,这样对象的辨识度便上升了。
因为在定义函数时会创建新的Function实例,每一个对象实例的同名方法不是同一个Function实例,每创建一个实例会新创建一个Function实例,这无疑会增加不必要的开销。针对这一点,
我们可以把函数定义在对象外部。
function Person(name, age,sex){ this.name = name; this.age = age; this.sex = sex; this.sayName = sayName; } function sayName(){ alert(this.name); } var person1 = new Person("Jack",18,"男"); var person2 = new Person("Rose",18,"女");
但是当对象有许多方法需要定义时,我们又会发现需要在全局范围定义许多全局方法,我们就离封装代码的目的越走越远了,所以我们又有了原型模式。
(3)原型模式
function Person(){ } Person.prototype.name = "Jack"; Person.prototype.age = 18; Person.prototype.sex = "男"; Person.prototype.sayName = function(){ alert(this.name); } var person1 = new Person(); person1.sayName();//"Jack" 开始搜索实例的内部是否有该方法,没有的场合会开始搜索实例的原型对象 var person2 = new Person(); person2.sayName();//"Jack" alert(person1.sayName == person2.sayName);//true
因为prototype出现了很多次我们也可以这样写
function Person(){ } Person.prototype = {
constructor:Person, //这里的constructor属性会变成可枚举的,默认情况下是不枚举的,可以用Object.defineProperty() name:"Jack", age:18, sex:"男", sayName:function(){ alert(this.name); } }
原型模式对于对象函数的共享非常友好,但因为每个对象的所有属性和方法都是公开的,当修改某个实例的属性时,其他实例的属性也会跟着一起改变,换句话说,实例彼此之间的相关性太大,所以我们可以组合使用构造函数模式和原型模式。用构造函数模式来定义实例属性,用原型模式来定义方法和共享的属性。
(4) 构造函数和原型模式组合使用
function Person(name, age,sex){ this.name = name; this.age = age; this.sex = sex; this.friend = ["Jack","Rose"]; } Person.prototype = { constructor : Person, sayName : function(){ alert(this.name); } }
当我们想把构造函数和原型写在一起时,可以使用动态原型模式。
(5)动态原型模式
function Person(name, age,sex){ this.name = name; this.age = age; this.sex = sex; if(typeof this.sayName != 'function'){ //通过这种写法,我们不会重复定义函数 Person.prototype.sayName = function(){ alert(this.name); }; } }
(6)寄生构造函数模式
function Person(name, age,sex){ var o = new Object(); //在典型构造函数模式中是直接把属性保存在this,这里新创建了一个对象 o.name = name; o.age = age; o.sex = sex; o.sayName = function(){ alert(this.name); } return o; //这里和工厂模式又有相似之处,区别在于实例的创建 } var person = new Person("Jack",18,"男"); //表面上是构造的Person对象,实际上是创建的Object类型的对象实例。 person.sayName();//"Jack"
寄生构造函数模式可以创建某个对象的加强版对象
function specialArray(){ var values = new Array(); values.push.apply(values,arguments)//将传来的参数装进数组 values.toPipedString = function(){ values.join('|'); } return values } var cities = new specialArray("Shanghai","Beijing","Guangzhou"); alert(cities.toPipedString());//"Shanghai|Beijing|Guangzhou"
(7)稳妥构造函数模式
稳妥对象指的是没有共有属性,并且方法中不出现this的对象
function Person(name, age,sex){ var o = new Object(); o.sayName = function(){ //只能通过此方法改变属性值 return name; } return o; }