class
在ES5中,
function Person(name,age){
this.name=name;
this.age=age;
}
Person.prototype.showName=function(){
console.log(this.name+","+this.age) ;
}
var s=new Person("op",20);
s.showName();
function Student(cose){
this.cose=cose;
this.showCode=function(){
console.log("hello"+cose);
}
}
var s1=new Student('for');
s1.showCode();
Student.prototype=new Person('some',18);//繼承
在ES6中,
let show='showAge';
class Person{
constructor(name,age){
this.name=name;
this.age=age;
}
showName(){
console.log(this.name+this.age);
}
[show](){
console.log("dddd");
}
}
var p1=new Person("we",20);
p1.showName();
p1.showAge();//ddd
constructor 方法
class Point {
}
// 等同于
class Point {
constructor() {}
}
類的所有執行個體共享一個原型對象
var p1 = new Point(2,3);
var p2 = new Point(3,2);
p1.__proto__ === p2.__proto__//true
上面代碼中,p1和p2都是Point的執行個體,它們的原型都是
Point.prototype
,是以
__proto__
屬性是相等的。
有get、set方法
class MyClass {
constructor() {
// ...
}
get prop() {
return 'getter';
}
set prop(value) {
console.log('setter: '+value);
}
}
類的屬性名,可以采用表達式。
let methodName = 'getArea';
class Square {
constructor(length) {
// ...
}
[methodName]() {
// ...
}
}
類也可以使用表達式的形式定義
const MyClass = class Me {
getClassName() {
return Me.name;
}
};
注意:
- 類和子產品的内部,預設就是嚴格模式,是以不需要使用
指定運作模式。use strict
- 類不存在變量提升(hoist)
- 由于本質上,ES6 的類隻是 ES5 的構造函數的一層包裝,是以函數的許多特性都被Class繼承,包括
屬性。name
- 如果某個方法之前加上星号(
),就表示該方法是一個*
函數。Generator
this 的指向:
- 類的方法内部如果含有
,它預設指向類的執行個體。但是,必須非常小心,一旦單獨使用該方法,很可能報錯。this
報錯解決方法:
- 在構造方法中綁定
,這樣就不會找不到this
方法了。print
class Logger {
constructor() {
this.printName = this.printName.bind(this);
}
//。。。
}
- 使用箭頭函數。
class Obj {
constructor() {
this.getThis = () => this;
}
}
const myObj = new Obj();
myObj.getThis() === myObj // true
- 使用
,擷取方法的時候,自動綁定Proxy
this
靜态方法
加上
static
關鍵字,就表示該方法不會被執行個體繼承,而是直接通過類來調用,這就稱為“靜态方法”。
- 注意,如果靜态方法包含
關鍵字,這個this
指的是類,而不是執行個體。this
class Foo {
static bar() {
this.baz();
}
static baz() {
console.log('hello');
}
baz() {
console.log('world');
}
}
Foo.bar() // hello
上面代碼中,靜态方法
bar
調用了
this.baz
,這裡的
this
指的是
Foo
類,而不是
Foo
的執行個體,等同于調用
Foo.baz
。另外,從這個例子還可以看出,靜态方法可以與非靜态方法重名。
- 父類的靜态方法,可以被子類繼承。
- 靜态方法也是可以從
對象上調用的。super
class Foo {
static classMethod() {
return 'hello';
}
}
class Bar extends Foo {
static classMethod() {
return super.classMethod() + ', too';
}
}
Bar.classMethod() // "hello, too"
執行個體屬性除了定義在
constructor()
方法裡面的this上面,也可以定義在類的最頂層。
靜态屬性指的是 Class 本身的屬性,即
Class.propName
,而不是定義在執行個體對象(
this
)上的屬性。
new.target
屬性
new
是從構造函數生成執行個體對象的指令。ES6 為
new
指令引入了一個
new.target
屬性,該屬性一般用在構造函數之中,傳回new指令作用于的那個構造函數。如果構造函數不是通過new指令或
Reflect.construct()
調用的,
new.target
會傳回
undefined
,是以這個屬性可以用來确定構造函數是怎麼調用的。
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 内部調用
new.target
,傳回目前 Class。
class Rectangle {
constructor(length, width) {
console.log(new.target === Rectangle);
this.length = length;
this.width = width;
}
}
var obj = new Rectangle(3, 4); // 輸出 true
子類繼承父類時,
new.target
會傳回子類。
class Rectangle {
constructor(length, width) {
console.log(new.target === Rectangle);
// ...
}
}
class Square extends Rectangle {
constructor(length, width) {
super(length, width);
}
}
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); // 正确
繼承
Class 可以通過
extends
關鍵字實作繼承
class Point {
}
class ColorPoint extends Point {
}
class ColorPoint extends Point {
constructor(x, y, color) {
super(x, y); // 調用父類的constructor(x, y)
this.color = color;
}
toString() {
return this.color + ' ' + super.toString(); // 調用父類的toString()
}
}
Object.getPrototypeOf
方法可以用來從子類上擷取父類。可以使用這個方法判斷,一個類是否繼承了另一個類。
super
這個關鍵字
super
這個關鍵字,既可以當作函數使用,也可以當作對象使用。在這兩種情況下,它的用法完全不同。
- 第一種情況,
作為函數調用時,代表父類的構造函數。ES6 要求,子類的構造函數必須執行一次super函數。super
class A {
constructor() {
console.log(new.target.name);
}
}
class B extends A {
constructor() {
super();
}
}
new A() // A
new B() // B
作為函數時,
super()
隻能用在子類的構造函數之中,用在其他地方就會報錯。
- 第二種情況,
作為對象時,在普通方法中,指向父類的原型對象;在靜态方法中,指向父類。super
class A {
p() {
return 2;
}
}
class B extends A {
constructor() {
super();
console.log(super.p()); // 2
}
}
let b = new B();
類的
prototype
屬性和
__proto__
屬性
(1)子類的_
_proto__
屬性,表示構造函數的繼承,總是指向父類。
(2)子類prototype屬性的
__proto__
屬性,表示方法的繼承,總是指向父類的
prototype
屬性。
class A {
}
class B extends A {
}
B.__proto__ === A // true
B.prototype.__proto__ === A.prototype // true
第一種,子類繼承Object類。
class A extends Object {
}
A.__proto__ === Object // true
A.prototype.__proto__ === Object.prototype // true
第二種情況,不存在任何繼承。
class A {
}
A.__proto__ === Function.prototype // true
A.prototype.__proto__ === Object.prototype // true