“保护全局Javascript”;空气污染指数;对象
我目前有一个基于全局Javascript的API运行的Web应用程序,其初始化如下:“保护全局Javascript”;空气污染指数;对象,javascript,html,object,Javascript,Html,Object,我目前有一个基于全局Javascript的API运行的Web应用程序,其初始化如下: var Api = { someVar: "test", someFunction: function() { return "foo"; } } Api.myExtension = { myNewFunction: function() { return "bar"; } } 此API在Web应用程序中的许多“小部件”之间共享,它们都
var Api = {
someVar: "test",
someFunction: function() {
return "foo";
}
}
Api.myExtension = {
myNewFunction: function() {
return "bar";
}
}
此API在Web应用程序中的许多“小部件”之间共享,它们都应该运行这个API
实例,以便彼此传递数据
AJAX目前用于加载这些小部件,例如在Widgets/mywidget.html中,它被放置在,比如,…
代码的某些其他部分可能会选择向Api
添加更多功能,目前的做法如下:
var Api = {
someVar: "test",
someFunction: function() {
return "foo";
}
}
Api.myExtension = {
myNewFunction: function() {
return "bar";
}
}
但是,这种用法会产生一些问题:
问题一:如果一个小部件(可能由第三方提供)决定在其中隐藏一些代码,并执行类似于Api={}
的操作,破坏了全局Api
var,破坏了整个应用程序,该怎么办?是否可以保护此Api
变量不被外部覆盖?只允许“扩展”(添加新事物),但不允许“删除/更改”。i、 e:
Api.foo = { test: "bar" } // allowed
Api.someVar = "changing the existing someVar"; // not allowed
以下代码位于Api的“内部”,例如:
var Api = {
Debug: {
Messages = new Array,
Write: function() {
Api.Debug.Messages.push("test"); // allowed
}
}
}
Api.Debug.Messages.push("test 2"); // not allowed
var Api = {
widgetApi = {
someFunction: function(){
// ...
}
},
addWidget:function(){
var temp = this.widgetApi.constructor();
for(var key in this.widgetApi)
temp[key] = clone(this.widgetApi[key]);
return temp;
}
// Include other variables that Widgets can't use
}
我想到的可能解决方案:
Api
s现在彼此独立。但是,如果我有许多运行的小部件,并且它们无法再与小部件的“主机”(帧所在的页面)通信,那么在反复加载Api
时会有额外的开销,例如,我可能想告诉主机显示通知:Api.Notify.show(“Test”)
,但是它不能这样做,因为这个Api
完全独立于其他实例,并且它不能与“主机”通信
var Api = {
Debug: {
Messages = new Array,
Write: function() {
Api.Debug.Messages.push("test"); // allowed
}
}
}
Api.Debug.Messages.push("test 2"); // not allowed
var Api = {
widgetApi = {
someFunction: function(){
// ...
}
},
addWidget:function(){
var temp = this.widgetApi.constructor();
for(var key in this.widgetApi)
temp[key] = clone(this.widgetApi[key]);
return temp;
}
// Include other variables that Widgets can't use
}
通过这种方式,小部件可以执行函数并与主机或全局变量Api
通信。要设置变量,小部件将编辑其私有对象,而不是全局对象。对于每个帧(表示小部件),必须初始化或创建widgetApi
对象的副本,并可能将其存储在一个数组中,以使小部件的实例存储在主Api
对象中
例如,给定
您将执行以下操作:
var widget = document.getElementById("widget");
widget.contentWindow.Api = Api.addWidget();
widget.contentWindow.parent = null;
widget.contentWindow.top = null;
var Api = (function () {
// private variable
var myArray = [];
return {
addItem: function (newItem) {
myArray.push(newItem);
},
printItems: function () {
console.log("lots if items");
}
};
})();
Api.addItem("Hello, world");
Api.extensionValue = 5;
此外,在每个帧中,您需要将
parent
和top
变量设置为null,以便小部件无法访问主帧的数据。我已经有一段时间没有测试过这个方法了,所以可能有一些方法可以绕过将这些变量设置为null的问题。没有好的方法可以防止“第三方”小部件覆盖全局变量。通常,组装最终应用程序的人都有责任确保他们使用的任何Java脚本不会乱丢全局名称空间和冲突。在这个方向上,你能做的最好的事情就是给你的“Api”起一个好的、唯一的名字
我认为对你有很大帮助的是类似于“揭示模式”的东西,这是一种做你提到的“获得者和设定者”的方式,如果你需要的话,还可以做更多
一个简单而无用的示例如下所示:
var widget = document.getElementById("widget");
widget.contentWindow.Api = Api.addWidget();
widget.contentWindow.parent = null;
widget.contentWindow.top = null;
var Api = (function () {
// private variable
var myArray = [];
return {
addItem: function (newItem) {
myArray.push(newItem);
},
printItems: function () {
console.log("lots if items");
}
};
})();
Api.addItem("Hello, world");
Api.extensionValue = 5;
我认为您应该清楚地描述什么是共享的,或“单例”数据,并将这些项目保持私有,就像我的示例中的myArray一样。看一看
Object.freeze
更多信息
以下是Mozilla页面中的代码示例:
var obj = {
prop: function (){},
foo: "bar"
};
// New properties may be added, existing properties may be changed or removed
obj.foo = "baz";
obj.lumpy = "woof";
delete obj.prop;
var o = Object.freeze(obj);
assert(Object.isFrozen(obj) === true);
// Now any changes will fail
obj.foo = "quux"; // silently does nothing
obj.quaxxor = "the friendly duck"; // silently doesn't add the property
// ...and in strict mode such attempts will throw TypeErrors
function fail(){
"use strict";
obj.foo = "sparky"; // throws a TypeError
delete obj.quaxxor; // throws a TypeError
obj.sparky = "arf"; // throws a TypeError
}
fail();
// Attempted changes through Object.defineProperty will also throw
Object.defineProperty(obj, "ohai", { value: 17 }); // throws a TypeError
Object.defineProperty(obj, "foo", { value: "eit" }); // throws a TypeError
然而,浏览器支持仍然是局部的
编辑:请参阅Kernel James的答案,它与您的问题更相关(冻结将保护对象,但不保护重新分配对象。但是const将)但在浏览器支持有限的情况下也存在同样的问题。将其设置为
常量
:
const Api = "hi";
Api = 0;
alert(Api); //"hi"
我不是JS大师,但我不认为单凭JS就可以做到这一点。也许看看微软的新“TypeScript”,它有更好的语言功能,可以编译成JS,也许这可以让你保护它。是的,我不认为有任何简单的方法可以避免第三方脚本(甚至你自己的脚本)对全局的冲击但我建议您为对象使用一个不太可能被其他脚本使用的名称
var TFQ={}
可能比Api
更不容易发生冲突。您可以尝试以下方法:。也许会有帮助。。;。谢谢但是,小部件如何与主机通信?我如何“观察”Api.widgetsApi[“widget”]以获得新的“消息”?@JimmieLin:widgetsApi中的函数仍然可以与Api
对象交互。因此,您可以调用其他函数并从中编辑变量。例如,如果您有Api.widgetApi.Debug.Messages.push()
,则可以将其链接到全局Api
中的push
函数。因此,从本质上讲,小部件中的Api.widgetApi.Debug.Messages.push()
相当于它们之外的Api.Debug.Messages.push()
?听起来很酷,谢谢!只要在widgetApi
中有一个函数调用它外部的函数(this.Debug.Messages.push()
)就比Object.freeze好,这应该是公认的答案!显然,这保护了对象,但不是p