Tôi dường như không thể tìm ra cách nạp chồng toán tử [] trong javascript. Có ai biết không?
Tôi đang suy nghĩ về ...
MyClass.operator.lookup(index)
{
return myArray[index];
}
hay là tôi không nhìn vào những điều đúng đắn.
Tôi dường như không thể tìm ra cách nạp chồng toán tử [] trong javascript. Có ai biết không?
Tôi đang suy nghĩ về ...
MyClass.operator.lookup(index)
{
return myArray[index];
}
hay là tôi không nhìn vào những điều đúng đắn.
MyClass
đối tượng của bạn thành một mảng. Bạn có thể sao chép các khóa và giá trị từ đối tượng myArray
của mình var myObj = new MyClass()
.
Câu trả lời:
Bạn không thể quá tải các toán tử trong JavaScript.
Nó đã được đề xuất cho ECMAScript 4 nhưng bị từ chối.
Tôi không nghĩ bạn sẽ sớm thấy nó.
Object arg1: a arg2: b arg3: c
như Object["arg1:arg2:arg3:"](a,b,c)
. Vì vậy, bạn có thể có myObject["[]"](1024)
: P
target[name]
trong getter, OP chỉ hiển thị các ví dụ
[]
nhà điều hành cũng vậy, btw:var key = 'world';
console.log(proxy[key]);
Câu trả lời đơn giản là JavaScript cho phép truy cập vào phần con của một Đối tượng thông qua dấu ngoặc vuông.
Vì vậy, bạn có thể xác định lớp của mình:
MyClass = function(){
// Set some defaults that belong to the class via dot syntax or array syntax.
this.some_property = 'my value is a string';
this['another_property'] = 'i am also a string';
this[0] = 1;
};
Sau đó, bạn sẽ có thể truy cập các thành viên trên bất kỳ trường hợp nào trong lớp của bạn bằng một trong hai cú pháp.
foo = new MyClass();
foo.some_property; // Returns 'my value is a string'
foo['some_property']; // Returns 'my value is a string'
foo.another_property; // Returns 'i am also a string'
foo['another_property']; // Also returns 'i am also a string'
foo.0; // Syntax Error
foo[0]; // Returns 1
foo['0']; // Returns 1
foo['random']
điều mà mã của bạn không thể làm được.
Sử dụng proxy. Nó đã được đề cập ở những nơi khác trong câu trả lời nhưng tôi nghĩ rằng đây là một ví dụ tốt hơn:
var handler = {
get: function(target, name) {
if (name in target) {
return target[name];
}
if (name == 'length') {
return Infinity;
}
return name * name;
}
};
var p = new Proxy({}, handler);
p[4]; //returns 16, which is the square of 4.
Vì toán tử dấu ngoặc thực sự là toán tử truy cập thuộc tính, bạn có thể kết nối nó với getters và setters. Đối với IE, bạn sẽ phải sử dụng Object.defineProperty () để thay thế. Thí dụ:
var obj = {
get attr() { alert("Getter called!"); return 1; },
set attr(value) { alert("Setter called!"); return value; }
};
obj.attr = 123;
Tương tự cho IE8 +:
Object.defineProperty("attr", {
get: function() { alert("Getter called!"); return 1; },
set: function(value) { alert("Setter called!"); return value; }
});
Đối với IE5-7, onpropertychange
chỉ có sự kiện, hoạt động cho các phần tử DOM, nhưng không hoạt động cho các đối tượng khác.
Hạn chế của phương pháp này là bạn chỉ có thể kết nối các yêu cầu đối với tập thuộc tính được xác định trước, không phải thuộc tính tùy ý mà không có bất kỳ tên được xác định trước nào.
obj['any_key'] = 123;
nhưng những gì tôi thấy trong mã của bạn, tôi cần xác định setter / getter cho bất kỳ khóa nào (chưa được biết đến). Đó là điều không thể.
Bạn cần phải sử dụng Proxy như được giải thích, nhưng nó cuối cùng có thể được tích hợp vào một lớp học xây dựng
return new Proxy(this, {
set: function( target, name, value ) {
...}};
Với cái này'. Sau đó, các chức năng set và get (cũng deleteProperty) sẽ kích hoạt. Mặc dù bạn nhận được một đối tượng Proxy có vẻ khác nhưng nó hoạt động để yêu cầu so sánh (target.constructor === MyClass) đó là loại lớp, v.v. [mặc dù đó là một hàm trong đó target.constructor.name là tên lớp trong văn bản (chỉ cần lưu ý một ví dụ về những thứ hoạt động hơi khác một chút.)]
Vì vậy, bạn đang hy vọng làm một cái gì đó như var anything = MyClassInstance [4]; ? Nếu vậy, câu trả lời đơn giản là Javascript hiện không hỗ trợ nạp chồng toán tử.
một cách lén lút để làm điều này là mở rộng ngôn ngữ của chính nó.
xác định quy ước lập chỉ mục tùy chỉnh, hãy gọi nó là "[]".
var MyClass = function MyClass(n) {
this.myArray = Array.from(Array(n).keys()).map(a => 0);
};
Object.defineProperty(MyClass.prototype, "[]", {
value: function(index) {
return this.myArray[index];
}
});
...
var foo = new MyClass(1024);
console.log(foo["[]"](0));
xác định một triển khai eval mới. (không làm theo cách này, nhưng đó là một bằng chứng về khái niệm).
var MyClass = function MyClass(length, defaultValue) {
this.myArray = Array.from(Array(length).keys()).map(a => defaultValue);
};
Object.defineProperty(MyClass.prototype, "[]", {
value: function(index) {
return this.myArray[index];
}
});
var foo = new MyClass(1024, 1337);
console.log(foo["[]"](0));
var mini_eval = function(program) {
var esprima = require("esprima");
var tokens = esprima.tokenize(program);
if (tokens.length == 4) {
var types = tokens.map(a => a.type);
var values = tokens.map(a => a.value);
if (types.join(';').match(/Identifier;Punctuator;[^;]+;Punctuator/)) {
if (values[1] == '[' && values[3] == ']') {
var target = eval(values[0]);
var i = eval(values[2]);
// higher priority than []
if (target.hasOwnProperty('[]')) {
return target['[]'](i);
} else {
return target[i];
}
return eval(values[0])();
} else {
return undefined;
}
} else {
return undefined;
}
} else {
return undefined;
}
};
mini_eval("foo[33]");
ở trên sẽ không hoạt động đối với các chỉ mục phức tạp hơn nhưng nó có thể được phân tích cú pháp mạnh hơn.
thay vì dùng đến việc tạo ngôn ngữ superset của riêng bạn, bạn có thể biên dịch ký hiệu của mình sang ngôn ngữ hiện có, sau đó đánh giá nó. Điều này làm giảm chi phí phân tích cú pháp thành gốc sau lần đầu tiên bạn sử dụng nó.
var compile = function(program) {
var esprima = require("esprima");
var tokens = esprima.tokenize(program);
if (tokens.length == 4) {
var types = tokens.map(a => a.type);
var values = tokens.map(a => a.value);
if (types.join(';').match(/Identifier;Punctuator;[^;]+;Punctuator/)) {
if (values[1] == '[' && values[3] == ']') {
var target = values[0];
var i = values[2];
// higher priority than []
return `
(${target}['[]'])
? ${target}['[]'](${i})
: ${target}[${i}]`
} else {
return 'undefined';
}
} else {
return 'undefined';
}
} else {
return 'undefined';
}
};
var result = compile("foo[0]");
console.log(result);
console.log(eval(result));
Chúng tôi có thể nhận proxy | thiết lập các phương thức trực tiếp. Lấy cảm hứng từ điều này .
class Foo {
constructor(v) {
this.data = v
return new Proxy(this, {
get: (obj, key) => {
if (typeof(key) === 'string' && (Number.isInteger(Number(key)))) // key is an index
return obj.data[key]
else
return obj[key]
},
set: (obj, key, value) => {
if (typeof(key) === 'string' && (Number.isInteger(Number(key)))) // key is an index
return obj.data[key] = value
else
return obj[key] = value
}
})
}
}
var foo = new Foo([])
foo.data = [0, 0, 0]
foo[0] = 1
console.log(foo[0]) // 1
console.log(foo.data) // [1, 0, 0]