使用 null 初始化对象属性

所有现代 JavaScript JIT 编译器都试图根据预期的对象结构优化代码。一些小费从 MDN

幸运的是,对象和属性通常是可预测的,在这种情况下,它们的底层结构也是可预测的。JIT 可以依靠它来更快地进行可预测的访问。

使对象可预测的最佳方法是在构造函数中定义整个结构。因此,如果你要在创建对象后添加一些额外的属性,请使用 null 在构造函数中定义它们。这将有助于优化器预测其整个生命周期中的对象行为。但是,所有编译器都有不同的优化器,并且性能提升可能不同,但总体而言,最好在构造函数中定义所有属性,即使它们的值尚未知晓。

一些测试的时间。在我的测试中,我正在创建一个带有 for 循环的一些类实例的大数组。在循环中,我在数组初始化之前为所有对象的 x 属性分配相同的字符串。如果构造函数使用 null 初始化 x 属性,则数组总是处理得更好,即使它正在执行额外的语句。

这是代码:

function f1() {
    var P = function () {
        this.value = 1
    };
    var big_array = new Array(10000000).fill(1).map((x, index)=> {
        p = new P();
        if (index > 5000000) {
            p.x = "some_string";
        }

        return p;
    });
    big_array.reduce((sum, p)=> sum + p.value, 0);
}

function f2() {
    var P = function () {
        this.value = 1;
        this.x = null;
    };
    var big_array = new Array(10000000).fill(1).map((x, index)=> {
        p = new P();
        if (index > 5000000) {
            p.x = "some_string";
        }

        return p;
    });
    big_array.reduce((sum, p)=> sum + p.value, 0);
}

(function perform(){
    var start = performance.now();
    f1();
    var duration = performance.now() - start;

    console.log('duration of f1  ' + duration);

    start = performance.now();
    f2();
    duration = performance.now() - start;

    console.log('duration of f2 ' + duration);
})()

这是 Chrome 和 Firefox 的结果。

       FireFox     Chrome
 --------------------------
 f1      6,400      11,400
 f2      1,700       9,600   

我们可以看到,两者之间的性能改进非常不同。