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()