繁体   English   中英

Javascript:为什么定义变量作为函数的结果会阻止我将该文件包含在HTML中?

[英]Javascript: Why does defining a variable as the result of a function prevent me from including that file in HTML?

假设我在yum.js中有一些javascript定义了这样的对象

/* yum.js */

var Yum = {
    MY_ID: "yum@yum.yum",

    MAX_PIES: 100,

    pies_eaten: [],

    pie_string: "blueberry",    

    eat_pie: function(pietype) {
        alert("mmmm, " + pietype);
    }

 }

我有一个HTML文件yumtest.html,我想要包含yum.js并调用一些函数。 HTML看起来像

<!-- yumtest.html -->

<html>
<head>

<script type="text/javascript" src="yum.js"></script>

<script type="text/javascript"> 
    function run_tests() {
        alert("The Yum class is type '" + typeof Yum + "'.");
        alert("pie_string is '" + Yum.pie_string + "'.");
        Yum.eat_pie("apple");
    }
</script>

</head>
<body>

<input type="button" value="Click to run tests" onclick="run_tests()">

</body>
</html>

这很好用:我可以点击按钮,警告告诉我“pie_string是'蓝莓'”。 这很好。

但是,假设我想将pie_string初始化为另一个对象上的函数返回的某个值。 我更改了yum.js,因此创建了pie_string

pie_string: OtherObj.get_best_pie(),

//... in another file, OtherObj is defined with
get_best_pie: function() {
    return "blueberry";
},

当我单击按钮以运行相同的代码时,这不起作用。 yumtest.html告诉我“Yum类的类型'未定义'',并且调用Yum.x属性或方法不起作用。 代码执行停止。

所以我想知道:

1)为什么将变量初始化为函数的返回值会阻止我将文件包含在HTML页面中? (我目前的猜测是,当解析文件并将其添加到HTML时,该函数无法执行并返回 - 请参阅下面的额外信息)

2)是否有办法获取有关包含失败的错误消息,或者是否是JavaScript正常/预期的静默失败?

额外的信息

我问的原因是因为我在Firefox扩展中看到了这种情况。 使用这种方式初始化几个变量

varname : Components.classes["@mozilla.org/extension-name-string;1"]
        .getService(Components.interfaces.nsIPrefBranchInternal),

加载各种用户首选项。 这工作正常,扩展正常运行,所以这可能是有效的Javascript代码。 或者至少 - 在某些情况下有效吗? 运行作为实际的Javascript和被解析并包含在HTML中之间的区别可能会阻止函数运行并返回一个值?

解决方法

我想一个解决方法是将Yum重新定义为一个类,并在构造函数中初始化变量。

对于那些不能或不想将他们的代码重构成课程的人来说,这是个好消息。 您可以将变量保留在原位,但仍然将该文件包含在HTML中,方法是将变量定义为函数并计算内部的返回值。 例如,我们可以做到

pie_string: function() {
    // do some calculations here;
    // whatever we would have done in get_best_pie()
    return "blueberry";
},

这意味着您必须将Yum.pie_string所有调用Yum.pie_stringYum.pie_string() (或者您可能希望重命名函数' get_pie_string() '以便它清楚......)。 但是javascript文件可以包含在HTML中并正常使用。

唷!

假设我在yum.js中有一些javascript定义了这样的类

你没有一个类,从可以创建实例的模板的意义上说,你有一个对象。 JavaScript没有类似于Java的意义上的类,但是如果使用new关键字调用,则可以使用JS函数作为对象构造函数。

1)为什么将变量初始化为函数的返回值会阻止我将文件包含在HTML页面中?

这与您是否将JS作为外部文件包含无关 - 即使您将其包含在html文件的脚本块中,它仍然无法正常工作。

问题是你没有初始化变量 (复数),你正在创建一个从对象文字初始化的单个变量Yum 您所认为的“变量”实际上是该对象的“属性”。 JS对象文字语法不允许您设置引用同一对象的其他属性的属性 - 如果您考虑它,该对象该代码行运行并且整个对象文字已被评估之后才会存在,当然你不能引用尚不存在的东西的属性。

你可以做的是通过对象文字初始化大多数对象属性,然后添加你的pie_string属性:

var Yum = {
   MY_ID: "yum@yum.yum",
   MAX_PIES: 100,
   pies_eaten: [],
   get_best_pie: function() {
      return "blueberry";
   }, 
   eat_pie: function(pietype) {
      alert("mmmm, " + pietype);
   }
}

Yum.pie_string = Yum.get_best_pie();

或者定义独立于对象文字的get_best_pie()函数,然后pie_string设置pie_string属性:

function get_best_pie() {
   return "blueberry";
}

var Yum = {
   pie_string : get_best_pie(), 
   eat_pie: function(pietype) {
      alert("mmmm, " + pietype);
   },
   // etc
}

2)是否有办法获取有关包含失败的错误消息,或者是否是JavaScript正常/预期的静默失败?

包含该文件是成功的 ,但随后您将收到一个您已经看到的JavaScript错误(您引用的那个)。

关于“额外信息”部分,您引用的代码同样不是创建变量 - 使用:语法它必须是从另一个对象文字的中间提取,创建一个属性。 如果是这样,将它设置为一个函数的返回是完全有效的,该函数被定义为已经存在的另一个对象的属性 - 我想你会发现正在发生的事情。

因为你永远不会有一个名为get_best_pie的函数来调用

它是一个对象的成员,特别是一个尚不存在的对象,所以即使你用正确的名称( Yum.get_best_pie() )调用它,它仍然无法工作。 你需要使用在对象外定义函数

function get_best_pie(){
    //...
}

在文件的某个地方

在对象创建时,您尝试将其中一个属性分配给在同一对象中声明的另一个属性(函数)的返回值

在javascript中,对象没有范围,只有函数。 因此, Yum对象定义中对get_best_pie()的引用将作为window.get_best_pie的窗口范围,该窗口不存在。 因为Yum尚不存在,所以要调用的函数(要在pie_string存储其返回值)尚不存在(直到创建对象之后)。

您正在查看工作的库的原因是因为它们显然不是指正在创建的容器对象。 它们引用必须已经实例化的Components对象(或者,如果没有,那么您提供的代码片段存在于在对象创建时未调用的函数内)。

Javascript没有明确的方法来为属性创建getter和setter(到目前为止,虽然这方面的想法正在进行中)。 这意味着属性必须是简单的标量或没有括号的解除引用的对象,或者,您必须使用函数,并使用括号取消引用值以调用函数(而不是引用它)。

您可能会考虑以下内容。 它接近你想要的东西,让你继续使用属性表示法,而不是切换到一个函数:

var Yum = {
    MY_ID: "yum@yum.yum",
    MAX_PIES: 100,
    pies_eaten: [],
    get_best_pie: function() {
        return "blueberry";
    },
    eat_pie: function(pietype) {
        alert("mmmm, " + pietype);
    },
    init: function() {
        Yum.pie_string = get_best_pie();
        // other initialization here.
    }
};
Yum.init();

它们解释为什么包含yum.js失败的原因是我们调用get_best_pie()的对象不仅仅是任何对象 - 它是一个'xpconnect wrapped'对象,因此调用get_best_pie()需要额外的权限。 如果OtherObj只是一个常规对象,初始化样式可以工作,我们可以包含HTML文件。 但是当尝试包含yum.js时,浏览器无法访问OtherObj。 据推测,这使我们只有Yum的部分对象定义,这就是为什么它仍然未定义且无法使用。

Firefox扩展失败的原因是因为Components.classes是一个'xpconnect wrapped'对象,而html页面没有访问它的权限。

要在HTML文件中包含yum.js,我们需要在初始化pie_string时拥有适当的权限。 一种方法(如@ErikE和@nnnnnn所述)是在函数内初始化变量 - 这允许调用者在初始化之前请求权限,然后yum.js可以被解析并正常包含在yumtest.html中。

var Yum = {
    //... rest of object definition goes here
    init : function() {
        //important: assigning to 'pie_string' will create a new local variable;
        //use this.pie_string instead to reference the property of this class.
        this.pie_string = Components.classes["@mozilla.org/extension-string;1"]
                    .getService(Components.interfaces.nsIPrefBranchInternal);
}

};

解决方案不当

这里有两个sqlutions 工作。 有人知道为什么吗?

  1. 在包含文件之前尝试在脚本内部请求权限

     <script type="text/javascript"> netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect'); </script> <script type="text/javascript" src="yum.js"></script> 
  2. 尝试请求权限,然后动态包含该文件

     netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect'); var script = document.createElement("script"); script.type="text/javascript"; script.src="yum.js"; document.getElementsByTagName("head")[0].appendChild(script); 

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM