为了账号安全,请及时绑定邮箱和手机立即绑定

JavaScript创建对象总结(上)

在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个步骤

  1. 创建一个新对象
  2. 将构造函数的作用于赋给新对象(因此this指向了这个新对象)
  3. 执行构造函数中的代码(为这个新对象添加属性)
  4. 返回这个新对象

既然说到了构造函数,那自然要说说它的返回值。这其中分三种情况。

①: 没有指明具体的返回值,则返回该构造函数的实例化对象

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()函数只能被某个对象调用,这明显就是名不副实,而且上面只有一个方法还好,但是你要添加多少个方法,就要创建多少个全局函数。
这个时候就要原型模式出场了。

由于原型模式内容较多,并且较复杂,我们在下篇中讲解。

点击查看更多内容
4人点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消