A-A+

ES6之class

2017年08月27日 JavaScript 暂无评论

ES6之前

function PersonType(name) {
    this.name = name;
}
PersonType.prototype.sayName = function() {
    console.log(this.name);
};
let person = new PersonType("Nicholas");
person.sayName();  // 输出 "Nicholas"
console.log(person instanceof PersonType);  // true
console.log(person instanceof Object);      // true

class

class PersonClass {
    // 等效于 PersonType 构造函数
    constructor(name) {
        this.name = name;
    }
    // 等效于 PersonType.prototype.sayName
    sayName() {
        console.log(this.name);
    }
}

let person = new PersonClass("Nicholas");
person.sayName();  // 输出 "Nicholas"

console.log(person instanceof PersonClass);    // true
console.log(person instanceof Object);          // true

console.log(typeof PersonClass);                    // "function"
console.log(typeof PersonClass.prototype.sayName);  // "function"

自有属性:属性只出现在实例而不是原型上,而且只能由构造函数和方法来创建。
注意

  • 类声明和函数定义不同,它们是不会被提升的。类声明的行为和 let 比较相似,所以当执行流作用到类声明之前类会存在于暂存性死区(temporal dead zone)内。
  • 类声明中的代码自动运行在严格模式下,同时没有任何办法可以手动切换到非严格模式。
  • 所有的方法都是不可枚举的(non-enumerable),这和自定义类型相比是个显著的差异,因为后者需要使用 Object.defineProperty() 才能定义不可枚举的方法。
  • 所有的方法都不能使用 new 来调用,因为它们没有内部方法 [[Construct]]。
  • 不使用 new 来调用类构造函数会抛出错误。
  • 试图在方法内部重写类名的行为会抛出错误。

设计类表达式的目的主要是为了将它赋值给变量或者传参给函数。

let PersonClass = class {}

以派生类为继承方式

function Rectangle(length, width) {
    this.length = length;
    this.width = width;
}

Rectangle.prototype.getArea = function() {
    return this.length * this.width;
};

function Square(length) {
    Rectangle.call(this, length, length);
}

Square.prototype = Object.create(Rectangle.prototype, {
    constructor: {
        value:Square,
        enumerable: true,
        writable: true,
        configurable: true
    }
});

var square = new Square(3);

console.log(square.getArea());              // 9
console.log(square instanceof Square);      // true
console.log(square instanceof Rectangle);  // true

Square 继承了 Rectangle。方法是通过创建了以 Rectangle.prototype 为原型创建的新对象对 quare.prototype 进行重写,并在构造函数上调用 Rectangle.call() 方法。
类通过 extends 关键字并指定要继承的函数或类名简单地实现了继承。原型会自动调整,并可以通过 super() 方法来访问基类构造函数。

class Rectangle {
    constructor(length, width) {
        this.length = length;
        this.width = width;
    }

    getArea() {
        return this.length * this.width;
    }
}

class Square extends Rectangle {
    constructor(length) {

        // 等效于 Rectangle.call(this, length, length)
        super(length, length);
    }
}

var square = new Square(3);

console.log(square.getArea());              // 9
console.log(square instanceof Square);      // true
console.log(square instanceof Rectangle);  // true

super注意事项

  • 你只能在派生类中使用 super(),否则(没有使用 extends 的类或函数)一个错误会被抛出。
  • 你必须在构造函数的起始位置调用 super(),因为它会初始化 this。任何在 super() 之前访问 this 的行为都会* 造成错误。
  • 在类构造函数中,唯一能避免调用 super() 的办法是返回一个对象。
    派生类中的方法总是会屏蔽基类中的同名方法。
    如果基类中包含静态成员,那么派生类也可以直接使用它们。这里的继承机制和其它语言相同.
    constructor内定义的方法和属性是实例对象自己的,而constructor外定义的方法和属性则是所有实例对象可以共享的。
class Animal {
    constructor(){
        this.type = 'animal'
    }
    says(say){
        setTimeout(function(){
            console.log(this.type + ' says ' + say)// this 为全局的
        }, 1000)
    }
}

var animal = new Animal()
animal.says('hi')  //undefined says hi

当我们使用箭头函数时,函数体内的this对象,就是定义时所在的对象,而不是使用时所在的对象。并不是因为箭头函数内部有绑定this的机制,实际原因是箭头函数根本没有自己的this,它的this是继承外面的,因此内部的this就是外层代码块的this。

todo

ES6 与ES5的写法对照

标签:

给我留言

Copyright © 花未全开月未圆 保留所有权利.   Theme  Ality

用户登录