ES 6 ----- class基本用法

首先class其实只是一个语法糖,绝大部分功能都可以用ES5实现。

类的所有方法都定义在类的prototype上

class MyFn {}
let a = new MyFn();
a.constructor === MyFn.prototype.constructor // ture
复制代码

可以用Object.assign向类里添加多个方法

Object.assign(MyFn.ptototype, {
    toString() {},
    toValue() {}
})复制代码

此外 MyFn.prototype.constructor === MyFn // true

与es5 不一致的地方,类内部定义的方法是不可枚举的

Object.keys(MyFn.prototype)  //  []
Object.getOwnPropertyNames(MyFn.prototype)  // ['toString', 'toValue']复制代码

constructor方法

constructor方法是类的默认方法,通过new命令生成对象实例时自动调用的方法,如果没有显示定义,会自动添加一个空的constructor方法,constructor方法默认返回实例对象(this),不过我们可以指定返回另一个对象

class Foo {
    constructor () {
        return Object.create(null);
    }
}

new Foo() instanceof Foo // false复制代码

与es5一样,实例的属性除非显示定义在其本身上(即this 对象上),否则都是定义在原型上(prototype)

看这段代码

var a = new Foo();
var b = new Foo();

a.__proto__.newProperty = function () { console.log("Attention !!!") }
b.newProperty(); // "Attention !!!"复制代码

这里__proto__指向的是构造原型(即Foo),所以修改原型必须谨慎,最好别用

利用Class表达式,可以写出立即函数形式

var foo = class {
    constructor (val) {
        this.value = val;
    }
    printVal () {
        cosole.log(this.value)
    }
}("money")复制代码

class 不存在变量提升

new Foo();  // ReferenceError
class Foo {}复制代码

注意类和模块的内部默认就是严格模式

class的继承

子类必须在constructor中调用super方法,否则新建实例会报错,这是因为子类没有自己的this 对象,而是继承了父类的this对象,然后对其进行加工。

es5的继承实质上是先创造子类的实例对象this,然后再将父类的方法添加到this上(Parent.apply(this));
es6的继承实质上是先创造父类的实例对象this,然后通过子类的构造函数修饰this;此时子类的this基于父类实例的加工,所以必须先调用super才能在子类里使用关键字this

类的prototype和__proto__ 属性

1.子类的__proto__指向的是父类,表示构造函数的继承;

2.子类的prototype.__proto__指向的是父类的prototype,表示的是方法的继承;

class A {};
class B {};
Object.setPrototypeOf(B.prototype, A.prototype);
Object.setPrototypeOf(B, A);复制代码

Object.setPrototypeOf = function (obj, proto) {
    obj.__proto__ = proto;
    return obj;
}复制代码

继承的几种情况

class A extend Object {}

A.__proto__ === Object   // true
A.prototype.__proto__ === Object.prototype   // true
复制代码

class A {}      即不存在继承
A.__proto__ === Function.prototype   // true
A.prototype.__proto__ === Object.prototype   // true复制代码

这时A作为一个基类,就是一个函数,直接继承Function.prototype,但是A被调用时返回的是一个对象,所以A.prototype.__proto__ 指向Object.prototype 

class A extend null {}
A.__proto__ === Function.prototype   // true
A.prototype.__proto__ === undefined  // true复制代码

Object.getPrototypeOf() 可从子类上获取父类,该方法可判断一个类是否继承另一个类

子类实例的__proto__的__proto__指向父类实例的__proto__,因此可以通过子类来修改父类实例的行为

class Foo {}
class Bar extends Foo {}

var a1 = new Foo();
var a2 = new Bar();

a2.__proto__ === a1.__proto__; // false
a2.__proto__.__proto__ === a1.__proto__; // true

a2.__proto__.__proto__.printName = function () {    
    console.log("this is a2")
}
a1.printName() // "this is a2"复制代码


原声构造函数的继承

js的原生构造函数大概有九种

Boolean();  Number();  Array();  String();  Object();  Date();  RegExp(); Error(); Function();

以前这些基本的构造函数是无法被继承的,举个例子,Array构造函数内有一个内部属性[[DefineOwnProperty]]来控制定义性属性时增加length的值,这个内部属性无法在子类汇中获取,所以会出现子类length属性行为不正常。

但是es6可以

class MyArray extends Array {    
    constructor (...arg) {        
        super(...arg);    
    }
}
var myArray = new MyArray();复制代码


class 的 getter 和 setter

es6的getter和setter都是定义在属性的descriptor对象上的

可以用Object.getOwnPropertyDescriptor()

class A {    
    constructor () {       ***    }    
    get oneProp () {        ***    }    
    set oneProp () {        ***    }
}
var oDescriptor = Object.getOwnPropertyDescriptor(A , "oneProp");
"get" in oDescriptor; //true
"set" in oDescriptor;  // true复制代码

class 的静态方法

在一个方法前加上 static关键字,该方法就不会被实例继承,但是子类可以继承父类的静态方法,同时静态方法也可以从super上调用。

class的静态属性

静态属性指的是class本身的属性,而不是定义在实例对象(this)上的属性,es6明确规定class只有静态方法没有静态属性

class Foo {
    写法一
    prop: 1
    写法二
    static prop : 1
}
Foo.prop // undefined 复制代码

这两种方法都无效,虽然不会报错

new.target 属性

返回new命令所调用的构造函数,如果构造函数不是new命令调用的,那么将返回undefined

以下两种方法用于确保构造函数只能用new调用

1.
function Person(name) {    
    if(new.target !== undefined) {       
        this.name = name;    
    }else {        
        throw new Error ("必须使用new调用")    
    }
}

2.
function Person (name) {    
    if(new.target === Person) {        
        this.name = name;    
    }else {        
        throw new Error ("必须使用new调用")            
    }
}复制代码

class内部调用new.target返回的是当前的class,子类继承父类时new.target返回的是子类,由此利用这个特点可以写出不能独立使用,只能继承后使用的类

class Shape {
    constructor () {
        if(new.target === Shape) {
            throw new Error ("必须使用new调用")
        }
    }
}
class Rectangle extends Shape {
    constructor () {
        super() 
        ***
    }
}

var x = new Shape() //   报错
var x = Rectangle()  //  正常复制代码

注意在函数外部调用new.target会报错

Mixin模式的实现

Mixin模式指的是将多个类的接口混入另一个类

function mix(...mixins) {    
    class Mix {}    
    for (let mixin of minins) {        
        copyProperties(Mix, mixin);        
        copyProperties(Mix.prototype, mixin.prototype);    
    }    
    return Mix;
}
function copyProperties(target, source) {    
    for( let key of Reflect.ownKeys(source)) {        
        if( key !== "constuctor" && 
            key !== "prototype" && 
            key !== "name") {            
        let desc = Object.getOwnPropertyDescriptor(source, key);            
        Object.defineProperties(target, key, desc);        
        }    
    }
}
class DistributedEdit extends mix(Loggable, Serializable) {
    // ..
}复制代码


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值