Như bạn đã yêu cầu một câu hỏi học tập, tôi cho rằng khả năng tương thích trình duyệt không phải là một vấn đề. Nếu nó thực sự không, tôi muốn giới thiệu proxy hài hòa cho việc này. onerror
không phải là một thực hành rất tốt vì nó chỉ là một sự kiện được nêu ra nếu ở đâu đó xảy ra lỗi. Nó nên, nếu bao giờ hết, chỉ được sử dụng như một phương sách cuối cùng. (Tôi biết bạn nói rằng bạn không sử dụng nó anyway, nhưng onerror
chỉ là không rất thân thiện với nhà phát triển.)
Về cơ bản, proxy cho phép bạn chặn hầu hết các hoạt động cơ bản trong JavaScript - đáng chú ý nhất là bất kỳ tài sản nào hữu ích ở đây. Trong trường hợp này, bạn có thể chặn quy trình nhận .slice
.
Lưu ý rằng proxy là "lỗ đen" theo mặc định. Chúng không tương ứng với bất kỳ đối tượng nào (ví dụ: thiết lập thuộc tính trên proxy chỉ cần gọi bẫy set
(bộ chặn); lưu trữ thực tế bạn phải tự thực hiện). Nhưng có một "handler chuyển tiếp" có sẵn để định tuyến tất cả mọi thứ thông qua một đối tượng bình thường (hoặc một thể hiện của khóa học), để proxy hoạt động như một đối tượng bình thường. Bằng cách mở rộng trình xử lý (trong trường hợp này là phần get
), bạn có thể dễ dàng định tuyến các phương thức Array.prototype
thông qua như sau.
Vì vậy, bất cứ khi nào sở hữu bất kỳ (với tên name
) đang được tải xuống, con đường mã như sau:
- Hãy thử trở lại
inst[name]
.
- Nếu không, hãy thử trả về một hàm áp dụng
Array.prototype[name]
trên cá thể với các đối số đã cho cho hàm này.
- Nếu không, chỉ cần trả lại
undefined
.
Nếu bạn muốn chơi xung quanh với proxy, bạn có thể sử dụng phiên bản V8 gần đây, ví dụ trong phiên bản Chromium hàng đêm (đảm bảo chạy dưới dạng chrome --js-flags="--harmony"
). Một lần nữa, proxy không có sẵn cho việc sử dụng "bình thường" vì chúng tương đối mới, thay đổi rất nhiều phần cơ bản của JavaScript và trên thực tế chưa được chỉ định chính thức (vẫn là bản nháp).
Đây là một sơ đồ đơn giản về cách nó diễn ra như thế nào (inst
thực sự là proxy mà cá thể đã được đưa vào). Lưu ý rằng nó chỉ minh họa nhận được thuộc tính; tất cả các hoạt động khác chỉ đơn giản là được truyền bởi proxy vì trình xử lý chuyển tiếp chưa sửa đổi.

Mã ủy quyền có thể là như sau:
function Test(a, b, c) {
this[0] = a;
this[1] = b;
this[2] = c;
this.length = 3; // needed for .slice to work
}
Test.prototype.foo = "bar";
Test = (function(old) { // replace function with another function
// that returns an interceptor proxy instead
// of the actual instance
return function() {
var bind = Function.prototype.bind,
slice = Array.prototype.slice,
args = slice.call(arguments),
// to pass all arguments along with a new call:
inst = new(bind.apply(old, [null].concat(args))),
// ^is ignored because of `new`
// which forces `this`
handler = new Proxy.Handler(inst); // create a forwarding handler
// for the instance
handler.get = function(receiver, name) { // overwrite `get` handler
if(name in inst) { // just return a property on the instance
return inst[name];
}
if(name in Array.prototype) { // otherwise try returning a function
// that calls the appropriate method
// on the instance
return function() {
return Array.prototype[name].apply(inst, arguments);
};
}
};
return Proxy.create(handler, Test.prototype);
};
})(Test);
var test = new Test(123, 456, 789),
sliced = test.slice(1);
console.log(sliced); // [456, 789]
console.log("2" in test); // true
console.log("2" in sliced); // false
console.log(test instanceof Test); // true
// (due to second argument to Proxy.create)
console.log(test.foo); // "bar"
Việc xử lý chuyển tiếp có sẵn tại the official harmony wiki.
Proxy.Handler = function(target) {
this.target = target;
};
Proxy.Handler.prototype = {
// Object.getOwnPropertyDescriptor(proxy, name) -> pd | undefined
getOwnPropertyDescriptor: function(name) {
var desc = Object.getOwnPropertyDescriptor(this.target, name);
if (desc !== undefined) { desc.configurable = true; }
return desc;
},
// Object.getPropertyDescriptor(proxy, name) -> pd | undefined
getPropertyDescriptor: function(name) {
var desc = Object.getPropertyDescriptor(this.target, name);
if (desc !== undefined) { desc.configurable = true; }
return desc;
},
// Object.getOwnPropertyNames(proxy) -> [ string ]
getOwnPropertyNames: function() {
return Object.getOwnPropertyNames(this.target);
},
// Object.getPropertyNames(proxy) -> [ string ]
getPropertyNames: function() {
return Object.getPropertyNames(this.target);
},
// Object.defineProperty(proxy, name, pd) -> undefined
defineProperty: function(name, desc) {
return Object.defineProperty(this.target, name, desc);
},
// delete proxy[name] -> boolean
delete: function(name) { return delete this.target[name]; },
// Object.{freeze|seal|preventExtensions}(proxy) -> proxy
fix: function() {
// As long as target is not frozen, the proxy won't allow itself to be fixed
if (!Object.isFrozen(this.target)) {
return undefined;
}
var props = {};
Object.getOwnPropertyNames(this.target).forEach(function(name) {
props[name] = Object.getOwnPropertyDescriptor(this.target, name);
}.bind(this));
return props;
},
// == derived traps ==
// name in proxy -> boolean
has: function(name) { return name in this.target; },
// ({}).hasOwnProperty.call(proxy, name) -> boolean
hasOwn: function(name) { return ({}).hasOwnProperty.call(this.target, name); },
// proxy[name] -> any
get: function(receiver, name) { return this.target[name]; },
// proxy[name] = value
set: function(receiver, name, value) {
this.target[name] = value;
return true;
},
// for (var name in proxy) { ... }
enumerate: function() {
var result = [];
for (var name in this.target) { result.push(name); };
return result;
},
// Object.keys(proxy) -> [ string ]
keys: function() { return Object.keys(this.target); }
};
có vẻ như bạn đang suy nghĩ về javascript [ "pollyfills" hoặc "miếng chêm"] (http://remysharp.com/2010/10/08/what-is-a-polyfill/) –
cờ nó thường thanh lịch và đáng tin cậy hơn để bắt ngoại lệ với một khối try-catch. –