Câu hỏi Javascript - Tạo cá thể với mảng đối số


Tôi biết khả năng gọi một hàm với một mảng các đối số có áp dụng (obj, args); Có cách nào để sử dụng tính năng này khi tạo một thể hiện mới của một hàm không?

Tôi có nghĩa là một cái gì đó như thế này:

function A(arg1,arg2){
    var a = arg1;
    var b = arg2;
}

var a = new A.apply([1,2]); //create new instance using an array of arguments

Tôi hy vọng bạn hiểu ý tôi ... ^^^

Cảm ơn bạn đã giúp đỡ!

Giải quyết!

Tôi có câu trả lời đúng. Để làm cho câu trả lời phù hợp với câu hỏi của tôi:

function A(arg1,arg2) {
    var a = arg1;
    var b = arg2;
}

var a = new (A.bind.apply(A,[A,1,2]))();

24
2018-02-20 02:48


gốc


Lưu ý quan trọng: không quan trọng yếu tố đầu tiên của mảng đó là gì. Ví dụ, new (A.bind.apply(A,['cats',1,2]))(); cũng sẽ hoạt động tốt. Lý do cho điều này là new bỏ qua this giá trị được cung cấp để ràng buộc. - Nikolai
Với phiên bản viết tắt được cung cấp, bạn không cần hai dấu ngoặc kép cuối cùng (). Vì vậy nó có thể là: var a = new (A.bind.apply(A, [null].concat([1, 2]))); - Daniel


Các câu trả lời:


var wrapper = function(f, args) {
    return function() {
        f.apply(this, args);
    };
};

function Constructor() {
    this.foo = 4;
}
var o = new (wrapper(Constructor, [1,2]));
alert(o.foo);

Chúng ta lấy một hàm và các đối số và tạo ra một hàm áp dụng các đối số cho hàm đó với phạm vi này.

Sau đó, nếu bạn gọi nó bằng từ khóa mới, nó sẽ chuyển sang một từ mới this và trả lại nó.

Điều quan trọng là dấu ngoặc

new (wrapper(Constructor, [1,2])) 

Gọi từ khóa mới trên hàm được trả về từ trình bao bọc, trong đó

new wrapper(Constructor, [1,2])

Gọi từ khóa mới trên hàm bao bọc.

Lý do nó cần phải được bọc là để this mà bạn áp dụng nó vào được đặt bằng từ khóa mới. Mới this đối tượng cần được tạo và chuyển vào một hàm có nghĩa là bạn phải gọi .apply(this, array) bên trong một hàm.

Trực tiếp thí dụ

Hoặc bạn có thể sử dụng ES5 .bind phương pháp

var wrapper = function(f, args) {
    var params = [f].concat(args);
    return f.bind.apply(f, params);
};

Xem thí dụ


13
2018-02-20 02:51



Rất đẹp. +1 Tòa nhà của bạn, có thể là mong muốn wrappertrả về hàm cho biến có số nhận dạng bạn muốn để bạn có thể gọi new từ đó, cho instanceof kết quả bạn mong đợi. jsfiddle.net/pSpz8/2 - user113716
... hay không (với jsFiddle của tôi). Sau một giấc ngủ, tôi thấy rằng tôi đã bỏ lỡ điểm của câu hỏi. - user113716
@patrickdw không sao đâu. Bạn không thể tuyệt vời mỗi ngày. - Raynos
Cảm ơn, điều này thực sự tốt. Nhưng vấn đề là, đối tượng được tạo ra, không phải kiểu Constructor. Có cách nào để tránh điều này không? - Van Coding
Lưu ý quan trọng: nó không quan trọng mảng bạn concat với, miễn là nó chứa chính xác một phần tử. Ví dụ, var params = ['cats'].concat(args); cũng sẽ hoạt động tốt. Lý do cho điều này là new bỏ qua this giá trị được cung cấp để ràng buộc. - Nikolai


với ECMAscript 5 bạn có thể:

function createInstanceWithArguments (fConstructor, aArgs) {
    var foo = Object.create(fConstructor.prototype);
    fConstructor.apply(foo, aArgs);
    return foo;
}

6
2018-02-23 07:19





Câu trả lời @Raynos hoạt động tốt, ngoại trừ phiên bản không phải của ES5 là thiếu nguyên mẫu của hàm tạo sau khi khởi tạo.

Đây là cập nhật của tôi cApply phương pháp:

var cApply = function(c) {
  var ctor = function(args) {
    c.apply(this, args);
  };
  ctor.prototype = c.prototype;
  return ctor;
};

Mà có thể được sử dụng như thế này:

var WrappedConstructor = cApply(Constructor);
var obj = new WrappedConstructor([1,2,3]);

// or inline like this.    
var obj2 = new (cApply(Constructor))([1,2,3]);

JSFiddle để tham khảo.


5
2018-05-01 18:53



Giải pháp tốt nhất - Tôi đã tinh chỉnh giải pháp của bạn để không phải vượt qua một mảng, nhưng sử dụng trình xây dựng bọc như bình thường, ví dụ: new WrappedConstructor(1,2,3). Tôi cũng đã thêm hàm tạo vào mẫu thử nghiệm để đo lường tốt - ngã ba jsfiddle: jsfiddle.net/pBJn4 - Ali
Thật không may, dường như không có cách nào để giữ nguyên hàm tạo ban đầu cho kiểu trả về, điều này sẽ rất tệ cho obj instanceof Constructor các trường hợp - Ali
Chắc chắn đồng ý, hacks như thế này ít hơn tối ưu. ES5 FTW. - Jon Jaques
@Ali Tôi vừa thử nghiệm trong firefox, instanceof trả về true bởi cả hai nhà xây dựng ... - inf3rno


Bạn có thể cà ri các chức năng:

function A(arg1, arg2) {
    // ...
}

function A12() {
    A(1, 2);
}

Bạn thậm chí có thể xây dựng một nhà máy cà ri:

function A_curry() {
    var args = arguments;
    return function () {
        A.apply(null, args);
    };
}

2
2018-02-20 02:51





Bạn có thể dùng Object.create() để xây dựng cá thể mới và gọi hàm tạo trên cá thể sau đó:

var args = [1,2,3];
var instance = Object.create(MyClass.prototype);
MyClass.apply(instance, args);

hoặc trong một dòng:

var instance = MyClass.apply(Object.create(MyClass.prototype), args);

nhưng đừng quên return this; trong MyClass bởi giải pháp dòng đơn này.

Nếu bạn không có Object.create(), thì rất đơn giản để viết một:

Object.create = function (source){
    var Surrogate = function (){};
    Surrogate.prototype = source;
    return new Surrogate();
};

Bạn có thể tùy chọn viết một Function.newInstance() hoặc một Function.prototype.newInstance() chức năng:

Function.newInstance = function (fn, args){
    var instance = Object.create(fn.prototype);
    fn.apply(instance, args);
    return instance;
};

vì thế var instance = Function.newInstance(MyClass, args);.

lưu ý: Không nên ghi đè lên các lớp gốc.


2
2017-09-05 14:27





Điều gì nếu bạn có tên lớp đối tượng của bạn được lưu trữ trong một biến gọi là className ?

var className = 'A'

Theo câu trả lời này ở đây tất cả trở nên rất sạch sẽ và đơn giản khi sử dụng ECMAScipt5'S Function.prototype.bind phương pháp.

Với một mảng các đối số:

new ( Function.prototype.bind.apply( className, arguments ) );

Hoặc với một danh sách đối số:

new ( Function.prototype.bind.call( className, argument1, argument2, ... ) );

Một dòng duy nhất, không cần một trình bao bọc.


0
2018-03-04 08:32





Tôi chỉ có cùng một vấn đề và cũng muốn giữ lại các đặc tính nguyên mẫu của đối tượng đích. Sau khi nhìn vào các câu trả lời, chỉ cần đưa ra một giải pháp khá đơn giản. Nghĩ rằng tôi cũng có thể chia sẻ nó cho bất kỳ người tìm kiếm trong tương lai :)

// Define a pseudo object that takes your arguments as an array
var PseudoObject = function (args) {
    OtherObject.apply(this, args);
};
// if you want to inherit prototype as well
PseudoObject.prototype = new OtherObject();

// Now just use the PseudoObject to instantiate a object of the the OtherObject
var newObj = new PseudoObject([1, 2, 3]);

0
2017-12-20 00:43