constructor 构造方法
this 代表实例对象
方法之间不需要逗号分隔,加了会报错。
typeof Point // "function"
Point === Point.prototype.constructor // true
类的数据类型就是函数,类本身就指向构造函数。
类的所有方法都定义在类的prototype
属性上面
类的内部所有定义的方法,都是不可枚举的(non-enumerable)
ES6类内部定义的方法不可枚举;ES5可以
# es5
console.log(Object.getPrototypeOf(a));//['es5method']
#es6
console.log(Object.getPrototypeOf(a));//[]
point.hasOwnProperty('toString') // false
类的默认方法
通过 new 命令生成对象实例时,自定调用该方法。
没有显式定义的话,会默认添加
constructor 方法默认返回实例对象(即this)
实例的属性除非显式定义在其本身(即定义在this
对象上),否则都是定义在原型上
类必须使用new
调用,否则会报错。
类的所有实例共享一个原型对象
class Point{
get prop() { return 'getter'; }
set prop(value) { console.log('setter: '+value); }
}
严格模式
类和模块的内部,默认就是严格模式,所以不需要使用use strict
指定运行模式。
不存在提升
类不存在变量提升(hoist)
这种规定的原因与下文要提到的继承有关,必须保证子类在父类之后定义。
let Poin = class Point {
getName() {
console.log(Point.name, 'name')
}
}
let point = new Poin()
point.getName() // Point
console.log(Poin.name, 'Poin.name');//Point
console.log(Point1.name, 'Poin.name');//Point is not defined
Point
只在 Class 的内部可用,指代当前类。在 Class 外部,这个类只能用Poin
引用。
类的方法内部如果含有this
,它默认指向类的实例。
但是,如果将这个方法提取出来单独使用,this
会指向该方法运行时所在的环境
箭头函数内部的this
总是指向定义时所在的对象。
static
关键字,不会被实例继承,而是直接通过类来调用
如果静态方法包含this
关键字,这个this
指的是类,而不是实例。
静态方法可以与非静态方法重名。
父类的静态方法,可以被子类继承。
静态方法也是可以从super
对象上调用的。
class Point {
name;
constructor() {/**/}
}
class Foo {}
Foo.prop = 1
# 或者
class Foo {
prop = 1;
}
只能在类的内部访问的方法和属性,外部不能访问。有利于代码的封装
在属性名之前,使用#
表示
class Foo {
#count = 0
}
只能在类的内部使用(
this.#count
)。如果在类的外部使用,就会报错
私有属性也可以设置 getter 和 setter 方法。
该属性一般用在构造函数之中
返回new
命令作用于的那个构造函数。如果构造函数不是通过new
命令或Reflect.construct()
调用的,new.target
会返回undefined
,因此这个属性可以用来确定构造函数是怎么调用的。
function Person(name) {
if (new.target !== undefined) {
this.name = name;
} else {
throw new Error('必须使用 new 命令生成实例');
}
}
var person = new Person('张三'); // 正确
var notAPerson = Person.call(person, '张三'); // 报错
Class 内部调用
new.target
,返回当前 Class。
子类继承父类时,new.target
会返回子类。
class Fu {
constructor() {
console.log( new.target) //Son
}
}
class Son extends Fu {
constructor () {
super()
}
}
通过extends
关键字实现继承
super
关键字:表示父类的构造函数,用来新建父类的this
对象。
子类必须在constructor
方法中调用super
方法,否则新建实例时会报错。
这是因为子类自己的this
对象,必须先通过父类的构造函数完成塑造,得到与父类同样的实例属性和方法,然后再对其进行加工,加上子类自己的实例属性和方法。如果不调用super
方法,子类就得不到this
对象。
子类的构造函数中,只有调用super
之后,才可以使用this
关键字,否则会报错。这是因为子类实例的构建,基于父类实例,只有super
方法才能调用父类实例。
class Son extends Fu {
constructor() {
this.color = color // ReferenceError
super(x,y)
}
}
父类的静态方法,也会被子类继承。
父类的静态方法,也会被子类继承。
Object.getPrototypeOf(ColorPoint) === Point
// true
既可以当作函数使用,也可以当作对象使用。
作为函数调用时代表父类的构造函数,super
内部的this
指的是B
的实例
只能用在子类的构造函数之中,用在其他地方就会报错。
class A {}
class B extends A {
m() {
super(); // 报错
}
}
在普通方法中,指向父类的原型对象;在静态方法中,指向父类
class A {
constructor() {this.p = 2}
say() {console.log('say', p)}
}
A.prototype.name = "Ren"
class B {
constructor() {
super()
this.p = 99
console.log(super.x) //undefined
super.say() //99
console.log(super.name) //Ren
this.b = 1
super.b = 2
console.log(super.b)//undefined
console.log(this.b)//2
}
}
获取属性 p 失败
获取方法 say 成功
获取属性 name 成功
注意:super.say()虽然调用的是 A.prototype.say(),但A.prototype()内部的this指向B所以输出的是 99
由于this
指向子类实例,所以如果通过super
对某个属性赋值,这时super
就是this
如果super
作为对象,用在静态方法之中,这时super
将指向父类,而不是父类的原型对象。
class Point {
static age = 18;
name = 19
static say() {
console.log(this.age, 'age')//18
console.log(this.name, 'name')//undefined
}
}
class Son extends Point {
static say() {
super.say()
}
}
Son.say()
在子类的静态方法中通过super
调用父类的方法时,方法内部的this
指向当前的子类,而不是子类的实例。
Class 作为构造函数的语法糖,同时有prototype
属性和__proto__
属性,因此同时存在两条继承链。
(1)子类的__proto__
属性,表示构造函数的继承,总是指向父类。
(2)子类prototype
属性的__proto__
属性,表示方法的继承,总是指向父类的prototype
属性。
这两条继承链,可以这样理解:作为一个对象,子类(B
)的原型(__proto__
属性)是父类(A
);作为一个构造函数,子类(B
)的原型对象(prototype
属性)是父类的原型对象(prototype
属性)的实例。
class A {}
class B {}
Object.setPrototypeOf(B.prototype, A.prototype)// B 继承 A 的静态属性
Object.setPrototypeOf(B, A)// B 继承 A 的静态属性
const b = new B()
Object.setPrototypeOf
方法的实现。
Object.setPrototypeOf = function (obj, proto) {
obj.__proto__ proto
return obj
}
没看
没看