在JavaScript中对象被定义为无序属性的集合,其属性值可以是基本值、对象或者函数。
在这一系列文章我们将介绍
- 工厂模式
- 构造函数模式
- 原型模式
- 组合使用构造函数模式和原型模式
- 动态原型模式
- 寄生构造函数模式
- 稳妥构造函数模式
我们知道创建对象可以使用 Object构造函数 或者 字面量的形式 创建单个对象,但是这样会产生大量重复的代码。
// Object构造函数
var obj = new Object();
// 字面量
var obj = {};
// 例如我们要记录小明跟小红的姓名跟年龄
var xiaoming = {
name: "xiaoming",
age: 11
};
var xiaohong = {
name: "xiaohong",
age: 10
};
很明显上面例子代码重复,要是记录的信息多一点,代码重复率则越高,为了解决这个问题,就有了工厂模式
function createPerson(name, age) {
var person = {
name: name,
age: age,
getName: function() {
console.log(this.name);
}
};
return person;
}
var xiaoming = createPerson("xiaoming", 11);
xiaoming.getName() // xiaoming
但是工厂模式无法解决对象识别的问题,其实是无法辨认实例是由哪个构造函数创建
console.log(xiaoming instanceof createPerson); // false
console.log(xiaoming instanceof Object); // true
为了解决这个问题就有了构造函数模式
// 按照惯例,构造函数以大写字母开头,以区别普通函数。
function Person(name) {
this.name = name;
this.getName = function() {
console.log(this.name);
};
}
var xiaoming = new Person("xiaoming");
xiaoming.getName(); // xiaoming
// 成功解决工厂模式问题
console.log(xiaoming instanceof Person); // true
之所以成为构造函数是因为 new 操作符,要创建构造函数实例就必须使用 new 操作符,并且经历以下4个步骤
- 创建一个新对象
- 将构造函数的作用于赋给新对象(因此this指向了这个新对象)
- 执行构造函数中的代码(为这个新对象添加属性)
- 返回这个新对象
既然说到了构造函数,那自然要说说它的返回值。这其中分三种情况。
①: 没有指明具体的返回值,则返回该构造函数的实例化对象
function Person(name) {
this.name = name;
this.getName = function() {
console.log(this.name);
};
}
var xiaoming = new Person("xiaoming");
console.log(xiaoming);
②:若指明返回值,但不是引用类型 的话,与情况①结果相同,返回该构造函数的实例化对象。
function Person(name) {
this.name = name;
this.getName = function() {
console.log(this.name);
};
return 12;
}
var xiaoming = new Person("xiaoming");
console.log(xiaoming);
③:若指明返回值且是引用类型,则返回该引用类型
function Person(name) {
this.name = name;
this.getName = function() {
console.log(this.name);
};
return {
age: 12
};
}
var xiaoming = new Person("xiaoming");
console.log(xiaoming);
接下来,我们来看下构造模式与工厂模式的不同
- 构造函数没有很明显的创建对象
- 构造函数志军讲属性跟方法赋给了this
- 没有return语句
感觉构造函数很厉害?其实它与普通函数没有什么区别,只有用new操作符,它才是构造函数
// 函数调用方式
function Person(name) {
this.name = name;
this.getName = function() {
console.log(this.name);
};
}
// 构造函数调用
var xiaoming = new Person("xiaoming");
xiaoming.getName(); // xiaoming
// 普通函数调用
Person("xiaohong");
window.getName(); // xiaohong
// 此时this指向全局window,若不懂可阅读我的手记《JavaScript迷之this总结》
// 在另一个对象中调用
var obj = {};
Person.call(obj, "xiaodong");
obj.getName(); // xiaodong
但是构造函数虽然好,但也会带来一定的问题:构造函数中的方法在每一个实例都会被重新创建。
function Person(name) {
this.name = name;
this.getName = function() {
console.log(this.name);
};
}
var xiaoming = new Person("xiaoming");
var xiaohong = new Person("xiaohong");
console.log(xiaoming.getName == xiaohong.getName); // false
在上面例子中创建两个完成相同功能的实例方法完全没有必要,所以你可能会这么解决。
function Person(name) {
this.name = name;
this.getName = getName;
}
function getName() {
console.log(this.name);
}
var xiaoming = new Person("xiaoming");
var xiaohong = new Person("xiaohong");
console.log(xiaoming.getName == xiaohong.getName); // true
上面例子将getName()函数定义为全局函数,使其成为window的属性,而在Person构造函数内部的getName属性设置成全局函数getName(),这样getName属性的属性值就是一个指向全局getName()函数的指针,因此来解决构造函数的问题。
但是(不好的预感)你看下全局函数getName()函数只能被某个对象调用,这明显就是名不副实,而且上面只有一个方法还好,但是你要添加多少个方法,就要创建多少个全局函数。
这个时候就要原型模式出场了。
由于原型模式内容较多,并且较复杂,我们在下篇中讲解。
热门评论
js中为什么要创建对象,或者说创建的对象用来干什么?
怎么 不可以收藏 怎么 不可以收藏 怎么 不可以收藏 怎么 不可以收藏 怎么 不可以收藏 怎么 不可以收藏 怎么 不可以收藏 怎么 不可以收藏 怎么 不可以收藏 怎么 不可以收藏 怎么 不可以收藏 怎么 不可以收藏 怎么 不可以收藏 怎么 不可以收藏 怎么 不可以收藏