暴露的对象具有数万个属性,并且在启动Web应用程序时创建它们的速度很慢。因此,我想知道是否有办法按需提供。一个例子:
var reallyLargeObject = {}; //root object, with many many propertys(the propertys has subpropertys in a tree as well.
此对象是在我们的客户无法控制的情况下创建的。但是,在客户脚本中会有如下代码:
reallyLargeObject.subProperty.subsubProperty = 23;
当然这会导致"对象没有被定义",但我想以某种方式捕捉到这一点(通过一些原型函数的覆盖可能?)并按需创建属性,如:
function(subpropertyName){
reallyLargeObject[subpropertyName]=createSubProperty(subpropertyName);
}
返回.subsubProperty之前调用......这甚至可能吗?
提前感谢:) /张志贤
答案 0 :(得分:0)
如果JavaScript引擎具有ES5功能(所有现代浏览器都可以,IE8等旧版浏览器不支持),则可能会出现这种情况。您仍然需要提前添加顶级属性,但不必初始化它们。 ES6将使真正懒惰的属性成为可能。
defineProperty
/ defineProperties
您可以使用Object.defineProperty
或Object.defineProperties
实现延迟初始化属性getter。
lazy-init有两种选择:首次使用时重新定义属性,或使用支持变量。
这是使用重新定义的示例;这样做的好处是,一旦init完成,你就不再有getter / setter了,只是一个无聊的旧属性:
// REUSABLE utility function: Make a redefinable property
function makeLazyInitProp(o, name, builder) {
Object.defineProperty(o, name, {
// Getter
get: function() {
snippet.log("Getter for " + name + " called, redefining");
var value = builder(this);
Object.defineProperty(this, name, {
value: value,
writable: true
});
return value;
},
// Setter, if you want one
set: function(value) {
Object.defineProperty(this, name, {
value: value,
writable: true
});
},
// Has to be configurable
configurable: true
});
}
// Make our object with `foo` and `bar` properties
var obj = {};
makeLazyInitProp(obj, "foo", function() {
return {
message: "This is the foo property's message"
};
});
makeLazyInitProp(obj, "bar", function() {
return {
message: "This is the bar property's message"
};
});
// Use it, note we only see the "Getter for X called,
// redefining" message *once* for each property
// foo
snippet.log(obj.foo.message);
snippet.log(obj.foo.message);
// bar
snippet.log(obj.bar.message);
snippet.log(obj.bar.message);
<!-- Script provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 -->
<script src="http://tjcrowder.github.io/simple-snippets-console/snippet.js"></script>
改为使用支持值:
// REUSABLE utility function: Make a property using a backing value
function makeLazyProp(o, name, builder) {
var pending = true, value;
Object.defineProperty(o, name, {
// Getter
get: function() {
if (pending) {
snippet.log("Building " + name + " property");
value = builder(this);
pending = false;
}
return value;
},
// Setter, if you want one
set: function(v) {
value = v;
pending = false;
}
});
}
// Make our object with `foo` and `bar` properties
var obj = {};
makeLazyProp(obj, "foo", function() {
return {
message: "This is the foo property's message"
};
});
makeLazyProp(obj, "bar", function() {
return {
message: "This is the bar property's message"
};
});
// Use it, note we only see the "Building X property"
// message *once* for each property
// foo
snippet.log(obj.foo.message);
snippet.log(obj.foo.message);
// bar
snippet.log(obj.bar.message);
snippet.log(obj.bar.message);
<!-- Script provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 -->
<script src="http://tjcrowder.github.io/simple-snippets-console/snippet.js"></script>
Proxy
ES6会有代理,这几乎就像它们听起来的那样:在其他对象(代理)之上的真正外观的对象。代理可以参与几乎所有你可以用它们所包围的对象做的事情 - 包括获取和设置属性。
Firefox的SpiderMonkey引擎现在有代理,因此您可以在Firefox中使用以下内容(但不是大多数其他浏览器):
// Create the object
var obj = (function() {
// This is the *real* object we'll return a proxy for
var real = {};
// These are the functions that will lazy-init our properties
var builders = {
foo: function(o) {
snippet.log("Building foo property");
o.foo = {
message: "This is foo's message"
};
},
bar: function(o) {
snippet.log("Building bar property");
o.bar = {
message: "This is bar's message"
}
}
};
// Create our proxy for `real`
var p = new Proxy(real, {
// `get` is called whenever the proxy is asked for a
// property, and passed the underlying object and the
// property name
get: function(o, name) {
// If we have a build and the underlying object doesn't
// yet have the property, build it
if (builders[name] && !o.hasOwnProperty(name)) {
builders[name](o);
}
// Return the (possibly-newly-built) property value
return o[name];
}
});
// Return the proxy (facade)
return p;
})();
// Use it, note we only see the "Building X property"
// message *once* for each property
// foo
snippet.log(obj.foo.message);
snippet.log(obj.foo.message);
// bar
snippet.log(obj.bar.message);
snippet.log(obj.bar.message);
<!-- Script provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 -->
<script src="http://tjcrowder.github.io/simple-snippets-console/snippet.js"></script>