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程序)改动时使用。