2013-09-23 70 views
2

我試圖子類Array,遵循this article中給出的想法和建議。試圖實現一個簡單的「子類」數組子類

這個子類Array的一個重要目標,在這裏我打電話ArrayBase,它本身比Array本身更直接。我發現實現這個目標非常困難。 (但可能這樣看我,因爲我是一個JavaScript的n00b!)

下面是ArrayBase的實現,是思想的基礎上提出了前面引用的文章towards the end,用我自己的一些改進。我還包含了一個實現ArrayBase.slice,因爲它說明了方案的一個問題。

function ArrayBase() { 
    var arr = Array.prototype.constructor.apply(null, arguments); 
    var ctor = arr.constructor = arguments.callee; 
    arr.__proto__ = ctor.prototype; 
    return arr; 
} 

ArrayBase.prototype = new Array; 
ArrayBase.prototype.slice = function() { 
    var ctor = this.constructor; 
    return ctor.apply(null, 
        Array.prototype.slice.apply(this, arguments)); 
} 

var a0 = new ArrayBase(0, 1, 2, 3); 
var a1 = a0.slice(2);     // [2, 3] 
console.log(a1 instanceof ArrayBase); // true 
console.log(a1 instanceof Array);  // true 

到目前爲止,這麼好。當我現在嘗試子類ArrayBase時,問題就會發生。我發現要做到這一點的唯一方法需要基本上覆制整個ArrayBase構造函數(唯一的區別,非常輕微,發生在第一行)。作爲繼承去,這是可憐...

function MyArray() { 
    var arr = ArrayBase.apply(this, arguments); 
    var ctor = arr.constructor = arguments.callee; 
    arr.__proto__ = ctor.prototype; 
    return arr; 
} 
MyArray.prototype = new ArrayBase; 

// behavior of MyArray 

var a2 = new MyArray(1, 2, 3, 0); 
var a3 = a2.slice(1);     // [2, 3, 0] 
console.log(a3 instanceof MyArray); // true 
console.log(a3 instanceof ArrayBase); // true 
console.log(a3 instanceof Array);  // true 
console.log(a3.join(':'));   // "2:3:0" 
a3[5] = 1; 
console.log(a3.length);    // 6 
a3.length = 2; 
console.log(a3.toString())   // "2,3" 

我的問題:

怎麼可能在ArrayBase和構造之間存在重複,被淘汰,同時仍保留由所示的行爲行後// behavior of MyArr行?該計劃是否也可以在子類別下工作?

(我所知道的對建築遺產的高塔的爭論,但無論是設計好與否,我希望他們至少穩健實施。)


如果我認爲它應該是Array的繼承,那就沒有必要實現ArrayBase.slice,但遺憾的是ArrayBase繼承自Arrayslice方法沒有顯示返回對象的基本OOP禮貌與this相同。

+0

只是之前的一個問題:您是否在IE上檢查過它?我只是希望你好運。說真的,我不推薦從本地對象繼承,它會導致很多問題。 –

回答

2

之前回答你的問題,在代碼中的一些評論:-)

var arr = Array.prototype.constructor.apply(null, arguments); 

由於Array.prototype.constructor === Array,不重複這一點。

var ctor = arr.constructor = … 

沒有理由在這裏創建屬性。如果constructor屬性需要任何東西,它應該從該構造函數的.prototype對象繼承。

arguments.callee; 

不要使用過時arguments.callee!你知道它指向ArrayBase

arr.__proto__ = ctor.prototype; 

你可能已經知道__proto__是非標準(和不特別是不能在IE瀏覽),但是我們在這裏需要它爲原型的注射技術。不過,不要忘記這個事實!

ArrayBase.prototype = new Array; 

not use new for setting up inheritance!你不想在這裏調用一個初始化器(即「構造器」)。改爲使用Object.create

現在,回到你的問題:

怎麼能說我的ArrayBase和構造之間存在重複被淘汰?

其實你已經使用過這個概念了。您的ArrayBase.prototype.slice實現適用於每個子類 - 再次構造this.constructor的實例。您可以使用ArrayBase構造函數的相同方法:

function ArrayBase() { 
    var arr = Array.apply(null, arguments); 
    var ctor = this.constructor; 
    arr.__proto__ = ctor.prototype; 
    return arr; 
} 
/* irrelevant for the answer, but helpful: 
ArrayBase.prototype = Object.create(Array.prototype, { 
    constructor: {value: ArrayBase} 
}); 
Object.keys(Array.prototype).forEach(function(k) { 
    if (typeof Array.prototype[k] != "function") return; 
    ArrayBase.prototype[k] = function() { 
    var arr = Array.prototype[k].apply(this, arguments); 
    if (Array.isArray(arr)) 
     arr.__proto__ = Object.getPrototypeOf(this); 
    return arr; 
    }; 
}); 
*/ 
function MyArray() { 
    return ArrayBase.apply(this, arguments); 
} 
MyArray.prototype = Object.create(ArrayBase.prototype, { 
    constructor: {value: MyArray} 
});