ES5/ES6 的继承除了写法以外还有什么区别?

336 阅读2分钟

class声明会提升,和let,const一样存在暂时性死区

let ani = new Animal();
function Animal() {
    this.name = 'le';
};
let dog = new Dog(); // Uncaught ReferenceError: Cannot access 'Dog' before initialization
class Dog {

}

class声明内部会启用严格模式

function Animal() {
    this.name = 'le';
    age = 10;
};
const ani = new Animal();
class Dog {
    constructor() {
        sex = 1; // Uncaught ReferenceError: sex is not defined
    }
}
let dog = new Dog();

必须使用new来调用class

function Animal() {
    this.name = 'le';
    console.log('animal');
};
const ani = Animal();
class Dog {
    constructor() {
        this.name = 'le';
    }
}
let dog = Dog(); // Uncaught TypeError: Class constructor Dog cannot be invoked without 'new'

class的静态方法和原型方法都是不可枚举的

function Animal() {
    this.name = 'le';
};
Animal.static_run = function() {
    console.log('animal static run');
}
Animal.prototype.say = function() {
    console.log('animal say');
}
Animal.prototype.eat = function() {
    console.log('animal eat');
}
const ani = new Animal();

class Dog {
    constructor() {
        this.name = 'le';
    }
    static static_run() {
        console.log('dog static run');
    }
    say() {
        console.log('dog say');
    }
    eat() {
        console.log('dog eat');
    }
}
let dog = new Dog();
console.log('Animal 静态方法:', Object.keys(Animal));           // Animal 静态方法: ["static_run"]
console.log('Animal 原型方法:', Object.keys(Animal.prototype)); // Animal 原型方法: (2) ["say", "eat"]
console.log('Dog 静态方法:', Object.keys(Dog));                 // Dog 静态方法: []
console.log('Dog 原型方法:', Object.keys(Dog.prototype));       //Dog 原型方法: []

class的静态方法和原型方法都没有prototype,不能使用new来调用

function Animal() {
    this.name = 'le';
};
Animal.static_run = function() {
    console.log('animal static run');
}
Animal.prototype.say = function() {
    console.log('animal say');
}
Animal.prototype.eat = function() {
    console.log('animal eat');
}
const ani = new Animal();

class Dog {
    constructor() {
        this.name = 'le';
    }
    static static_run() {
        console.log('dog static run');
    }
    say() {
        console.log('dog say');
    }
    eat() {
        console.log('dog eat');
    }
}
let dog = new Dog();
console.log('Animal 静态方法static_run属性:', Reflect.ownKeys(Animal.static_run));
console.log('Animal 原型方法say属性:', Reflect.ownKeys(Animal.prototype.say));
console.log('Dog 静态方法static_run属性:', Reflect.ownKeys(Dog.static_run));
console.log('Dog 原型方法say属性:', Reflect.ownKeys(Dog.prototype.say));
/**
 * Animal 静态方法static_run属性: (5) ["length", "name", "arguments", "caller", "prototype"]
 * index.html:81 Animal 原型方法say属性: (5) ["length", "name", "arguments", "caller", "prototype"]
 * index.html:82 Dog 静态方法static_run属性: (2) ["length", "name"]
 * index.html:83 Dog 原型方法say属性: (2) ["length", "name"]
 */
// const obj_a_static_run = new Animal.static_run(); // animal static run
// const obj_a_say = new Animal.prototype.say(); // animal say
// const obj_static_run = new Dog.static_run(); // Uncaught TypeError: Dog.static_run is not a constructor
const obj_say = new Dog.prototype.say(); // Uncaught TypeError: Dog.prototype.say is not a constructor

class 子类的__proto__等于父类,es5中子类的__proto__为Function.prototype

function People() {
    this.name = 'le';
};

function Chinese() {
    People.call(this);
}
Chinese.prototype = Object.create(People.prototype);
Chinese.prototype.constructor = Chinese;

class Animal {
    constructor() {
        this.name = 'le';
    }
}
class Dog extends Animal {};
console.log(Chinese.__proto__ === People); // false
console.log(Chinese.__proto__ === Function.prototype); // true
console.log(Dog.__proto__ === Animal); // true
console.log(Animal.__proto__ === Function.prototype); // true

ES5继承是先新建子类的实例对象this,再将父类的属性添加到子类上,ES6是先新建父类的实例对象this,然后再用子类的构造函数修饰this,使得父类的所有行为都可以继承

function ES5Array(len) {
    Array.call(this, len); // 这里没有生效,无法进入Array的构造函数
}
ES5Array.prototype = Object.create(Array.prototype);
ES5Array.prototype.constructor = ES5Array;

class ES6Array extends Array {
    constructor(len) {
        super(len);
    }
};
// 或者 class ES6Array extends Array{}
const arr5 = new ES5Array(3);
const arr6 = new ES6Array(3);
console.log(arr5.length); // 0
console.log(arr6.length); // 3