2017-10-14 28 views
2

請幫助:) - 我不得不檢查性能訪問屬性 - 工廠函數,連續繼承和類,我不明白爲什麼連續繼承失去?畢竟,對連續繼承中複製的屬性的訪問應該是最快的。 我在Chrome上運行測試,Safari和CI總是丟失。從本次測試 https://jsperf.com/factory-function-vs-concatenative-inheritance-get性能訪問屬性 - 工廠函數與連續繼承與類

代碼:

const alien = { 
    sayHello() { 
     return `Hello, my name is ${ this.name }`; 
    } 
    }; 
    //Delegate prototype 
    const createAlienFF = (name) => { 
    return Object.assign(Object.create(alien), { 
     name 
    }); 
    } 
    //Delegate prototype - creating objects 
    var tabFF = []; 
    for(var i = 0; i < 1000; i++) { 
    tabFF[i] = createAlienFF('Clark' + i); 
    } 

    //Concatenative inheritance 
    const createAlienCI = (name) => { 
    return Object.assign( 
     {}, 
     alien, 
     {name: name} 
    ); 
    } 
    //Concatenative inheritance - creating objects 
    var tabCI = []; 
    for(var i = 0; i < 1000; i++) { 
    tabCI[i] = createAlienCI("Clark" + i); 
    } 

    //Class 
    class Alien { 
    constructor(name) { 
     this.name = name 
    } 
    sayHello() { 
     return `Hello, my name is ${ this.name }`; 
    } 
    } 
    //Class - creating objects 
    var tabClass = []; 
    for(var i = 0; i < 1000; i++) { 
    tabClass[i] = new Alien("Clark" + i); 
    } 
    //Tests 
    //1 - Delegate prototype 
    for(var i = 0; i < 1000; i++) { 
    tabFF[i].sayHello(); 
    } 

//2 - Concatenative inheritance 
for(var i = 0; i < 1000; i++) { 
    tabCI[i].sayHello(); 
} 

//3 - Class 
for(var i = 0; i < 1000; i++) { 
    tabClass[i].sayHello(); 
} 
+0

在邊緣它是類和CI之間的聯繫,在Firefox中它是CI的勝利。所以你的問題是關於Webkit的實現細節 –

+0

你可以在問題中包含代碼嗎? – guest271314

+0

我覺得這個測試不夠好。例如,您應該將更復雜的類與更多級別的繼承進行比較。例如,假設你有一個10級的類層次結構。在一個版本中,您將所有內容連接到單個對象上,而在另一個版本中,您將會有一個長達10級的原型鏈。這個較長的原型鏈可能真的顯示出性能的差異。 – trusktr

回答

1

畢竟,獲得了繼承的串連複製的屬性應該是最快的。

你爲什麼這麼認爲?因爲這是一個不需要遍歷原型鏈的直接屬性訪問?

嗯,這可能是一個很好的推理關於一個天真的引擎實現。但是你沒有考慮專門針對繼承的對象模型的優化,使(類)實例的方法訪問速度非常快。看看https://github.com/v8/v8/wiki/Design%20Elements#fast-property-access,https://blog.ghaiklor.com/optimizations-tricks-in-v8-d284b6c8b183,http://richardartoul.github.io/jekyll/update/2015/04/26/hidden-classes.html和偉大的http://mrale.ph/blog/2012/06/03/explaining-js-vms-in-js-inline-caches.html。要點:V8優化了對「已知形狀」對象的訪問方法,即在您的案例中繼承alienAlien.prototype的對象(它們共享相同的隱藏類)。它知道猜測,在你的循環中,只有那個形狀的物體被使用,並且可以推斷出它們全都調用完全相同的功能sayHello函數。這是一個可以從中獲取代碼的固定位置,可以進一步優化內聯等。另一方面,由createAlienCI工廠創建的對象也都具有相同的形狀,但每個對象都包含其各自的sayHello屬性。所有這些屬性可能包含相同的函數對象,但我們無法知道(我們不會猜測它 - 這是一種不尋常的模式)。因此,引擎在調用它之前每次都從每個實例中獲取函數引用 - 至少它知道每個實例中的哪個(在哪個內存偏移量),因爲它們的形狀不變。