//定義類class Point { constructor(x, y) { this.x = x; this.y = y; } toString() { return '(' + this.x + ', ' + this.y + ')'; }}
class Rectangle { constructor(height, width) { this.height = height; this.width = width; }}
var obj = new Myclass(); //報錯class Myclass (){ }
{ let B = class {}; // let 聲明 不存在函數提高 class A extends B { //若是存在類哈函數提高的話,這行會提高到第一行,父親還沒聲明,兒子怎麼繼承? } }
class f1 {}; class f1 {}; var f2 = class {}; class f2 {}; // 報錯了 class f3 {}; var f3 = class {}; // 報錯了 var f4 = class {}; var f4 = class {}; // 若是兩個函數表達式重名了,那麼不會報錯
var myClass = class [className] [extends] { // class body}
// 方式一const MyClass = class {};// 方式二:給出類名const MyClass = class Me { getClassName() { return Me.name; }};
var Foo = class { constructor() {} bar() { return 'Hello World!'; }};var instance = new Foo();instance.bar(); // "Hello World!"Foo.name; // "Foo"
var Foo = class NamedFoo { constructor() {} whoIsThere() { return NamedFoo.name; }}var bar = new Foo();bar.whoIsThere(); // "NamedFoo"NamedFoo.name; // ReferenceError: NamedFoo is not definedFoo.name; // "NamedFoo"
let person = new class { constructor(name) { this.name = name; } sayName() { console.log(this.name); }}('Zhang San');person.sayName(); // Zhang San
一個類只能擁有一個名爲constructor
的方法(不然會報錯),一個類的 constructor 方法只有在實例化的時候被調用。javascript
若是沒有顯式定義constructor
方法,這個方法會被默認添加,即,無論有沒有顯示定義,任何一個類都有constructor
方法。
html
子類必須在constructor方法中調用super
方法,不然新建實例時會報錯。由於子類沒有本身的this
對象,而是繼承父類的this
對象,而後對其進行加工,若是不調用super
方法,子類就得不到this
對象。
java
class Point {}class ColorPoint extends Point { constructor() {}}let cp = new ColorPoint(); // ReferenceError
ColorPoint
繼承了父類
Point
,可是它的構造函數沒有調用
super
方法,致使新建實例時報錯。
定義類的方法時,方法名前面不須要加上function
關鍵字。另外,方法之間不須要用逗號分隔,加了會報錯。es6
class Bar { constructor() {} doStuff() {} toString() {} toValue() {}}
Bar.prototype = { doStuff() {}, toString() {}, toValue() {}};
prototype
上面,因此類的新方法能夠添加在
prototype
對象上面。
Object.assign
方法能夠很方便地一次向類添加多個方法。
class Point { constructor() { // ... }}Object.assign(Point.prototype, { toString() {}, toValue() {}});
class Point { constructor(x, y) { // ... } toString() { return '(' + x + ', ' + y + ')'; }}Object.keys(Point.prototype); // []Object.getOwnPropertyNames(Point.prototype); // ["constructor", "toString"]Object.getOwnPropertyDescriptor(Point, 'toString');// Object {writable: true, enumerable: false, configurable: true}
static
關鍵字用來定義類的靜態方法。靜態方法是指那些不須要對類進行實例化,使用類名就能夠直接訪問的方法。靜態方法常常用來做爲工具函數。
class Point { constructor(x, y) { this.x = x; this.y = y; } static distance(a, b) { const dx = a.x - b.x; const dy = a.y - b.y; return Math.sqrt(dx*dx + dy*dy); }}const p1 = new Point(5, 5);const p2 = new Point(10, 10);console.log(Point.distance(p1, p2));
靜態方法不能夠被實例繼承,是經過類名直接調用的。可是,父類的靜態方法能夠被子類繼承。express
class Foo { static classMethod() { return 'hello'; }}class Bar extends Foo {}Bar.classMethod(); // "hello"
extends
關鍵字用於實現類之間的繼承。子類繼承父類,就繼承了父類的全部屬性和方法。 extends
後面只能夠跟一個父類。babel
class ColorPoint extends Point { constructor(x, y, color) { super(x, y); // 調用父類的constructor(x, y) this.color = color; } toString() { return this.color + ' ' + super.toString(); // 調用父類的toString() }}
extends
關鍵字不能用於繼承一個對象,若是你想繼承自一個普通的對象,你必須使用 Object.setPrototypeof ( )
//先來個父類,帶些屬性 function Super(){ this.flag = true; } //爲了提升複用性,方法綁定在父類原型屬性上 Super.prototype.getFlag = function(){ return this.flag; } //來個子類 function Sub(){ this.subFlag = false; } //實現繼承 Sub.prototype = new Super; //給子類添加子類特有的方法,注意順序要在繼承以後 Sub.prototype.getSubFlag = function(){ return this.subFlag; } //構造實例 var es5 = new Sub;
function Super(){ this.flag = true; } Super.prototype.getFlag = function(){ return this.flag; //繼承方法 } function Sub(){ this.subFlag = flase Super.call(this) //繼承屬性 } Sub.prototype = new Super; var obj = new Sub(); Sub.prototype.constructor = Sub; Super.prototype.getSubFlag = function(){ return this.flag; }
Sub.prototype.constructor = Sub;
function _inherits(subClass, superClass) { // 確保superClass爲function if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } // 把子類.prototype 繼承了父類.prototype(new 父類), 同時把子類prototype的constructor進行了重寫; // 給subClass添加constructor這個屬性 subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); // 將父類設爲子類的prototype if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass;}
子類.prototype = new 父類
function Car (desc) { this.desc = desc; this.color = "red";} Car.prototype = { getInfo: function() { return 'A ' + this.color + ' ' + this.desc + '.'; }};//instantiate object using the constructor functionvar car = Object.create(Car.prototype);car.color = "blue";alert(car.getInfo()); //displays 'A blue undefined.' ??! // 看見了吧,只會繼承方法,不能繼承屬性
var Car2 = Object.create(null); //this is an empty object, like {}Car2.prototype = { getInfo: function() { return 'A ' + this.color + ' ' + this.desc + '.'; }}; var car2 = Object.create(Car2.prototype, { //value properties color: { writable: true, configurable:true, value: 'red' }, //concrete desc value rawDesc: { writable: false, configurable:true, value: 'Porsche boxter' }, // data properties (assigned using getters and setters) desc: { configurable:true, get: function () { return this.rawDesc.toUpperCase(); }, set: function (value) { this.rawDesc = value.toLowerCase(); } }}); car2.color = 'blue';alert(car2.getInfo()); //displays 'A RED PORSCHE BOXTER.'
var _this = _possibleConstructorReturn(this, (b.__proto__ || Object.getPrototypeOf(b)).call(this));
class A extends Object {}A.__proto__ === Object // trueA.prototype.__proto__ === Object.prototype // true
class A {}A.__proto__ === Function.prototype // trueA.prototype.__proto__ === Object.prototype // true
class C extends null { constructor() { return Object.create(null); }}
class A extends B {}A.__proto__ === B; //繼承屬性A.prototype.__proto__ === B.prototype; //繼承方法
子類.prototype = Object.create (父類.prototype) // 至關於 new 父類
if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass;
var p1 = new Point(2,3);var p2 = new Point(3,2);p1.__proto__ === p2.__proto__
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"
super
關鍵字能夠用來調用其父類的構造器或方法。super 做爲方法的時候,必須在 constructor 中調用,而且只能在 constructor 裏面被調用app
class Cat { constructor(name) { this.name = name; } speak() { console.log(this.name + ' makes a noise.'); }}class Lion extends Cat { speak() { super.speak(); console.log(this.name + ' roars.'); }}
class A { p() { return 2; }}class B extends A { constructor() { super(); console.log(super.p()); // 2 }}let b = new B();
class A { constructor() { this.x = 1; } print() { console.log(this.x); }}class B extends A { constructor() { super(); this.x = 2; } m() { super.print(); }}let b = new B();b.m() // 2
class A { constructor() { this.x = 1; }}class B extends A { constructor() { super(); this.x = 2; super.x = 3; console.log(super.x); // undefined console.log(this.x); // 3 }}let b = new B();
class Parent { static myMethod(msg) { console.log('static', msg); } myMethod(msg) { console.log('instance', msg); }}class Child extends Parent { static myMethod(msg) { super.myMethod(msg); } myMethod(msg) { super.myMethod(msg); }}Child.myMethod(1); // static 1var child = new Child();child.myMethod(2); // instance 2
class A {}class B extends A { constructor() { super(); console.log(super); // 報錯 }}
與ES5同樣,在類內部可使用get
和set
關鍵字,對某個屬性設置取值和賦值方法。函數
class Foo { constructor() {} get prop() { return 'getter'; } set prop(val) { console.log('setter: ' + val); }}let foo = new Foo();foo.prop = 1;// setter: 1foo.prop;// "getter"
prop
屬性有對應 的賦值和取值方法,所以賦值和讀取行爲都被自定義了。
var descriptor = Object.getOwnPropertyDescriptor(Foo.prototype, 'prop');"get" in descriptor // true"set" in descriptor // true
prop
屬性的描述對象上的,這與ES5一致。
若是類的某個方法名前加上星號(*
),就表示這個方法是一個Generator函數。工具
class Foo { constructor(...args) { this.args = args; } * [Symbol.iterator]() { for (let arg of this.args) { yield arg; } }}for (let x of new Foo('hello', 'world')) { console.log(x);}// hello// world
for...of
循環會自動調用這個遍歷器。
function Person(name) { if (new.target !== undefined) { this.name = name; } else { throw new Error('必須使用new生成實例'); }}// 另外一種寫法function Person(name) { if (new.target === Person) { this.name = name; } else { throw new Error('必須使用new生成實例'); }}var person = new Person('張三'); // 正確var notAPerson = Person.call(person, '張三'); // 報錯
class Rectangle { constructor(length, width) { console.log(new.target === Rectangle); // ... }}class Square extends Rectangle { constructor(length) { super(length, length); // 至關於執行父類中的constructor, }}var obj = new Square(3); // 輸出 false
class Shape { constructor() { if (new.target === Shape) { throw new Error('本類不能實例化'); // 拋出一個錯誤 } }}class Rectangle extends Shape { constructor(length, width) { super(); // ... }}var x = new Shape(); // 報錯var y = new Rectangle(3, 4); // 正確