在 ES6 类中,如果父类的属性是通过异步赋值的,子类能否获取到这个值取决于访问时机。下面通过代码示例详细说明:

1. 同步 vs 异步赋值的区别

同步赋值(正常情况)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Parent {
constructor() {
this.syncValue = '同步值'; // 同步赋值
}
}

class Child extends Parent {
getValues() {
return {
syncValue: this.syncValue // 可以正常获取
};
}
}

const child = new Child();
console.log(child.getValues()); // { syncValue: '同步值' }

异步赋值的情况

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
class Parent {
constructor() {
this.asyncValue = null;
// 异步赋值
setTimeout(() => {
this.asyncValue = '异步赋值完成';
}, 1000);
}
}

class Child extends Parent {
getValues() {
return {
asyncValue: this.asyncValue // ❌ 立即访问可能为 null
};
}
}

const child = new Child();
console.log(child.getValues()); // { asyncValue: null }

// 1秒后再访问
setTimeout(() => {
console.log(child.getValues()); // { asyncValue: '异步赋值完成' }
}, 1500);

2. 解决方案

方案 1:使用 Promise 管理异步状态

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
class Parent {
constructor() {
this.asyncValue = null;
this.valueReady = new Promise((resolve) => {
setTimeout(() => {
this.asyncValue = '异步赋值完成';
resolve(this.asyncValue);
}, 1000);
});
}
}

class Child extends Parent {
async getValues() {
// 等待异步赋值完成
await this.valueReady;
return {
asyncValue: this.asyncValue
};
}
}

// 使用
const child = new Child();
child.getValues().then(values => {
console.log(values); // { asyncValue: '异步赋值完成' }
});

方案 2:使用 async/await 模式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
class Parent {
constructor() {
this.initialized = this.init();
}

async init() {
// 模拟异步操作
this.asyncValue = await new Promise(resolve => {
setTimeout(() => resolve('异步值'), 1000);
});
}

async ensureInitialized() {
await this.initialized;
}
}

class Child extends Parent {
async getAsyncValue() {
await this.ensureInitialized(); // 等待父类初始化完成
return this.asyncValue;
}
}

// 使用
const child = new Child();
child.getAsyncValue().then(value => {
console.log(value); // '异步值'
});

方案 3:事件驱动模式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
class Parent {
constructor() {
this.asyncValue = null;
this.listeners = [];

setTimeout(() => {
this.asyncValue = '异步值';
this.listeners.forEach(callback => callback(this.asyncValue));
}, 1000);
}

onValueReady(callback) {
if (this.asyncValue) {
callback(this.asyncValue);
} else {
this.listeners.push(callback);
}
}
}

class Child extends Parent {
getValue(callback) {
this.onValueReady(value => {
callback(value);
});
}
}

// 使用
const child = new Child();
child.getValue(value => {
console.log(value); // '异步值'
});

3. 实际应用场景

异步数据获取

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
class ApiService {
constructor() {
this.userData = null;
this.initialized = this.fetchUserData();
}

async fetchUserData() {
// 模拟 API 调用
this.userData = await fetch('/api/user').then(res => res.json());
}

async ensureReady() {
await this.initialized;
}
}

class UserComponent extends ApiService {
async getUserProfile() {
await this.ensureReady();
return {
name: this.userData.name,
email: this.userData.email
};
}
}

总结

  • 子类可以获取父类的异步赋值,但必须在异步操作完成后
  • 立即访问可能得到 null 或初始值
  • 推荐使用 Promiseasync/await 来管理异步状态
  • 通过等待初始化完成的方法确保数据可用性
  • 事件监听模式适合需要实时响应的场景

关键在于时序控制 - 确保在访问异步值之前,相关的异步操作已经完成。