2011-01-21 55 views
10

我認識到,嚴格來說,這不是繼承數組類型,但會按照人們可能期望的方式工作,還是我仍然會遇到.length等問題?如果正常的子類化是一種選擇,我是否有任何缺點?這是一個合理的方式來'子類'的JavaScript數組?

 function Vector() 
     { 
      var vector = []; 
      vector.sum = function() 
      { 
       sum = 0.0; 
       for(i = 0; i < this.length; i++) 
       { 
        sum += this[i]; 
       } 
       return sum; 
      }    
      return vector; 
     } 

     v = Vector(); 
     v.push(1); v.push(2); 
     console.log(v.sum()); 
+0

有多少這些*矢量*數組你實例化規劃? 2?數百? – 2011-01-21 16:16:57

+0

你忘了一個變種。 `var vector = [];`。 – Thai 2011-01-21 16:17:26

+0

超過成千上萬。 – shino 2011-01-21 16:17:45

回答

7

我包裹適當的載體類型內的陣列是這樣的:

window.Vector = function Vector() { 
    this.data = []; 
} 

Vector.prototype.push = function push() { 
    Array.prototype.push.apply(this.data, arguments); 
} 

Vector.prototype.sum = function sum() { 
    for(var i = 0, s=0.0, len=this.data.length; i < len; s += this.data[i++]); 
    return s; 
} 

var vector1 = new Vector(); 
vector1.push(1); vector1.push(2); 
console.log(vector1.sum()); 

或者,也可以在陣列上建立新的原型函數,然後只用正常的陣列。

如果你符合命名數組,所以它們都以小寫字母v開頭,或者類似的東西,清楚地標記它們,而不是正常的數組,然後你在矢量特定的原型函數上做同樣的事情,那麼它應該很容易跟蹤。

Array.prototype.vSum = function vSum() { 
    for(var i = 0, s=0.0, len=this.length; i < len; s += this[i++]); 
    return s; 
} 

var vector1 = []; 
vector1.push(1); vector1.push(2); 
console.log(vector1.vSum()); 
0

@hvgotcodes答案有awesome link。我只是想總結這裏的結論。

Wrappers. Prototype chain injection

這似乎是從物品延伸陣列的最佳方法。

包裝可用於...在對象的原型鏈增強,而不是對象本身。

function SubArray() { 
    var arr = [ ]; 
    arr.push.apply(arr, arguments); 
    arr.__proto__ = SubArray.prototype; 
    return arr; 
} 
SubArray.prototype = new Array; 

// Add custom functions here to SubArray.prototype. 
SubArray.prototype.last = function() { 
    return this[this.length - 1]; 
}; 

var sub = new SubArray(1, 2, 3); 

sub instanceof SubArray; // true 
sub instanceof Array; // true 

Unfortunally對我來說,這個方法在IE 8使用arr.__proto__,不支持,瀏覽器我要支持。

Wrappers. Direct property injection.

此方法比上述慢一點,但在IE 8-工作。

包裝方法避免設置繼承或模擬長度/索引關係。相反,類似工廠的函數可以創建一個普通的Array對象,然後使用任何自定義方法直接對其進行擴充。由於返回的對象是一個數組,所以它保持適當的長度/索引關係,以及「數組」的[[Class]]。它也自然地從Array.prototype繼承。

function makeSubArray() { 
    var arr = [ ]; 
    arr.push.apply(arr, arguments); 

    // Add custom functions here to arr. 
    arr.last = function() { 
    return this[this.length - 1]; 
    }; 
    return arr; 
} 

var sub = makeSubArray(1, 2, 3); 
sub instanceof Array; // true 

sub.length; // 3 
sub.last(); // 3 
2

只是包裝的另一個例子。與.bind有一些樂趣。

var _Array = function _Array() { 
    if (!(this instanceof _Array)) { 
     return new _Array(); 
    }; 
}; 

_Array.prototype.push = function() { 
    var apContextBound = Array.prototype.push, 
     pushItAgainst = Function.prototype.apply.bind(apContextBound); 

    pushItAgainst(this, arguments); 
}; 

_Array.prototype.pushPushItRealGood = function() { 
    var apContextBound = Array.prototype.push, 
     pushItAgainst = Function.prototype.apply.bind(apContextBound); 

    pushItAgainst(this, arguments); 
}; 

_Array.prototype.typeof = (function() { return (Object.prototype.toString.call([])); }()); 
0

有一種看起來和感覺像原型繼承的方式,但它只有一種方式不同。

首先讓我們來看看在JavaScript實現原型繼承的standard ways之一:

var MyClass = function(bar){ 
    this.foo = bar; 
}; 

MyClass.prototype.awesomeMethod = function(){ 
    alert("I'm awesome") 
}; 

// extends MyClass 
var MySubClass = function(bar){ 
    MyClass.call(this, bar); // <- call super constructor 
} 

// which happens here 
MySubClass.prototype = Object.create(MyClass.prototype); // prototype object with MyClass as its prototype 
// allows us to still walk up the prototype chain as expected 
Object.defineProperty(MySubClass.prototype, "constructor", { 
    enumerable: false, // this is merely a preference, but worth considering, it won't affect the inheritance aspect 
    value: MySubClass 
}); 

// place extended/overridden methods here 
MySubClass.prototype.superAwesomeMethod = function(){ 
    alert("I'm super awesome!"); 
}; 

var testInstance = new MySubClass("hello"); 
alert(testInstance instanceof MyClass); // true 
alert(testInstance instanceof MySubClass); // true 

下面的例子只是包裝了上述結構,以保持清潔的一切。有一點微調,似乎乍看之下表現出奇蹟。然而,所有真正發生的事情是,子類的每個實例不是將Array原型用作構造的模板,而是使用Array的實例 - 因此子類的原型掛接到完全加載的對象的末尾傳遞一個數組的ducktype - 然後它複製。如果你仍然在這裏看到一些奇怪的東西,並且它困擾着你,我不確定我能否更好地解釋它 - 所以也許它是如何工作的是另一個問題的好主題。 :)

var extend = function(child, parent, optionalArgs){ //... 
    if(parent.toString() === "function "+parent.name+"() { [native code] }"){ 
     optionalArgs = [parent].concat(Array.prototype.slice.call(arguments, 2)); 
     child.prototype = Object.create(new parent.bind.apply(null, optionalArgs)); 
    }else{ 
     child.prototype = Object.create(parent.prototype); 
    } 
    Object.defineProperties(child.prototype, { 
     constructor: {enumerable: false, value: child}, 
     _super_: {enumerable: false, value: parent} // merely for convenience (for future use), its not used here because our prototype is already constructed! 
    }); 
}; 
var Vector = (function(){ 
    // we can extend Vector prototype here because functions are hoisted 
    // so it keeps the extend declaration close to the class declaration 
    // where we would expect to see it 
    extend(Vector, Array); 

    function Vector(){ 
     // from here on out we are an instance of Array as well as an instance of Vector 

     // not needed here 
     // this._super_.call(this, arguments); // applies parent constructor (in this case Array, but we already did it during prototyping, so use this when extending your own classes) 

     // construct a Vector as needed from arguments 
     this.push.apply(this, arguments); 
    } 

    // just in case the prototype description warrants a closure 
    (function(){ 
     var _Vector = this; 

     _Vector.sum = function sum(){ 
      var i=0, s=0.0, l=this.length; 
      while(i<l){ 
       s = s + this[i++]; 
      } 
      return s; 
     }; 
    }).call(Vector.prototype); 

    return Vector; 
})(); 

var a = new Vector(1,2,3);       // 1,2,3 
var b = new Vector(4,5,6,7);      // 4,5,6,7 
alert(a instanceof Array && a instanceof Vector); // true 
alert(a === b);         // false 
alert(a.length);         // 3 
alert(b.length);         // 4 
alert(a.sum());         // 6 
alert(b.sum());         // 22 

不久,我們將不得不類,並在ES6延長本機類的能力,但可能是一個又一年。同時我希望這可以幫助某人。

0
function SubArray(arrayToInitWith){ 
    Array.call(this); 
    var subArrayInstance = this; 
    subArrayInstance.length = arrayToInitWith.length; 
    arrayToInitWith.forEach(function(e, i){ 
    subArrayInstance[i] = e; 
    }); 
} 

SubArray.prototype = Object.create(Array.prototype); 
SubArray.prototype.specialMethod = function(){alert("baz");}; 

var subclassedArray = new SubArray(["Some", "old", "values"]); 
0

這裏有很多很好的方法。就我個人而言,我認爲子類化「數組」的最佳方式不是實際數組的子類,而是子類「數組 - 類 - 對象」。他們中有很多人,我個人使用Collection

http://codepen.io/dustinpoissant/pen/AXbjxm?editors=0011

var MySubArray = function(){ 
    Collection.apply(this, arguments); 
    this.myCustomMethod = function(){ 
    console.log("The second item is "+this[1]); 
    }; 
}; 
MySubArray.prototype = Object.create(Collection.prototype); 

var msa = new MySubArray("Hello", "World"); 
msa[2] = "Third Item"; 
console.log(msa); 
msa.myCustomMethod(); 
0

現在你可以使用子類與ES6類:

class Vector extends Array { 
    sum(){ 
    return this.reduce((total, value) => total + value) 
    } 
} 

let v2 = new Vector(); 
v2.push(1); 
v2.push(2); 
console.log(v2.sum()) 
相關問題