JavaScript——创建对象
Object构造函数或对象字面量都可以用来创建单个对象,但是有缺点:使用同一接口创建很多对象,会产生大量的重复代码。
创建对象的方式大致有以下7种:
1.工厂模式
2.构造函数模式
3.原型模式
4.组合使用构造函数模式和原型模式
5.动态原型模式
6.寄生构造函数模式
7.稳妥构造函数模式
下面一一介绍
1.工厂模式
eg:
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("chenxiaoming",18,"Web dev"); //创建实例不需要用到new
var person1 = createPerson("chenxiaoming",18,"Student");
可以无数次调用这个函数,而每次返回一个包含三个属性和一个方法的对象。解决了创建多个相似对象的问题,但却没有解决对象识别的问题(instanceof)。
2.构造函数模式
使用构造函数模式重写上面例子
eg:
function Person(name, age, job){ //约定俗成,大写字母开头
this.name = name;
this.age = age;
this.job = job;
this.sayName = function(){
alert(this.name);
};
}
var person1 = new Person("chenxiaoming",18,"Web dev");
var person2 = new Person("chenxiaoming",18,"Student");
与工厂模式大致相同,不同之处:
a.没有显示的创建对象
b.直接将属性和方法赋给了this对象
c.没有return语句
以这种方式调用构造函数实际上经历以下4个步骤:
a.创建一个新对象
b.将构造函数的作用域赋给新对象(因此this就指向这个新对象)
c.执行构造函数中的代码(为新对象添加属性)
d.返回新对象
person1和person2分别保存着Person的一个不同的实例。这两个对象都有一个constructor(构造函数)属性,该属性指向Person。同时也是Object的实例。
console.log(person1.constructor == Person); //true
console.log(person2.constructor == Person); //true
console.log(person1.constructor == Object); //true
console.log(person2.constructor == Object); //true
之所以是Object的实例,是因为所有对象均继承自Object。
对象的constructor属性最初是用来标识对象类型的。可以使用instanceof操作符来检测对象类型。
创建自定义的构造函数可以将它的实例标识为一种特定的类型。
a.将构造函数当作函数
构造函数与其他函数的唯一区别,就在于调用它们的方式不同。
任何函数,只要通过new操作符来调用,那它就可以作为构造函数;而任何函数,如果不通过new操作符来调用,那它跟普通函数也不会有什么两样。
构造函数可以通过以下三种方式调用:
//当做构造函数使用
var person = new Person("chenxiaoming", 18, "Web dev");
person.sayName(); //chenxiaoming
//作为普通函数调用
Person("chenxiaoming", 18, "Web dev"); //添加到window
window.sayName(); //chenxiaoming
//在另一个对象的作用域中调用
var o = new Object();
Person.call(o, "chenxiaomiing", 18, "Web dev");
o.sayName(); //chenxiaoming
b.构造函数的问题
每个方法都要在每个实例上重新创建一遍。上面所创建量person1和person2实例中的方法不是同一个Function实例。
console.log(peson1.sayName == person2.sayName); //false
以这种方式创建函数,会导致不同的作用域链和标识符解析。
不同实例上的同名函数是不相等的。
通过把函数定义转移到构造函数外部来解决这个问题。
function Person(name, age, job){
this.name = name;
this.age = age;
this.job = job;
this.sayName = sayName; //指向函数sayName
}
function sayName(){
console.log(this.name);
}
var person1 = new Person("chenxiaoming", 18, "Web dev");
var person2 = new Person("chenxiaoming", 18, "Student");
在例子中,我们讲sayName()函数的定义转移到了构造函数外部。而在构造函数内部,我们将sayName属性设置成等于全局的sayName函数。
缺点:全局作用域中定义的函数只能被某个对象调用。遇到需要定义多个全局函数的自定义引用类型,封装性就比较差。通过原型模式能比较好的解决构造函数的缺点。
注:原型模式比较重要,在后面花一节整理笔记。
以上笔记整理自《JavaScript权威指南》/《JavaScript高级程序设计(第三版)》,用做个人学习分享