js面向对象-创建对象(模拟类)

101 阅读3分钟

js没有类的概念,js里万物皆是对象,对象是无序属性的集合,其属性可以包含基本值,对象或者函数

既然要面向对象编程,那肯定首先得有类,就像建房子需要砖头一样。但是js中es6之前其实是没有类的概念的,聪明的小伙伴们利用js的特性来模拟出来‘类’。常用的模拟类的模式有如下几种:

  • 工厂模式

function createUser(name) {
    let o = new Object();
    o.name = name;
    o.sayName = function() {
        alert(this.name)
    }
    return o;
}
let user = createUser('chenjz');

缺点: 无法识别对象类型(都是object),以及下面几种方式的缺点他好像都有...基本不会用,了解一下就好。

  • 构造器模式

function User(name) {
    this.name = name;
    this.sayName = function() {
        alert(this.name)
    }
}
let user = new User('chenjz');

优点: 可识别对象类型,user instanceOf User === true以及user.constructor === User缺点: 每次创建实例时都要重新创建一次funciton类型属性,如sayName方法,针对该模式缺点的优化,可以把sayName这个方法提取为公共方法,如:

function User(name) {
    this.name = name;
    this.sayName = sayName;
}
function sayName = function() {
    alert(this.name)
}
let user = new User('chenjz');

实际运用中不可能这么写的,该模式也基本不会用。

  • 原型模式

function User() {
}
User.prototype.name = 'chenjz';
User.prototype.sayName = function() {
    alert(this.name)
}

优点: 所有使用该方式创建的实例对象共享属性和方法。 缺点: 1.没有构造器环节,实例无法设置初始值;2.如果一个实例修改了原型引用,所有的实例都会受影响。

  • 混合模式(构造器模式 + 原型模式)

function User(name) {
    // 这边就可以起到初始化实例的效果
    this.name = name;
}
User.prototype.sayName = function() {
    alert(this.name)
}

基本用这种方式就足够完善了,实际运用中也大多使用的这一种,如果你用babel编译es6中的class,你会发现编译出来的代码就是类似这样的。

  • 动态原型模式

function User(name) {
    this.name = name;
    // 这样写sayName方法在原型对象中只会定义一次
    if (typeof this.sayName !== 'function') {
        User.prototype.sayName = function() {
            alert(this.name)
        }
    }
}

相当于把原型函数定义在函数体内,封装性更高一点,区别不大。

  • 寄生构造函数模式

function SpecialArray() {
    var values = new Array()
    values.push.apply(this, arguments)
    //添加特殊方法
    values.toPipedString = function(){ 
        return this.join("|"); 
    };
    return values;
}
var colors = new SpecialArray("red", "blue", "green"); 
alert(colors.toPipedString()); //"red|blue|green"

这个代码看起来和工厂模式一模一样,只是它是通过new关键词来调用的,主要用来创建一些特殊的对象,比如上例就是创建一个特殊的数组对象。

  • 稳妥构造函数模式

function Person(name, age, job) {
    let o = new Object();
    //可以在这里定义私有变量和函数

    //只有sayName方法能访问到name
    o.sayName = function() {
            alert(name)
    }
    return o;
}
var friend = Person("Nicholas", 29, "Software Engineer"); 
friend.sayName(); //"Nicholas"

通过直接调用函数获取一个稳妥对象,而除了调用 sayName()方法外,没有别的方式可以访问其数据成员。即使有其他代码会给这个对象添加方法或数据成员,但也不可能有别的办法访问传入到构造函数中的原始数据。稳妥构造函数模式提供的这种安全性,使得它非常适合在某些安全执行环境(这些环境中会禁止使用 this 和 new),或者在防止数据被其他应用程序(如 Mashup程序)改动时使用。