ES6系列之class
栏目: JavaScript · 发布时间: 5年前
内容简介:构造函数的prototype属性,在 ES6 的“类”上面继续存在。事实上,类的所有方法都定义在类的prototype属性上面。由于类的方法都定义在prototype对象上面,所以类的新方法可以添加在prototype对象上面。Object.assign方法可以很方便地一次向类添加多个方法。prototype对象的constructor属性,直接指向“类”的本身,这与 ES5 的行为是一致的。
构造函数的prototype属性,在 ES6 的“类”上面继续存在。事实上,类的所有方法都定义在类的prototype属性上面。
由于类的方法都定义在prototype对象上面,所以类的新方法可以添加在prototype对象上面。Object.assign方法可以很方便地一次向类添加多个方法。
prototype对象的constructor属性,直接指向“类”的本身,这与 ES5 的行为是一致的。
另外,类的内部所有定义的方法,都是不可枚举的(non-enumerable)。
1.严格模式
类和模块的内部,默认就是严格模式,所以不需要use strict指定运行模式。只要你的代码写在类或模块之中,就只有严格模式可用。
2.constructor方法
constructor方法是类的默认方法,通过new命令生成对象实例时,自动调用该方法。一个类必须有constructor方法,如果没有显示定义,一个空的constructor方法会被默认添加。
类必须使用new调用,否则会报错,这是它跟普通构造函数的一个主要区别,后者不用new也可以执行。
3.类的实例对象
生成类的实例对象的写法,与ES5完全一样,也是使用new命令。前面说过,如果忘记加上new,像函数那样调用Class,将会报错。
4.Class表达式
const MyClass = class Me { getClassName() { return Me.name; } }; let inst = new MyClass(); inst.getClassName() // Me Me.name // ReferenceError: Me is not defined
如果类的内部没用到的话,可以省略Me,也就是可以写成下面的形式。
const MyClass = class { /* ... */ };
5.不存在变量提升
6.变量提升
类的方法内部如果含有this,它默认指向类的实例。但是,必须非常小心,一旦单独使用该方法,很可能报错。
1)在构造方法中绑定this
class Logger { constructor() { this.printName = this.printName.bind(this); } // ... }
2)使用箭头函数
class Logger { constructor() { this.printName = (name = 'there') => { this.print(`Hello ${name}`); }; } // ... }
7.name属性
name属性总是返回仅跟在class关键字后面的类名
8.Class的取值函数(getter)和存值函数(setter)
与ES5一样,在“类”的内部可以使用get和set关键字,对某个属性设置存值函数和取值函数,拦截该属性的存取行为。
class MyClass { constructor() { // ... } get prop() { return 'getter'; } set prop(value) { console.log('setter: '+value); } } let inst = new MyClass(); inst.prop = 123; // setter: 123 inst.prop // 'getter'
9.Class的静态方法
类相当于实例的原型,所有在类中定义的方法,都会被实例继承。如果在一个方法前,加上static关键字,就表示该方法不会被实例继承,而是直接通过类来调用,这就称为“静态方法”。
class Foo { static classMethod() { return 'hello'; } } Foo.classMethod() // 'hello' var foo = new Foo(); foo.classMethod() // TypeError: foo.classMethod is not a function
注意,如果静态方法包含this关键字,这个this指的是类,而不是实例。
父类的静态方法,可以被子类继承。
静态方法也是可以从super对象上调用的。
10.Class的静态属性和实例属性
静态属性指的是Class本身的属性,即Class.propName,而不是定义在实例对象(this)上的属性。
ES6明确规定,Class内部只有静态方法,没有静态属性。
11.new.target属性
new是从构造函数生成实例对象的命令。如果构造函数不是通过new命令调用的,new.target会返回undefined,因此这个属性可以用来确定构造函数是怎么调用的。
Class 内部调用new.target,返回当前 Class。
需要注意的是,子类继承父类时,new.target会返回子类。
利用这个特点,可以写出不能独立使用、必须继承后才能使用的类。
class Shape { constructor() { if (new.target === Shape) { throw new Error('本类不能实例化'); } } } class Rectangle extends Shape { constructor(length, width) { super(); // ... } } var x = new Shape(); // 报错 var y = new Rectangle(3, 4); // 正确
12.继承
1)Class可以通过extends关键字实现继承。
class ColorPoint extends Point { constructor(x, y, color) { super(x, y); // 调用父类的constructor(x, y) this.color = color; } toString() { return this.color + ' ' + super.toString(); // 调用父类的toString() } }
子类必须在constructor方法中调用super方法,否则新建实例时会报错。这是因为子类自己的this对象,必须先通过父类的构造函数完成塑造,得到与父类同样的实例属性和方法,然后再对其进行加工,加上子类自己的实例属性和方法。如果不调用super方法,子类就得不到this对象。
另一个需要注意的是,在子类的构造函数中,只有调用super之后,才可以使用this关键字,否则会报错。这是因为子类实例的构建,基于父类实例,只有super方法才能调用父类实例。
2)Object.getPrototypeOf()方法可以用来从子类上获取父类。因此,可以判断一个类是否继承了另一个类。
3)super关键字
a.第一种情况,super作为函数调用时,代表父类的构造函数。只能在子类的构造函数中调用,否则报错。
b.第二种情况,super作为对象时,在普通方法中,指向父类的原型对象;在静态方法中,指向父类。
4)类的prototype属性和__proto__属性
大多数浏览器的 ES5 实现之中,每一个对象都有__proto__属性,指向对应的构造函数的prototype属性。Class 作为构造函数的语法糖,同时有prototype属性和__proto__属性,因此同时存在两条继承链。
a.子类的__proto__属性,表示构造函数的继承,总是指向父类。
b.子类prototype属性的__proto__属性,表示方法的继承,总是指向父类的prototype属性。
子类实例的__proto__属性的__proto__属性,指向父类实例的__proto__属性。也就是说,子类的原型的原型,是父类的原型。
//示例 class A { } class B extends A { } B.__proto__ === A // true B.prototype.__proto__ === A.prototype // true //等同于以下实现逻辑 class A { } class B { } // B 的实例继承 A 的实例 Object.setPrototypeOf(B.prototype, A.prototype); // B 继承 A 的静态属性 Object.setPrototypeOf(B, A); const b = new B(); Object.setPrototypeOf = function (obj, proto) { obj.__proto__ = proto; return obj; }
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。