之前说过ES6引入class(类)这个概念,那我们赶快来学习一番吧。
http://es6.ruanyifeng.com/#docs/class 这是阮一峰老师的ES6入门书,我觉得是学习ES6必看的书,而且它在网络开源,非常了不起,给阮一峰老师点赞。
这篇文章就是阅读上面文章的简单笔记,话不多说开始。
怎么使用class?
//定义类
class Point {
constructor(x, y) {
this.x = x;
this.y = y;
}
toString() {
return '(' + this.x + ', ' + this.y + ')';
}
}
可以看到每个class都有一个constructor(构造函数),使用new操作会默认调用construcor生成实例。
下面可以看到 toString()不用再加: 和 function,大括号直接写函数定义。
class Point {
// ...
}
typeof Point // "function"
Point === Point.prototype.constructor // true
这段代码表示类的数据类型就是函数,类的constructor指向类自身。
class Point {
constructor() {
// ...
}
toString() {
// ...
}
toValue() {
// ...
}
}
// 等同于
Point.prototype = {
constructor() {},
toString() {},
toValue() {},
};
阮老师进一步揭示类的方法都是定义在的类的原型上(这就如同原型模式一样)。
因此,我们使用Object.assgin()可以一次为对象添加多种方法
class Point {
constructor(){
// ...
}
}
Object.assign(Point.prototype, {
toString(){},
toValue(){}
});
类必须包括constructor,否则JavaScript会为它创建一个空的constructor
类与普通构造函数一个主要区别在于,类必须由new调用,自己不能执行,而普通构造函数能自己执行
class Foo {
constructor() {
return Object.create(null);
}
}
Foo() // error
实例显示定义在其自身,否则都是定义在原型上(即定义在class上)。
//定义类
class Point {
constructor(x, y) {
this.x = x;
this.y = y;
}
toString() {
return '(' + this.x + ', ' + this.y + ')';
}
}
var point = new Point(2, 3);
point.toString() // (2, 3)
point.hasOwnProperty('x') // true
point.hasOwnProperty('y') // true
point.hasOwnProperty('toString') // false
point.__proto__.hasOwnProperty('toString') // true
再复习一次__proto__是实例的一个属性,指向构造函数或者class的原型。在这里,阮老师更深入介绍了这个属性。
_proto_ 并不是语言本身的特性,这是各大厂商具体实现时添加的私有属性,虽然目前很多现代浏览器的 JS 引擎中都提供了这个私有属性,但依旧不建议在生产中使用该属性,避免对环境产生依赖。生产环境中,我们可以使用 Object.getPrototypeOf 方法来获取实例对象的原型,然后再来为原型添加方法/属性。
var p1 = new Point(2,3);
var p2 = new Point(3,2);
p1.__proto__.printName = function () { return 'Oops' };
p1.printName() // "Oops"
p2.printName() // "Oops"
var p3 = new Point(4,2);
p3.printName() // "Oops"
上面代码,表明可以通过实例的__proto__为类添加方法,因为它指向class的prototype啊。
class的表达式
const MyClass = class Me {
getClassName() {
return Me.name;
}
};
注意这个类名是叫Myclass。me的作用就是替代this而已。
采用 Class 表达式,可以写出立即执行的 Class。
let person = new class {
constructor(name) {
this.name = name;
}
sayName() {
console.log(this.name);
}
}('张三');
person.sayName(); // "张三"
类不会有变量提升
{
let Foo = class {};
class Bar extends Foo {
}
}
上面的代码不会报错,因为Bar继承Foo的时候,Foo已经有定义了。但是,如果存在class的提升,上面代码就会报错,因为class会被提升到代码头部,而let命令是不提升的,所以导致Bar继承Foo的时候,Foo还没有定义。
类的私有属性
很遗憾,ES6不提供。阮老师提到一种使用symbol的方法来模拟实现。因为我不懂symbol,日后再来介绍,先放代码。
const bar = Symbol('bar');
const snaf = Symbol('snaf');
export default class myClass{
// 公有方法
foo(baz) {
this[bar](baz);
}
// 私有方法
[bar](baz) {
return this[snaf] = baz;
}
// ...
};
暂时先介绍到这里,后面一些内容有点难,我需要整理一下。