2012-07-05 45 views
32

Tôi cố gắng mở rộng đối tượng mảng trong javascript bằng một số phương thức thân thiện với người dùng như Array.Add() thay vì Array.push(), v.v ...Cách mở rộng đối tượng mảng trong javascript

tôi thực hiện 3 cách để thực hiện việc này . không may là cách thứ 3 không hoạt động và tôi muốn hỏi tại sao? và cách thực hiện.

//------------- 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 

theo cách thứ ba tôi muốn mở rộng đối tượng Array bên trong lớp Array3. Làm thế nào để làm điều này để không có được "đẩy không phải là một chức năng" và "không xác định"?

Ở đây tôi thêm một cách thứ tư.

//------------- 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]); 

Ở đây một lần nữa tôi phải sử dụng mẫu thử nghiệm. Tôi hy vọng tránh sử dụng các đường thừa bên ngoài hàm tạo lớp như Array4.prototype. Tôi muốn có một lớp học được định nghĩa nhỏ gọn với tất cả các phần ở một nơi. Nhưng tôi nghĩ rằng tôi không thể làm điều đó nếu không.

+0

Nếu bạn thêm phương thức vào Mảng, bạn sẽ ngắt foreach() trên các mảng – SpacedMonkey

+0

Bạn đã xem tập lệnh cà phê chưa? Tôi sẽ cập nhật câu trả lời của mình với ví dụ – SMathew

+0

tôi sẽ không thêm phương thức vào Array.prototype như trong ví dụ thứ nhất. Đây là một thử nghiệm. Tôi sẽ tạo một lớp sẽ mở rộng đối tượng Array. Ví dụ jsArray. Các đối tượng jsArray sẽ là các mảng nhưng với nhiều tính năng hơn. – demosthenes

Trả lời

27

Tên phương pháp phải là chữ thường. Nguyên mẫu không nên được sửa đổi trong hàm tạo.

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

trong CoffeeScript

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

Nếu bạn không thích cú pháp đó, và bạn phải mở rộng nó từ bên trong các nhà xây dựng, lựa chọn duy nhất của bạn là:

// 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) 
     } 

    }); 
}; 

Bạn cũng có thể làm điều này

ArrayExtenstions = { 
    Add: function() { 

    } 
} 
extend(ArrayExtenstions, Array.prototype); 



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

Trong những ngày cũ, 'prototype.js' được sử dụng để có phương thức Class.create.Bạn có thể bọc tất cả điều này là một phương pháp như thế

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

    },  
    Add: function() { 

    } 
}); 

Để biết thêm thông về vấn đề này và làm thế nào để thực hiện, nhìn vào mã nguồn prototype.js

+0

có đây là cách thứ 2. Tôi sử dụng trong mục đích Thêm thay vì thêm vì tôi có ý định viết một số phương pháp mở rộng như nhìn cơ bản và cảm nhận. – demosthenes

+0

ok tôi không thể sử dụng nguyên mẫu bên trong constructor. Có cách nào để mở rộng đối tượng Array bên trong constructor? – demosthenes

+1

Có, nhưng sẽ rất tốn kém nếu bạn phải khởi tạo rất nhiều đối tượng. Xem http://api.jquery.com/jQuery.extend/ để biết ví dụ về Triển khai. Sử dụng kỹ thuật đó bạn có thể. function Array3() {extend (this, {add: function (item) {return this.push (item)}})}; – SMathew

2

Trong ví dụ thứ ba, bạn chỉ cần tạo thuộc tính mới có tên prototype cho đối tượng Array3. Khi bạn làm new Array3 phải là new Array3(), bạn đang khởi tạo đối tượng đó thành biến list3. Do đó, phương thức Add sẽ không hoạt động vì this, là đối tượng được đề cập, không có phương thức hợp lệ push. Mong là bạn hiểu.

Chỉnh sửa: Khám phá Understanding JavaScript Context để tìm hiểu thêm về this.

+0

tôi thấy, this.prototype được coi là tài sản của Array3, nhờ – demosthenes

+1

Cũng đừng quên thêm '()' khi bạn khởi tạo các đối tượng. 'Array' cũng là một đối tượng nên' new Array() '(hoặc tipically chỉ' [] '). Nó hoạt động vì trình duyệt thông minh. – elclanrs

+0

ok tôi sẽ thêm() cảm ơn cho các elclanrs tip :) – demosthenes

0

Bạn đang cố gắng làm điều gì đó phức tạp hơn sau đó chỉ cần thêm một bí danh cho "đẩy" được gọi là "Thêm"?

Nếu không, tốt nhất nên tránh làm điều này. Lý do tôi đề nghị đây là một ý tưởng tồi là bởi vì Array là một kiểu dựng sẵn javascript, việc sửa đổi nó sẽ khiến cho tất cả các kiểu lệnh Array có phương thức "Add" mới của bạn. Tiềm năng cho các cuộc đụng độ tên với một bên thứ ba khác cao và có thể khiến cho tập lệnh của bên thứ ba mất phương thức của nó để ủng hộ cho bạn.

Quy tắc chung của tôi là tạo một hàm trợ giúp để làm việc trên Array nếu nó không tồn tại ở đâu đó và chỉ mở rộng Mảng nếu nó cực kỳ cần thiết.

+0

bây giờ tôi chỉ học một số điều mới về js. Tôi muốn viết một số phương pháp mở rộng cho js để trông giống như Visual Basic chức năng cốt lõi. Điều này là phù hợp hơn và dễ dàng hơn cho tôi trong việc viết các dự án web. – demosthenes

+0

Âm thanh như một bài tập tuyệt vời! Chỉ cần những gì bạn cần tìm hiểu thêm JS. – elclanrs

+0

tất nhiên tôi sử dụng nó trong một không gian tên khác nhau – demosthenes

0

Bạn không thể mở rộng các mảng Object trong JavaScript. Thay vào đó, những gì bạn có thể làm là định nghĩa một đối tượng sẽ chứa một danh sách các hàm thực hiện trên Array và đưa các hàm này vào cá thể Array đó và trả về cá thể Array mới này. Những gì bạn không nên làm là thay đổi Array.prototype để bao gồm các chức năng tùy chỉnh của bạn trong danh sách.

Ví dụ:

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", 
} 

Chỉ cần một mẫu mã, bạn có thể sửa đổi nó và sử dụng tuy nhiên bạn muốn. Nhưng khái niệm cơ bản mà tôi khuyên bạn nên theo dõi vẫn giữ nguyên.

+0

Tôi thấy thực tiễn không tốt là chỉ định 'nguyên mẫu'. Nó luôn luôn tốt hơn để gán các thuộc tính của đối tượng 'prototype' hiện có. – jchook

+1

Bạn nói rằng bạn không thể mở rộng đối tượng mảng nhưng thừa nhận rằng thêm hàm vào Array.prototype là có thể ... câu trả lời của bạn có vẻ mâu thuẫn với tôi – Purefan

+1

@Purefan - Điều này có thể mâu thuẫn, nhưng nó giúp hiểu được Javascript nào (và không) - có tính phản trực giác đối với những người từ bên ngoài thế giới 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__

(câu trả lời cũ, không được khuyến khích, có thể gây performance issues)

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

Bây giờ bạn có thể thêm các phương pháp của bạn để SubArray

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

Initialize như Mảng bình thường

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

hoạt động như Mảng bình thường

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

Trong khi sử dụng '__proto__' được hỗ trợ trong hầu hết các triển khai JavaScript, nó không phải là một tính năng tiêu chuẩn cho đến khi được đánh dấu là một tính năng kế thừa trong es6. Ngoài ra nó có thể gây ra vấn đề hiệu suất nếu được sử dụng nhiều. Sử dụng nó thường là một ý tưởng tồi. – Insomniac

+0

@ TBotV63 đã đồng ý. trong es6, bạn có thể đơn giản mở rộng một lớp Array.đã cập nhật câu trả lời của tôi – laggingreflex

+1

Bạn nên chuyển các giá trị trong 'constructor' của bạn tới' super', như sau: 'constructor (... items) {super (... items)}' –

0

Một thời gian trước, tôi đọc cuốn sách Javascript Ninja được viết bởi John Resig, tác giả của jQuery. Ông đã đề xuất một cách để bắt chước các phương thức giống mảng với một đối tượng đơn giản. Về cơ bản chỉ có length là bắt buộc.

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' 

Tôi không có ý là tốt hay xấu. Đó là một cách ban đầu để thực hiện các hoạt động Array. Lợi ích là bạn không mở rộng Array prototype. Hãy nhớ rằng obj là đồng bằng object, không phải là Array. Do đó, obj instanceof Array sẽ trả lại false. Hãy suy nghĩ obj làm mặt tiền .

Nếu mã đó bạn quan tâm, hãy đọc đoạn trích Ví dụ 4.10 Mô phỏng các phương pháp giống như mảng.

1

Bạn cũng có thể sử dụng cách này trong ES6:

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

Kết quả:

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

Điều này mở rộng nguyên mẫu Array và không nên được thực hiện (vì nó ảnh hưởng đến toàn bộ trang web) –

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 

Câu trả lời là một cách giải quyết gọn nhẹ mà làm việc như dự định trong tất cả các trình duyệt hỗ trợ.

Các vấn đề liên quan