跳到主要内容

Class

// 实例属性的新写法
class People {
name
age

getName() {
return this.name
}
}

new People() // {name: undefined, age: undefined}

// 类似于

People.call({
name: undefined,
age: undefined,
__proto__: People.prototype
})

在以往构造函数的写法中,实例的属性都是执行构造函数时添加的;而通过这种新写法,在执行构造函数之前,实例已经拥有该属性了(以上代码属性的值为undefined,我们也可以最开始的时候就赋值,如:

class People {
name = 'akara'
age = 996
}
new People() // {name: "akara", age: 996}

这也是为什么,在TypeScript中我们应该这样写

class People {
name: string
id: number

constructor(name: string, id: number) {
this.name = name
this.id = id
}
}

// 而不是

class People {
constructor(name: string, id: number) {
this.name = name // Property 'name' does not exist on type 'People'
this.id = id // Property 'id' does not exist on type 'People'
}
}

class中的箭头函数

class People {
name = 'akara'

getNameA = () => {
console.log(this)
}

getNameB() {
console.log(this)
}
}

const p = new People() // {name: "a", getNameA: ƒ}

p.name
p.getNameA() // 实例p
p.getNameB() // 实例p

这里有几个注意的点

一:

getNameA是实例的方法,而getNameB是原型对象上的方法

getNameA: () => { console.log(this) }
name: "akara"
__proto__:
constructor: class People
getNameB: ƒ getNameB()
__proto__: Object

二:

p.getNameA输出的是实例p,这可能并不符合我们的预期。

我们都知道,如果是下面这样的对象,输出结果应该会符合预期。因为箭头函数本身没有this值,那么需要输出this的时候就沿着作用域链寻找,也就找到了window

const obj = {
name: 'akara',
getNameA: () => {
console.log(this)
},
getNameB: function() {
console.log(this)
}
}
obj.getNameA() // window
obj.getNameB() // obj

既然如此,为什么通过class创建的实例的箭头函数,输出的this却是实例本身。简单来说,这是一个特性,或者说JS引擎的机制

我们可以通过babel把代码编译成es5的代码,来破解其背后的玄机。

// es6
class People {
name = 'akara'
getName = () => {
console.log(this.name)
}

getMyName() {
console.log(this.name)
}
}

// 通过babel编译后 (stage-1, stage-3)

class People {
constructor() {
_defineProperty(this, "name", 'akara');

_defineProperty(this, "getName", () => {
console.log(this.name);
});
}

getMyName() {
console.log(this.name);
}
}