JavaScript 定义 class 的方式

自从转了 iOS 写 JavaScript 就越来越少了,即使写也没有复杂到要定义个类。我一直知道 JavaScript 也支持定义 class 了,但是直到前两天才偶然看到了 JavaScript 定义 class 的语法,我惊奇地发现写法居然和我的 $class.js 不能说一毛一样,但实在是太像了!

zszz,早期的 JavaScript 是不支持定义 class 的,要拿 functionprototype 组装。画风大概是这样的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
function Person(name) {
this.name = name;
this.friends = [];
}

Person.prototype = {
makeFriend: function(person) {
this.friends.push(person.name);
}
};

function Student(name, grade) {
// super.constructor()
Person.apply(this, arguments);
this.grade = grade;
}

Student.prototype = new Person();
Student.prototype.makeFriend = function(person) {
// super.makeFriend()
Person.prototype.makeFriend.apply(this, arguments);
};

var ming = new Person("ming")
nina = new Person("nina");

ming.makeFriend(nina);
nina.makeFriend(ming);

console.log(ming.friends); // ['nina']
console.log(nina.friends); // ['ming']

很丑!所以当时很多框架都给出了不同形式的封装,但是没有一个我喜欢的,比如现在唯一能想到的 Prototype(停更于 2015 年)使用实现 都没好到哪去。并且我倾向于写原生的 JavaScript,于是自己写了一个 $class.js

最初 1.0 版本的 $class.js 极其精简,只有 4 行代码!但很好地满足了核心需求:

1
2
3
4
5
this.$class = function(src) {
src.constructor.prototype = src;
return src.constructor;
};

$class.js 1.0 的使用,看起来是不是好多了:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
var Person = $class({
constructor: function(name) {
this.name = name;
this.friends = [];
},
makeFriend: function(person) {
this.friends.push(person.name);
}
});

var ming = new Person("ming")
nina = new Person("nina");

ming.makeFriend(nina);
nina.makeFriend(ming);

console.log(ming.friends); // ['nina']
console.log(nina.friends); // ['ming']

后来 2.0 版本的 $class.js 支持了继承、以及调用父类构造方法和方法,代码依然不算多:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
this.$class = function $class(source, SuperClass) {

SuperClass = SuperClass || Object;
source = source || {};
source.constructor = source.hasOwnProperty("constructor") ? source.constructor : function() {
SuperClass.apply(this, arguments);
};

var Class = source.constructor;
Class.prototype = new SuperClass();
for (var each in source) {
Class.prototype[each] = source[each]; // include `constructor`
}

return Class;
};

$class.js 2.0 的使用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
var Person = $class({
constructor: function(name) {
this.name = name;
this.friends = [];
},
makeFriend: function(person) {
this.friends.push(person.name);
}
});

var Student = $class({
constructor: function(name, grade) {
// super.constructor()
Person.apply(this, arguments);
this.grade = grade;
},
makeFriend: function(person) {
// super.makeFriend()
Person.prototype.makeFriend.apply(this, arguments);
}
}, Person);

var ming = new Person("ming")
nina = new Student("nina");

ming.makeFriend(nina);
nina.makeFriend(ming);

console.log(ming.friends); // ['nina']
console.log(nina.friends); // ['ming']

JavaScript 定义 class 的写法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
const Person = class {
constructor(name) {
this.name = name;
this.friends = [];
}
makeFriend(person) {
this.friends.push(person.name);
}
};

const Student = class extends Person {
constructor(name, grade) {
// super constructor
super(...arguments);
this.grade = grade;
}
makeFriend(person) {
// super method
super.makeFriend(...arguments);
}
}

var ming = new Person("ming")
nina = new Student("nina");

ming.makeFriend(nina);
nina.makeFriend(ming);

console.log(ming.friends); // ['nina']
console.log(nina.friends); // ['ming']

所以我想说的是:我对代码的品味好像还可以,昂 😎