JavaScript - 在 Safari 上执行代码之前可用的对象定义

2024-01-09

我只需要在页面加载时执行一次的对象和函数被包装在undefined检查物体。在我通常使用的 Windows/Linux 上的 Chrome 上,代码运行得很好,即代码只执行一次。但在 iPad 和 MacBook 上的 Safari 上,未定义的检查不起作用,即根据浏览器,对象/函数已经被声明,甚至代码执行还没有到达那里!

我已经简化了我的代码,只包含一个if循环检查嵌套函数是否已声明。由于它不应该在第一次声明,所以我已经包括了someVariable在 - 的里面if那不应该是undefined.

在 Chrome 和 Safari 上运行相同的函数并查看差异。


if (typeof anObject == 'undefined') {

    function anObject(someParameter = 'someParameter') {
        var someProperty = 'someProperty';

        function someMethod(someParameter) {
            console.log(someParameter);
        }
    }

    console.log('Hi');
    var someVariable = 404;
}

在 Chrome 上,您可以看到控制台日志记录'Hi'还有someVariable为 404。但在 Safari 上,没有控制台日志记录,并且 someVariable 未定义。

如果您设置断点来了解发生了什么 - 第一个未定义的检查实际上永远不会起作用。这anObject甚至在声明之前就已定义。

我尝试搜索 V8(Chrome JS 引擎)和 JavaScriptCore(Safari 引擎)之间的差异,但没有找到任何可靠的东西。我认为这与执行和功能提升有关。如果有人能向我解释执行中出现这种差异的原因,那就更好了。 iPad 上的行为是相同的,甚至在 Chrome 上也是如此!

Updates:

  1. 我发现了关于不同执行的类似问题。似乎 就像这是与函数提升相关的东西,但不能 尚未找到任何可靠的来源。Chrome 和 Firefox 中的 Javascript 提升 https://stackoverflow.com/questions/14242399/javascript-hoisting-in-chrome-and-firefox

  2. 现在看来,实际上是一种吊装行为。这是通过使用函数表达式来实现的。在这种情况下,只需简单替换即可function anObject() with var anObject = function()。我认为,通过这样做,即使函数在执行之前被提升和评估,变量也不会被分配函数引用。

  3. 根据 PhistucK 的建议,我已经在 WebKit 问题跟踪器上打开了该问题(Bug#199823 https://bugs.webkit.org/show_bug.cgi?id=199823), 铬讨论 https://groups.google.com/a/chromium.org/forum/#!topic/chromium-discuss/UWDmDK4uKak和 TC39 ECMA262 Github(问题#1632 https://github.com/tc39/ecma262/issues/1632).

  4. 这是 2016 年报告的现有 Webkit 错误 -错误 163209 - [ES6]。在全局范围内实施附件 B.3.3 函数提升规则 https://bugs.webkit.org/show_bug.cgi?id=163209. 我现在在我的回答中总结了研究.


此行为与在 Webkit 引擎中使用草率模式有关,有一个错误 https://bugs.webkit.org/show_bug.cgi?id=163209。让我总结一下研究:

具体来说,该示例有三个关键方面:非严格模式代码,一个函数是在块内声明 and 在该块之前引用.

正如介绍附录B.3.3 https://tc39.es/ecma262/#sec-block-level-function-declarations-web-legacy-compatibility-semantics解释说,块语句内的函数声明最初并不是语言规范的一部分;这是浏览器经常实现的扩展,每个浏览器都以自己独特的方式实现。 ES2015 试图尽可能多地指定这种行为,但由于浏览器之间的差异无法完全协调,一些现有代码仍然不可避免地无法移植。

“以下是我们被迫指定的内容,因为网络浏览器 实现了这个行为,然后页面开始依赖它,但是我们 对此并不满意。” - 附件 B 3.3

In 草率模式,JavaScriptCore 的行为确实与正常行为不同:

λ eshost -sx "if (typeof foo === 'undefined') { function foo() {} print('ok'); } else { print('hmm'); }"
#### ch, sm, v8, xs
ok

#### jsc
hmm

一种解决方案是使用“严格”模式:

λ eshost -sx "(function () { 'use strict'; if (typeof foo === 'undefined') { function foo() {} print('ok'); } else { print('hmm'); } })()"

#### ch, jsc, sm, v8, xs
ok

而且,这显然只发生在 Safari 的脚本顶层。在函数中,如

function g(){
  console.log(typeof f);
  {
    function f(){}
  }
}

g();

Safari 符合规范。这很可能是因为脚本顶层的行为仅在 ES2016 中指定,8582e81 https://github.com/tc39/ecma262/commit/8582e812cd7f6d4aa15890e2a65800fe4785e8c7,与 ES2015 中指定的函数中的行为相反。

来源:评论者发表的评论罗斯·科斯林 https://github.com/rkirsling and 凯文·吉本斯 https://github.com/bakkot在 GitHub 问题上#1632 https://github.com/tc39/ecma262/issues/1632.

2016 年报告了一个与此提升行为相关的现有错误,Webkit 问题#16309:[ES6]。在全局范围内实施附件 B.3.3 函数提升规则 https://bugs.webkit.org/show_bug.cgi?id=163209。这是一个Test262 https://test262.report/browse/annexB/language/global-code/block-decl-global-existing-block-fn-no-init.js涵盖这一点的案例。

为了解决这个问题,我使用了函数表达式:

这是我替换的function anObject() with var anObject() = function()。现在运行此代码以了解流程:

if (typeof anObject == 'undefined') {

  if (typeof anObject == 'undefined') console.log('anObject not defined inside block')
  if (typeof someVariable == 'undefined') console.log('someVariable not defined as of now');

  var anObject = function(someParameter = 'someParameter') {
    var someProperty = 'someProperty';
  }

  console.log('anObject is now defined');
  var someVariable = 404;

  if (typeof someVariable == 'undefined') console.log('someVariable not defined as of now');

}

这里发生了什么事?

函数和变量被提升到顶层。但像 V8 (Chrome) 这样的引擎会在代码执行期间从语义上定义函数名称。然而,在Webkit浏览器的草率模式下,即使在ECMA2015/16标准化之后,函数名称也是在执行之前定义的。请注意,在两个引擎上,函数实际上是在任何内容之前定义(提升)的 - 这只是关于函数的语义name。上面的代码在执行期间将匿名函数的引用(因为它现在没有名称)分配给 anObject,这在 Safari 上也可以正常运行。关于块作用域和提升的一个很好的解释ES6 中块级函数的精确语义是什么? https://stackoverflow.com/questions/31419897/what-are-the-precise-semantics-of-block-level-functions-in-es6.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

JavaScript - 在 Safari 上执行代码之前可用的对象定义 的相关文章

  • 使用 Ajax 在输入时提交 Textarea,然后渲染部分内容而不刷新整个页面

    目前我正在尝试通过 JS 和 Ajax 在没有提交按钮的情况下发表评论 并且它有效 问题是当帖子提交时 页面重新加载到 post id comment页面 我希望它呈现部分内容 而不是刷新整个页面或将我带到不同的页面 我对 JS 不熟悉 任
  • 如何在react-select v2中创建optgroup?

    我想在我的反应选择列表中包含 optgroups 但它似乎没有记录在任何地方 我有以下结构 是从评论中提取的https github com JedWatson react select issues 59 https github com
  • 在 Angular 单元测试中应该如何处理运行块?

    我的理解是 当您在 Angular 单元测试中加载模块时 run块被调用 我认为如果你正在测试一个组件 你不会想同时测试run块 因为unit测试应该只是测试一个unit 真的吗 如果是的话有什么办法可以防止run阻止运行 我的研究让我认为
  • 将组件注册到现有的 Vue.js 实例

    我是 Vue js 新手 我想注册一个本地组件 如下所述 https v2 vuejs org v2 guide components html Local Registration https v2 vuejs org v2 guide
  • 在 angularjs 模块初始化期间有条件地注入依赖项

    我有一个角度模块 我想有条件地将依赖项注入其中 IE var myapp angular module myapp ngRoute myappcontroller ngGrid I want to include ngGrid only i
  • 如何在 javascript 或 jquery 中按尺寸对图像进行排序

    如何在 JavaScript 或 jQuery 中按尺寸对图像进行排序 我的代码如下 var imgsrc if document images length lt 1 alert No images to open return for
  • 模型不是 AngularJS 中输入的日期对象

    使用 AngularJS 我试图使用输入显示日期type date
  • FormData 中的 Blob 为 null

    我正在尝试通过远程 API 通过 ajax 在 android 中发送创建的照片 我在用着相机图片背景 https github com an rahulpandey cordova plugin camerapicturebackgrou
  • 使用 jQuery/JavaScript 将文本框值复制到剪贴板

    我有一个文本框和按钮 如下所示 div class col xs 11 style padding 20px 0 div
  • jspm / jQuery / TypeScript - 模块“jquery”没有默认导出

    我正在尝试使用 TypeScript 和 jspm system js 来引导 Web 应用程序进行模块加载 我还没有走多远 安装 jspm 后 并使用它来安装 jQuery jspm install jquery 以及基础知识 main
  • 更改特定字符串的颜色

    有谁知道如果将特定单词输入文本区域 我如何更改它的颜色 例如 如果用户输入 你好我的朋友 它会动态地将 你好 更改为绿色 在google上花了很多时间 找不到任何相关的东西 谢谢 textareas 的设计目的不是选择性着色
  • Promise 构造函数回调的主体何时执行?

    假设我有以下代码构造一个Promise function doSomethingAsynchronous return new Promise resolve gt const result doSomeWork setTimeout gt
  • 不可见的 reCAPTCHA - 缺少必需的参数:sitekey

    我正在为每个带有具有类的按钮的表单动态加载不可见的 reCAPTCHAg recaptcha 我遇到的问题是验证码未正确加载 我不知道为什么 我按照验证码网站上的文档进行操作 但我不确定如何以及为什么会出现此错误 Uncaught Erro
  • 简单的颜色变化

    我正在创建一个用户界面 用户可以在其中更改页面的颜色值 我想要的是获取分配给其背景颜色的值并将其变亮一定程度 我只是想获得一条亮点线 而不必每次都制作新图像 示例 用户将背景颜色设置为 ECECEC 现在我希望某个元素边框变成 F4F4F4
  • window.open 使用 css 样式

    我想设计我的 window open 目前 我的网页上有一些项目由于解析了某个类而打开 然后在新窗口中打开指定的文本 我想更改字体大小 字体和填充等 这是我的 JavaScript 代码
  • ES6 Reflect API 的好处

    我一直在努力升级一些代码以使用 ES6 语法 我有以下代码行 delete this foo 我的 linter 提出了使用建议 Reflect deleteProperty this foo 您可以找到该方法的文档here https d
  • 使用 div 或表格来包含链接列更好吗?

    我的页面底部有 3 列链接 每列都放入一个 div 中 所有三个 div 都包装在页面中央的一个大 div 中 这是更适合桌子的东西还是桌子不适合这项工作 您还可以使用 ul http www w3schools com tags tag
  • 如何制作过期/签名视频嵌入网址

    我是新来的 正在学习网络开发等等 我只知道如何将我的视频嵌入网站中 任何菜鸟都可以轻松获得源代码 他们也可以嵌入它 但在许多网站中 视频 src 均使用重定向器链接进行编码 例如 它会在一段时间后过期 在本例中是一天 我了解到这是一个签名网
  • 将 Angular Web 组件 EventEmitter 监听到 javascript

    我在以下工具的帮助下创建了一个小型网络组件本文 https medium com IMM9O web components with angular d0205c9db08f使用角度元素 其中包括 Input and Output 我能够将
  • React 错误:目标容器不是 DOM 元素

    我刚刚开始使用 React 所以这可能是一个非常简单的错误 但我们开始吧 我的html代码非常简单 load staticfiles

随机推荐