Object.getOwnPropertyNames(class{}); // ["length", "prototype"]
Object.getOwnPropertyNames(class{}); // ["length", "prototype", "name"]
Object.getOwnPropertyNames(class cl{}.prototype); // ["constructor"]複製代碼
// 1️⃣ function 與 class 的區別
/*---------------- ES5 寫法 ----------------*/
Object.getOwnPropertyNames(Function); // ["length", "name", "prototype"]
Object.getOwnPropertyNames(Function.prototype); // ["length", "name", "arguments", "caller", "constructor", "apply", "bind", "call", "toString"]
function Point(x, y) {
this.x = x;
this.y = y;
}
Point.prototype.toString = function () {
return '(' + this.x + ',' + this.y + ')';
}
// 實例化時能夠不須要new
const point = new Point(10, 20);
Object.keys(Point.prototype); // ['toString']
Object.getOwnPropertyNames(Object.prototype); // ['constructor', 'toString']
/*---------------- ES6 寫法 ----------------*/
const methodName = 'getArea';
const privateMehod = Symbol('privateMethod');
const privateVariable = Symbol('privateMethod');
// Class 繼承了 Function 的屬性,如 name 等
// Class不像 Function 存在變量提高,必須先定義才能使用
// Class 實例化必須使用 new 調用,不然 TypeError: Class constructor Foo cannot be invoked without 'new'
class Point {
// 該方法不被繼承,只能 Point.staticMethod() 調用
static staticMethod() {
// 這裏 this 指的是類而不是實例
this.toString();
}
// 容許靜態和非靜態方法重名
static toString() {
console.log('');
}
// 類的實例屬性
state = {
value: '100'
};
// class 內部默認嚴格模式 'use strict'
// class 內部的全部方法都是公開的,除了Symbol表達式定義的方法名除外
// 構造函數,至關於上面的 ES5 Point,會默認添加
constructor(x, y) {
console.log('new.target.name: ', new.target.name);
// new.target 指向當前正在執行的function,即返回當前 class
// 實例經過 new 構造時輸出true,當在被繼承的子類構造函數中執行時,輸出 false,new.target只能在函數或類內部使用
console.log(new.target === Point);
// x、y屬性定義在其自己上,即 this 上
// this 默認指向類的實例,經過 super 調用父類的方法時,super會綁定子類的this
this.x = x;
this.y = y;
// this.publicMethod = this.publicMehtod.bind(this);
// 與上面等效,運行時綁定this到類內部
this.publicMethod = (arg) => {
this.publicMethod(arg);
}
}
/* constructor(...args) { this.args = args; } //*/
// 容許定義一個 Generator 函數
* generatorFunc() {
for (let arg of this.args) {
yield arg;
}
}
publicMehtod(parm) {
}
// class 的全部方法都定義在 prototype 上
toString() {
return '(' + this.x + ',' + this.y + ')';
}
// 屬性名能夠用表達式
[methodName]() {
}
// 內部實際上將 privateMethodName 變成了私有方法
execPrivateMehod(param) {
privateMethodName.call(this, param)
}
// 私有方法
[privateMethod](param) {
return this[privateVariable] = param;
}
// 使用set/get
set prop(value) {
console.log('setting prop');
}
get prop() {
return 'getter prop';
}
}
// 類的靜態屬性,不容許直接寫在類內部即 prop: '200' 或 static prop: '200'
Point.prop = '200';
function privateMethodName(name) {
return this.name = name;
}
const point = new Point(10, 20);
point.prop = 'setting';
point.pop; // getting prop
const descriptor = Object.getOwnPropertyDescriptor(Point.prototype, 'prop');
'set' in descriptor; // true
'get' in descriptor; // true
point.hasOwnProperty('x'); // true
point.hasOwnProperty('toString'); // false
point.__proto__.hasOwnProperty('toString'); // true
point.__proto__.addMethod = function () { // 在原型對象上添加方法
return 'something';
}
const point1 = new Point(30, 40);
// 共享原型對象
point.__proto__ === point1.__proto__; // true
point.constructor = Point.prototype.constructor; // true
typeof Point; // 'function'
Point === Point.prototype.constructor // true,類自己指向構造函數
Object.keys(Point.prototype); // []
Object.getOwnPropertyNames(Object.prototype); // ['constructor', 'toString']
// 2️⃣ 修改構造函數
class Foo {
constructor() {
return Object.create(null); // 返回空對象
}
}
new Foo() instanceof Foo // false
// 3️⃣ Class 表達式
const ClassDefine = class Cn {
getClassName() {
return Cn.name;
}
};
const classObj = new ClassDefine();
classObj.getClassName(); // Cn;
Cn.name; // ReferenceError: cn is not define
// 4️⃣ 當即執行 Class
const obj = new class {
constructor(name) {
this.name = name;
}
getName() {
return this.name;
}
}('name');
obj.getName(); // 'name'
// 5️⃣ 繼承(extends)
class ColorPoint extends Point {
// 如子類沒顯式定義constructor函數,自動添加 constructor(...args) { super(...args) }
constructor() {
// 只有先調用super以後纔可使用this關鍵字,不然報 ReferenceError
// 至關於 Point.prototype.constructor.call(this);
// super() 函數只能用在構造函數中
// super 當作對象使用時至關於 Point.prototype,注意:只能調取父類的prototype屬性或方法(即父類顯式定義的),而不能調用其實例方法或屬性
super(); // 調用父類的構造函數,返回父類實例
super.staticMethod(); // 能夠直接調用父類的靜態方法
}
}
ColorPoint.staticMethod(); // 能夠直接調用父類的靜態方法
const cp = new ColorPoint(); // 輸出new.target.name: ColorPoint
// cp 同時是子類和父類的實例
cp instanceof Point; // true
cp instanceof ColorPoint; // true
Object.getPrototypeOf(ColorPoint) === Point; // true
// 6️⃣ 使用 Proxy綁定this
function selfish (target) {
const cache = new WeakMap();
const handler = {
get (target, key) {
const value = Relect.get(tartget, key);
if (typeof value !== 'function') {
return value;
}
if (!cache.has(value)) {
cache.set(value, value.bind(target));
}
return cache.get('value');
}
};
const proxy = new Proxy(target, handler);
reutn proxy;
}複製代碼
ES5 的繼承,實質是先創造子類的實例對象 this,而後再將父類的方法添加到 this 上面(Parent.call(this)
)
ES6 的繼承,是先創造父類的實例對象 this(super()
), 而後再用子類的構造函數修改 thisjavascript
// 1️⃣ 基本用法和注意事項
class Point {
static hello() {
console.log('hello, world');
}
p() {
return 2;
}
}
// 繼承同時會繼承父類的靜態方法
class ColorPoint extends Point {
// 若是顯式寫了 constructor,內部必需要有 super(),不然實例化時報: Uncaught ReferenceError: Must call super constructor in derived class before accessing 'this' or returning from derived constructor
constructor() {
// 子類沒有本身的 this 對象,而是繼承 父類的 this 對象,若是不調用 super 方法,子類就得不到 this 對象,在constructor 中使用 this 會報 Uncaught ReferenceError: Must call super constructor in derived class before accessing 'this' or returning from derived constructor
// super() 這種函數用法只能用在子類 constructor 中
// 至關於調用父類構造函數,可是返回的是子類的實例,見 3️⃣
super();
// 等效於
// Point.prototype.constructor.call(this);
// super 做爲對象使用,能夠在 constructor 和子類的其它方法中使用,至關於調用 Point.prototype.p,見4️⃣
console.log(super.p()); // 2
}
// 若是沒有顯式定義 constructor,則會隱式添加 constructor(...args){super(...args)}
}
let cp = new ColorPoint();
// ES5 和 ES6 這兩種行爲一致
cp instanceof ColorPoint; // true
cp instanceof Point; // true
// 2️⃣ 判斷繼承關係
Object.getPrototypeOf(ColorPoint) === Point; // true
// 3️⃣ 子類的super()中this指向子類
class A {
constructor() {
console.log(new.target.name);
}
}
class B extends B {
constructor() {
super();
}
}
new A; // A
new B; // B
// 4️⃣ supr 當作對象使用時指向父類prototype
class A {
constructor() {
this.p = 2;
}
}
A.prototype.x = 2;
class B extends A {
get m() {
// super 指向父類原型對象
return super.p;
}
get x() {
return super.x;
}
}
let b = new P();
b.m; // undefined
b.x; // 2
// 5️⃣ 經過suer調用父類的方法時,方法內部的this指向子類
class A {
constructor() {
this.x = 1;
}
print() {
// 此處 this 指向子類B
console.log(this.x);
}
}
class B extends A {
constructor() {
super();
this.x = 2;
// 若是經過 super 對屬性賦值,這時 super 就是 this
super.x = 3;
// 此處super仍是指向 A.prototype,因此打印 undefined
console.log(super.x); // undefined
console.log(this.x); // 3
}
m() {
// 至關於 A.prototype.print()
super.print();
}
}
let b = new B();
b.m() // 2
// 6️⃣ 在靜態方法中使用super,指向父類,在普通方法中super指向父類的prototype
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 1
var child = new Child();
child.myMethod(2); // instance 2
// 7️⃣ super不能單獨使用
class A2 {}
class B2 extends A2 {
constructor() {
super();
// super.valueOf() 返回 B 的實例
console.log(super.valueof() instanceof B); // true
// 編譯階段就會報錯
console.log(super); // Uncaught SyntaxError: 'super' keyword unexpected here
}
}
let b = new B();
// 8️⃣ 對象老是繼承其它對象,因此能夠用super
var obj = {
toString() {
return 'MyObject: ' + super.toString();
}
}
obj.toString(); // "MyObject: [object Object]"複製代碼
Boolean()
Number()
String()
Array()
RegExp()
Date()
Function()
Error()
Object()