JavaScript 语言中,生成实例对象的传统办法是通过构造函数
class Point {// ...}
typeof Point // "function"
Point === Point.prototype.constructor // true
下面代码表明,类的数据类型就是函数,类自身就指向构造函数
应用的时候,也是间接对类应用 new 命令,跟构造函数的用法完全一致。
类的实例对象
class Bar {doStuff() {console.log('stuff');
}
}
var b = new Bar();
b.doStuff() // "stuff"
构造函数的 prototype 属性,在 ES6 的“类”下面持续存在。事实上,类的所有办法都定义在类的 prototype 属性下面。
class Point {constructor() {// ...}
toString() {// ...}
toValue() {// ...}
}
// 等同于
Point.prototype = {constructor() {},
toString() {},
toValue() {},
};
在类的实例下面调用办法,其实就是调用原型上的办法。
类必须应用 new 调用,否则会报错。这是它跟一般构造函数的一个次要区别,后者不必 new 也能够执行。
与 ES5 一样,类的所有实例共享一个原型对象。
var p1 = new Point(2,3);
var p2 = new Point(3,2);
p1.__proto__ === p2.__proto__
//true
下面代码中,p1 和 p2 都是 Point 的实例,它们的原型都是 Point.prototype,所以__proto__属性是相等的。
这也意味着,能够通过实例的__proto__属性为“类”增加办法。
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"
下面代码在 p1 的原型上增加了一个 printName 办法,因为 p1 的原型就是 p2 的原型,因而 p2 也能够调用这个办法。而且,尔后新建的实例 p3 也能够调用这个办法。这意味着,应用实例的__proto__属性改写原型,必须相当审慎,不举荐应用,因为这会扭转“类”的原始定义,影响到所有实例
Class 表达式
与函数一样,类也能够应用表达式的模式定义。
const MyClass = class Me {getClassName() {return Me.name;}
};
下面代码应用表达式定义了一个类。须要留神的是,这个类的名字是 MyClass 而不是 Me,Me 只在 Class 的外部代码可用,指代以后类。
let inst = new MyClass();
inst.getClassName() // Me
Me.name // ReferenceError: Me is not defined
下面代码示意,Me 只在 Class 外部有定义。
如果类的外部没用到的话,能够省略 Me,也就是能够写成上面的模式。
const MyClass = class {/ … / };
采纳 Class 表达式,能够写出立刻执行的 Class。
let person = new class {constructor(name) {this.name = name;}
sayName() {console.log(this.name);
}
}('张三');
person.sayName(); // "张三"
下面代码中,person 是一个立刻执行的类的实例。
不存在变量晋升
类不存在变量晋升(hoist),这一点与 ES5 齐全不同。ES6 不会把类的申明晋升到代码头部。这种规定的起因与下文要提到的继承无关,必须保障子类在父类之后定义。
附件下载:http://github.crmeb.net/u/defu