我尝试使用一些用户友好的方法(如Array.Add()而不是Array.push()等在javascript中扩展Array对象...
我实现了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
以第三种方式我想在Array3内部扩展Array对象。 如何做到这一点,以免“推不是一个功能”和“未定义”?
在这里我添加了第四种方式。
//------------- 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 :(得分:28)
方法名称应为小写。不应在构造函数中修改原型。
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源代码
答案 1 :(得分:15)
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
__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
答案 2 :(得分:2)
在第三个示例中,您只是为对象prototype
创建名为Array3
的新属性。当您执行new Array3
new Array3()
时,您将该对象实例化为变量list3
。因此,Add
方法无效,因为this
(有问题的对象)没有有效的方法push
。希望你明白。
修改:查看Understanding JavaScript Context以了解有关this
的更多信息。
答案 3 :(得分:2)
不久前,我读了 jQuery 的创建者 John Resig 撰写的 Javascript Ninja 一书。
他提出了一种使用普通JS对象模仿类数组方法的方法。基本上,只需要length
。
var obj = {
length: 0, //only length is required to mimic an Array
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
视为façade。
如果您对该代码感兴趣,请阅读摘录清单4.10模拟类似数组的方法。
答案 4 :(得分:0)
您是否尝试做一些更复杂的事情,然后只为“推送”添加一个名为“添加”的别名?
如果没有,最好避免这样做。我之所以这样做是个坏主意,因为Array是一个内置的javascript类型,修改它会导致所有脚本数组类型都有你的新“添加”方法。与另一个第三方发生名称冲突的可能性很高,可能导致第三方脚本失去其支持您的方法。
我的一般规则是如果一个辅助函数在某个地方不存在,那么就可以使用一个辅助函数来处理它,只有极其必要时才扩展数组。
答案 5 :(得分: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",
}
只是示例代码,您可以根据需要对其进行修改和使用。但我建议你遵循的基本概念保持不变。
答案 6 :(得分:0)
你也可以在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]
答案 7 :(得分: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
答案是一个紧凑的解决方法,可以在所有支持的浏览器中使用。