microsoft / microsoft/TypeScript
Clarify class property initializer behavior
Chưa có ai nhận issue này.
- Ngôn ngữ chính
- Go
- Star
- 111k
- Fork
- 14.4k
- Merge trung bình
- 1 ngày 19 giờ
- Pull request đã merge (30 ngày)
- 117
Mô tả
The problem
Briefly, if a class property isn't initialized with the declaration, it will be initialized as undefined, no matter how you initialize it in constructor. This will lead to v8 performance issue because of property type transition in many cases.
So I think it's very important to mention the behavior difference in documentation.
Documentation difference
In Class field declarations proposal from TC39, it's very clearly mentioned that "Fields without initializers are set to undefined."
Thus in TS handbook, there is nowhere mentioned how the field declaration without initializer will be handled. Actually the documentation lead us to believe it's the same result to initialize a property in declaration or in constructor. E.G., in the Classes default example, it says:
In the last line we construct an instance of the Greeter class using new. This calls into the constructor we defined earlier, creating a new object with the Greeter shape, and running the constructor to initialize it.
But actually it's like the TC39 proposal, if you don't assign a default value in declaration, the property will be initialized as undefined in constructor (before your actual initialize code).
Take a look at a simple example
class Test {
x: number;
constructor(x: number) {
this.x = x;
}
}
With tsc, this will be generated as the following js
"use strict";
var Test = /** @class */ (function () {
function Test(x) {
Object.defineProperty(this, "x", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
this.x = x;
}
return Test;
}());
As you can see, property this.x is firstly defined with void 0 (undefined) and then assigned with x parameter.
Why should we care
In the previous example, there is a type transition for the property x which is sadly not a good idea in v8. I assume it cause the Test instances to be polymorphic or it cause the Test instances generate a new hidden class. Anyway, the property access performance drops significantly after the construction.
Test case:
index.js.zip
From the simple test case with a loop of Vec3 calculations, we can see the performance difference
- Initialize in declaration(Vec3_104): 4-5ms
- Initialize in constructor(Vec3_110): 28-32ms
From more complexe use case in our engine's particle system simulation, the fps drops from 60fps to 30fps.
Conclusion
I'd like to suggest a very clear description of different initializer behaviors in TypeScript documentation, so that developers know that they really need to initialize in declaration.
If possible, we'd like TSC to improve the logic:
If developers are using constructor to initialize properties, then use that value for defineProperty directly, or use a type compatible value for defineProperty.
We have also submit an issue to babel which have similar behavior.
Hướng dẫn đóng góp
Bắt đầu từ đâu
- Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
- Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
- Fork repository và làm thay đổi trên một nhánh.
- Mở pull request có tham chiếu số hiệu của issue.
Hướng nghiên cứu
Bắt đầu với trang TypeScript Handbook Classes được liên kết trong issue, sau đó so sánh phần giải thích về việc khởi tạo class của trang này với đề xuất TC39 class fields và ví dụ JavaScript được sinh ra. Công việc được xem là hoàn tất khi đã ghi lại sự khác biệt giữa khai báo và khởi tạo trong constructor, bao gồm hành vi khởi tạo với undefined và mối lo ngại về hiệu năng được mô tả ở đây.
Do mô hình lập chỉ mục viết ra từ nội dung của issue.
Đánh giá
- Công nghệ
- javascript, typescript
- Lĩnh vực
- documentation, performance
- Loại issue
- Tài liệu
- Độ khó
- 2/5
- Thời gian dự kiến
- 1-3 giờ
- Mức độ hoạt động
- Đình trệ
- Độ rõ ràng
- Khá rõ ràng
- Mức phù hợp với người mới
- 38/100