2012-07-05 72 views
32

我嘗試在JavaScript擴展Array對象有一些用戶友好的方法,如Array.Add()代替的Array.push()等數組對象...方式來擴展在JavaScript

我實現了3種方式來做到這一點。 不幸的是,第三種方式不工作,我想問爲什麼?以及如何做到這一點。

//------------- 1st way 
Array.prototype.Add=function(element){ 
    this.push(element); 
}; 

var list1 = new Array(); 
list1.Add("Hello world"); 
alert(list1[0]); 

//------------- 2nd way 
function Array2() { 
    //some other properties and methods 
}; 

Array2.prototype = new Array; 
Array2.prototype.Add = function(element){ 
    this.push(element); 
}; 

var list2 = new Array2; 
list2.Add(123); 
alert(list2[0]); 

//------------- 3rd way 
function Array3() { 
    this.prototype = new Array; 
    this.Add = function(element){ 
     this.push(element); 
    }; 
}; 

var list3 = new Array3; 
list3.Add(456); //push is not a function 
alert(list3[0]); // undefined 

在第三種方式我想擴展Array對象內部的Array3類。 如何做到這一點,以免得到「推動不是一個功能」和「未定義」?

這裏我添加了第四種方式。

//------------- 4th way 
function Array4() { 
    //some other properties and methods 
    this.Add = function(element){ 
     this.push(element); 
    }; 
}; 
Array4.prototype = new Array(); 

var list4 = new Array4(); 
list4.Add(789); 
alert(list4[0]); 

在這裏再次我必須使用原型。 我希望避免在類構造函數之外使用額外的行作爲Array4.prototype。 我想在一個地方有一個緊湊的定義類與所有作品。 但我想我不能這樣做,否則。

+0

如果你添加一個方法到數組,你將破壞數組的foreach() – SpacedMonkey

+0

你看過咖啡腳本嗎?我將用示例更新我的答案 – SMathew

+0

我不會像第一個示例中那樣向Array.prototype添加方法。這是一個考驗。我將創建一個將擴展Array對象的類。例如jsArray。 jsArray對象將是數組,但具有更多功能。 – demosthenes

回答

27

方法名稱應該是小寫。原型不應該在構造函數中修改。

function Array3() { }; 
Array3.prototype = new Array; 
Array3.prototype.add = Array3.prototype.push 
在CoffeeScript中

class Array3 extends Array 
    add: (item)-> 
    @push(item) 

如果你不喜歡的語法,你必須把它從構造函數中延伸, 你唯一的選擇是:

// define this once somewhere 
// you can also change this to accept multiple arguments 
function extend(x, y){ 
    for(var key in y) { 
     if (y.hasOwnProperty(key)) { 
      x[key] = y[key]; 
     } 
    } 
    return x; 
} 


function Array3() { 
    extend(this, Array.prototype); 
    extend(this, { 
     Add: function(item) { 
     return this.push(item) 
     } 

    }); 
}; 

你也可以這樣做

ArrayExtenstions = { 
    Add: function() { 

    } 
} 
extend(ArrayExtenstions, Array.prototype); 



function Array3() { } 
Array3.prototype = ArrayExtenstions; 

過去,'prototype.js'曾經有一個Class.create方法。你可以換這一切就是這樣

var Array3 = Class.create(Array, { 
    construct: function() { 

    },  
    Add: function() { 

    } 
}); 

有關此的詳細信息以及如何實現的方法,看在prototype.js中源代碼

+0

是的,這是第二種方式。我使用目的添加,而不是添加,因爲我打算寫一些擴展方法,如視覺基本的外觀和感覺。 – demosthenes

+0

好吧我不能使用構造函數內的原型。有什麼辦法在構造函數中擴展Array對象嗎? – demosthenes

+1

是的,但如果必須實例化大量對象,則代價很高。有關示例實現,請參閱http://api.jquery.com/jQuery.extend/。使用這種技術,你可以。函數Array3(){extend(this,{add:function(item){return this.push(item)}})}; – SMathew

2

在第三個示例中,您只需爲對象Array3創建一個名爲prototype的新屬性。當你做new Array3這應該是new Array3(),你正在將該對象實例化爲變量list3。因此,Add方法將不起作用,因爲this(有關對象)沒有有效的方法push。希望你能理解。

編輯:檢查出Understanding JavaScript Context瞭解更多關於this

+0

我看到,this.prototype被視爲Array3的屬性,謝謝 – demosthenes

+1

也不要忘記在實例化對象時添加'()'。 'Array'也是一個對象,所以'new Array()'(或者簡單地說'']')。它的作用是因爲瀏覽器很聰明。 – elclanrs

+0

好吧,我會加()感謝提示elclanrs :) – demosthenes

0

你是否想要做更復雜的事情,然後添加一個別名稱爲「添加」的「推」?

如果沒有,最好避免這樣做。我建議這是一個壞主意的原因是,因爲數組是一個內置的JavaScript類型,修改它會導致所有腳本數組類型有你的新的「添加」方法。與其他第三方發生名稱衝突的可能性很高,可能會導致第三方腳本失去支持您的方法。

我的一般規則是,如果輔助函數不存在於某個地方,那麼可以使用輔助函數來處理數組,如果它非常必要的話,那麼只能擴展數組。

+0

現在我只是學習一些關於js的新東西。我想寫一些擴展方法讓js看起來像Visual Basic核心函數。這對我寫作網站項目來說更適合和更容易。 – demosthenes

+0

聽起來很不錯!正是你需要了解更多的JS。 – elclanrs

+0

當然我用它在不同的名字空間 – demosthenes

0

不能擴展數組對象在JavaScript中。

相反,您可以做的是定義一個對象,該對象將包含在Array上執行的函數列表,並將這些函數注入該Array實例並返回這個新的Array實例。你不應該做的是改變Array.prototype以包括你的自定義功能的列表。

例子:

function MyArray() { 
    var tmp_array = Object.create(Array.prototype); 
    tmp_array = (Array.apply(tmp_array, arguments) || tmp_array); 
    //Now extend tmp_array 
    for(var meth in MyArray.prototype) 
    if(MyArray.prototype.hasOwnProperty(meth)) 
     tmp_array[meth] = MyArray.prototype[meth]; 
    return (tmp_array); 
} 
//Now define the prototype chain. 
MyArray.prototype = { 
    customFunction: function() { return "blah blah"; }, 
    customMetaData: "Blah Blah", 
} 

只是一個示例代碼,你可以修改它,但是你想使用。但我建議你遵循的基本概念仍然是一樣的。

+0

我發現分配'prototype'是不好的做法。分配現有'prototype'對象的屬性總是更好。 – jchook

+1

你說你不能擴展數組對象,但承認向Array.prototype添加函數是可能的......你的答案似乎與我矛盾 – Purefan

+1

@Purefan - 這可能是矛盾的,但它有助於理解Javascript做什麼(和不)做 - 這對JS世界以外的人來說是違反直覺的。 –

9

ES6

class SubArray extends Array { 
    constructor(...args) { 
     super(...args); 
    } 
    last() { 
     return this[this.length - 1]; 
    } 
} 
var sub = new SubArray(1, 2, 3); 
sub // [1, 2, 3] 
sub instanceof SubArray; // true 
sub instanceof Array; // true 

Using __proto__

(舊答案,不推薦使用,可能會導致performance issues

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

現在,您可以將您的方法來SubArray

SubArray.prototype.last = function() { 
    return this[this.length - 1]; 
}; 

初始化像正常的陣列

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

行爲像正常的陣列

sub instanceof SubArray; // true 
sub instanceof Array; // true 
+1

雖然在大多數JavaScript實現中都支持'__proto__',但在被標記爲es6中的遺留功能之前,它不是標準功能。如果使用量很大,它也會導致性能問題。使用它通常是一個壞主意。 – Insomniac

+0

@ TBotV63同意。在es6中,您可以簡單地擴展Array類。更新我的回答 – laggingreflex

+1

你應該在你的'constructor'值傳遞給'super',像這樣: '構造函數(...項){超(...項)}' –

0

前段時間我讀過約翰寫的書的JavaScript忍者 Resig的創作者的jQuery。 他提出了一種使用普通對象模仿類似數組的方法。基本上只需要length

var obj = { 
    length: 0, 
    add: function(elem){ 
     Array.prototype.push.call(this, elem); 
    }, 
    filter: function(callback) { 
     return Array.prototype.filter.call(this, callback); //or provide your own implemetation 
    } 
}; 

obj.add('a'); 
obj.add('b'); 
console.log(obj.length); //2 
console.log(obj[0], obj[1]); //'a', 'b' 

我並不是說它的好壞。這是執行Array操作的原始方式。好處是你不會擴展Array prototype。 請記住,obj是一個普通的object,它不是Array。因此obj instanceof Array將返回false。將obj認爲是立面

如果代碼是你的興趣,閱​​讀摘錄4.10模擬陣列狀的方法

1

您還可以在ES6用這樣的方式:

Object.assign(Array.prototype, { 
    unique() { 
     return this.filter((value, index, array) => { 
     return array.indexOf(value) === index; 
     }); 
    } 
}); 

結果:

let x = [0,1,2,3,2,3]; 
let y = x.unique(); 
console.log(y); // => [0,1,2,3] 
+0

這擴展了數組原型,不應該完成(因爲它會影響整個站點) –

0
var SubArray = function() {           
    var arrInst = new Array(...arguments); // spread arguments object 
    /* Object.getPrototypeOf(arrInst) === Array.prototype */ 
    Object.setPrototypeOf(arrInst, SubArray.prototype);  //redirectionA 
    return arrInst; // now instanceof SubArray 
}; 

SubArray.prototype = { 
    // SubArray.prototype.constructor = SubArray; 
    constructor: SubArray, 

    // methods avilable for all instances of SubArray 
    add: function(element){return this.push(element);}, 
    ... 
}; 

Object.setPrototypeOf(SubArray.prototype, Array.prototype); //redirectionB 

var subArr = new SubArray(1, 2); 
subArr.add(3); subArr[2]; // 3 

答案是一個緊湊的解決方法,因爲打算在所有支持的瀏覽器,其工作原理。