ฉันไม่สามารถหาวิธีในการโอเวอร์โหลดโอเปอเรเตอร์ [] ในจาวาสคริปต์ได้ มีใครรู้บ้าง?
ฉันกำลังคิดเกี่ยวกับ ...
MyClass.operator.lookup(index)
{
return myArray[index];
}
หรือฉันไม่ได้มองสิ่งที่ถูกต้อง
ฉันไม่สามารถหาวิธีในการโอเวอร์โหลดโอเปอเรเตอร์ [] ในจาวาสคริปต์ได้ มีใครรู้บ้าง?
ฉันกำลังคิดเกี่ยวกับ ...
MyClass.operator.lookup(index)
{
return myArray[index];
}
หรือฉันไม่ได้มองสิ่งที่ถูกต้อง
MyClass
วัตถุของคุณเป็นอาร์เรย์ คุณสามารถคัดลอกคีย์และค่าจากmyArray
ไปยังvar myObj = new MyClass()
วัตถุของคุณ
คำตอบ:
คุณไม่สามารถโอเวอร์โหลดโอเปอเรเตอร์ใน JavaScript ได้
ได้รับการเสนอสำหรับ ECMAScript 4แต่ถูกปฏิเสธ
ฉันไม่คิดว่าคุณจะได้เห็นมันเร็ว ๆ นี้
Object arg1: a arg2: b arg3: c
Object["arg1:arg2:arg3:"](a,b,c)
ดังนั้นคุณสามารถมีmyObject["[]"](1024)
: P
คุณสามารถทำได้ด้วย ES6 Proxy (มีให้ในเบราว์เซอร์สมัยใหม่ทั้งหมด )
var handler = {
get: function(target, name) {
return "Hello, " + name;
}
};
var proxy = new Proxy({}, handler);
console.log(proxy.world); // output: Hello, world
target[name]
ใน getter OP กำลังแสดงตัวอย่าง
[]
ตัวดำเนินการได้เช่นกัน btw:var key = 'world';
console.log(proxy[key]);
คำตอบง่ายๆก็คือ JavaScript อนุญาตให้เข้าถึงลูกของ Object ผ่านวงเล็บเหลี่ยม
ดังนั้นคุณสามารถกำหนดชั้นเรียนของคุณ:
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;
};
จากนั้นคุณจะสามารถเข้าถึงสมาชิกในอินสแตนซ์ของชั้นเรียนของคุณด้วยไวยากรณ์ใดก็ได้
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']
รหัสที่คุณไม่สามารถทำได้
ใช้พร็อกซี มีการกล่าวถึงที่อื่นในคำตอบ แต่ฉันคิดว่านี่เป็นตัวอย่างที่ดีกว่า:
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.
เนื่องจากตัวดำเนินการวงเล็บเป็นตัวดำเนินการเข้าถึงคุณสมบัติคุณสามารถเชื่อมต่อกับ getters และ setters สำหรับ IE คุณจะต้องใช้ Object.defineProperty () แทน ตัวอย่าง:
var obj = {
get attr() { alert("Getter called!"); return 1; },
set attr(value) { alert("Setter called!"); return value; }
};
obj.attr = 123;
เช่นเดียวกับ IE8 +:
Object.defineProperty("attr", {
get: function() { alert("Getter called!"); return 1; },
set: function(value) { alert("Setter called!"); return value; }
});
สำหรับ IE5-7 จะมีonpropertychange
เฉพาะเหตุการณ์ซึ่งใช้ได้กับองค์ประกอบ DOM แต่ไม่ใช่สำหรับวัตถุอื่น ๆ
ข้อเสียเปรียบของวิธีนี้คือคุณสามารถเชื่อมต่อกับคำขอไปยังชุดคุณสมบัติที่กำหนดไว้ล่วงหน้าเท่านั้นไม่ใช่ในคุณสมบัติที่กำหนดเองโดยไม่มีชื่อที่กำหนดไว้ล่วงหน้า
obj['any_key'] = 123;
แต่สิ่งที่ฉันเห็นในโค้ดของคุณฉันจำเป็นต้องกำหนด setter / getter สำหรับคีย์ใด ๆ (ยังไม่ทราบ) ว่าเป็นไปไม่ได้.
คุณต้องใช้ Proxy ตามที่อธิบายไว้ แต่ในที่สุดก็สามารถรวมเข้ากับตัวสร้างคลาสได้
return new Proxy(this, {
set: function( target, name, value ) {
...}};
ด้วยสิ่งนี้'. จากนั้นฟังก์ชัน set and get (รวมถึง deleteProperty) จะเริ่มทำงาน แม้ว่าคุณจะได้รับวัตถุ Proxy ซึ่งดูเหมือนว่าจะแตกต่างกัน แต่ส่วนใหญ่ทำงานเพื่อขอการเปรียบเทียบ (target.constructor === MyClass) เป็นประเภทคลาสเป็นต้น [แม้ว่าจะเป็นฟังก์ชันที่ target.constructor.name เป็นชื่อคลาสใน ข้อความ (เพียงแค่สังเกตตัวอย่างของสิ่งที่ทำงานแตกต่างกันเล็กน้อย)]
ดังนั้นคุณหวังว่าจะทำบางอย่างเช่น var อะไรก็ได้ = MyClassInstance [4]; เหรอ? ถ้าเป็นเช่นนั้นคำตอบง่ายๆก็คือขณะนี้ Javascript ไม่สนับสนุนตัวดำเนินการที่โอเวอร์โหลด
วิธีการส่อเสียดอย่างหนึ่งคือการขยายภาษา
กำหนดรูปแบบการจัดทำดัชนีที่กำหนดเองเรียกว่า "[]"
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));
กำหนดการใช้งาน eval ใหม่ (อย่าทำแบบนี้ แต่เป็นการพิสูจน์แนวคิด)
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]");
ข้างต้นใช้ไม่ได้กับดัชนีที่ซับซ้อนมากขึ้น แต่อาจใช้การแยกวิเคราะห์ที่ชัดเจนกว่า
แทนที่จะใช้การสร้างภาษาซูเปอร์เซ็ตของคุณเองคุณสามารถรวบรวมสัญกรณ์ของคุณเป็นภาษาที่มีอยู่แล้วจึงประเมินได้ ซึ่งจะช่วยลดค่าใช้จ่ายในการแยกวิเคราะห์เป็นเนทีฟหลังจากครั้งแรกที่คุณใช้
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));
เราสามารถรับพร็อกซี| กำหนดวิธีการโดยตรง แรงบันดาลใจจากนี้
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]