私はArray.Push()などの代わりにArray.Add()のようないくつかのユーザーフレンドリーなメソッドでjavascriptのArrayオブジェクトを拡張しようとします...
これを行う3つの方法を実装します。残念ながら、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
3番目の方法では、Arrayオブジェクトを内部的にArray3クラスに拡張したいです。 「プッシュは関数ではありません」および「未定義」にならないようにこれを行う方法は?
ここで、4番目の方法を追加します。
//------------- 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としてクラスコンストラクターの外側に余分な行を使用しないようにしたかった。すべてのピースを1か所に収めたコンパクトな定義済みクラスが必要でした。しかし、そうでなければできないと思います。
メソッド名は小文字でなければなりません。プロトタイプをコンストラクターで変更しないでください。
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のソースコードをご覧ください
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__
を使用(推奨されない古い答えは、 パフォーマンスの問題 を引き起こす可能性があります)
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
少し前に私は本を読んだJavascript NinjaJohn Resig、jQuery彼は、単純な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配列のようなメソッドのシミュレーション.
3番目の例では、オブジェクト_Array3
_に対してprototype
という名前の新しいプロパティを作成しています。 new Array3()
である_new Array3
_を実行すると、そのオブジェクトを変数_list3
_にインスタンス化します。したがって、問題のオブジェクトであるAdd
には有効なメソッドthis
がないため、Push
メソッドは機能しません。ご理解ください。
編集:this
の詳細については、 JavaScriptコンテキストについて をご覧ください。
「追加」と呼ばれる「プッシュ」のエイリアスを追加するよりも複雑なことをしようとしていますか?
そうでなければ、おそらくこれを避けるのが最善でしょう。これが悪いアイデアだと思う理由は、Arrayは組み込みのJavaScriptタイプであるため、変更するとすべてのスクリプトのArrayタイプに新しい「追加」メソッドが設定されるためです。他のサードパーティと名前が衝突する可能性が高く、サードパーティスクリプトがメソッドを失い、自分のスクリプトが優先される可能性があります。
私の一般的なルールは、ヘルパー関数が既に存在しない場合は配列で動作し、非常に必要な場合にのみ配列を拡張するようにすることです。
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
答えは、すべてのサポートするブラウザーで意図したとおりに機能するコンパクトな回避策です。
JavaScriptで配列オブジェクトを拡張することはできません。
代わりに、できることは、配列で実行する関数のリストを含むオブジェクトを定義し、それらの関数をその配列インスタンスに注入して、この新しい配列インスタンスを返すことです。すべきではないことは、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",
}
単なるサンプルコードです。修正して、好きなように使用できます。しかし、従うことをお勧めする基本概念は同じままです。
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]