Javascript 为什么在删除属性之前使用点符号检查属性要比直接删除属性快?

Javascript 为什么在删除属性之前使用点符号检查属性要比直接删除属性快?,javascript,performance,dom,syntax,conditional,Javascript,Performance,Dom,Syntax,Conditional,我问了,结果是当从元素中删除属性时,首先使用elem.xxx检查元素是否存在==未定义的使运行时更快 为什么更快?还有更多的代码需要处理,无论您采用哪种方法,都必须遇到removeAttribute()方法。好吧,首先您需要知道的是elem.xxx与elem.getAttribute()或与属性相关的任何其他方法不同 elem.xxx是DOM元素的一个属性,而DOM中HTML上的attribute和element既相似又不同。例如,以这个DOM元素:为例,这个代码: //Let say var

我问了,结果是当从元素中删除属性时,首先使用
elem.xxx检查元素是否存在==未定义的
使运行时更快


为什么更快?还有更多的代码需要处理,无论您采用哪种方法,都必须遇到
removeAttribute()
方法。

好吧,首先您需要知道的是
elem.xxx
elem.getAttribute()
或与属性相关的任何其他方法不同

elem.xxx
是DOM元素的一个属性,而DOM中HTML上的attribute和element既相似又不同。例如,以这个DOM元素:
为例,这个代码:

//Let say var a is the <a> tag
a.getAttribute('href');// == #
a.href;// == http://www.something.com/# (i.e the complet URL)
//假设var a是标记
a、 getAttribute('href');//==#
a、 href;//==http://www.something.com/# (即完整的URL)
但是让我们使用一个自定义属性:

//假设var a是标记
a、 getAttribute('custom');//==测试
a、 自定义;//==未定义
因此,你无法真正比较两者的速度,因为它们没有达到相同的结果。但是一个明显更快,因为属性是一个快速访问数据的属性,而属性使用get/hasaAttribute DOM函数

现在,为什么没有条件会更快?仅仅因为
removeAttribute
不关心属性是否丢失,它就会检查属性是否丢失


因此,在
removeAttribute
之前使用
hasAttribute
类似于执行两次检查,但条件稍微慢了一点,因为它需要检查是否满足条件才能运行代码。

我怀疑速度提升的原因是跟踪树

痕量树是由尔湾加利福尼亚大学的Andreas Gal和Michael Franz在其论文中首次提出的。 在他的博客文章Andreas Gal(论文的合著者)中,他解释了跟踪实时编译器是如何工作的

为了尽可能有条理地解释跟踪JIT编译器(因为我对该主题的了解并不深入),跟踪JIT编译器执行以下操作:

  • 最初,将解释要运行的所有代码
  • 对每个代码路径执行的次数进行计数(例如,执行
    if
    语句的
    分支的
    true
    次数)
  • 当采用代码路径的次数大于预定义阈值时,代码路径将编译为机器代码以加快执行速度(例如,我认为SpiderMonkey会执行多次执行的代码路径)
  • 现在让我们看看你的代码,了解什么导致了速度提升:

    测试用例1:检查 此代码具有代码路径(即
    if
    语句)。记住,跟踪JIT只优化代码路径,而不是整个函数。这就是我认为正在发生的事情:

  • 由于代码是由JSPerf进行基准测试的,所以它被执行了不止一次(轻描淡写)。因此,它被编译成机器代码
  • 但是,它仍然会产生对
    hasAttribute
    的额外函数调用的开销,该函数不是JIT编译的,因为它不是条件代码路径(大括号之间的代码)的一部分
  • 因此,尽管大括号内的代码很快,但条件检查本身很慢,因为它没有编译。它被解释了。结果是代码速度很慢
  • 测试用例2:删除 在这个测试用例中,我们没有任何条件代码路径。因此,JIT编译器永远不会生效。因此代码很慢

    测试用例3:检查(点符号) 这与第一个测试用例相同,但有一个显著差异:

  • 条件检查是一种简单的非等价检查。因此,它不会产生函数调用的全部开销
  • 大多数JavaScript解释器通过为这两个变量假设一个固定的数据类型来优化这样的简单等价性检查。由于
    elem.xxx
    undefined
    的数据类型不会每次迭代都改变,因此这种优化使得条件检查更快
  • 结果是,条件检查(尽管已解释)不会显著降低编译代码路径的速度。因此,这段代码是最快的

  • 当然,这只是我的猜测。我不知道JavaScript引擎的内部结构,因此我的答案不是规范的。然而,我认为这是一个很有根据的猜测。

    你的证明是错误的

    elem.class!==未定义的
    总是计算为
    false
    ,因此永远不会调用
    elem.removeAttribute(“类”)
    ,因此,此测试将总是更快

    elem
    上要使用的正确属性是
    className
    ,例如:

    typeof elem.className !== "undefined"
    

    正如Karl AndréGagnon指出的,访问[本机]JavaScript属性和调用DOM函数/属性是两种不同的操作

    一些DOM属性通过;这些属性与adhoc JS属性不同,需要DOM访问。而且,即使DOM属性是公开的,但与DOM属性没有严格的关系

    例如,
    inputElm.value=“x”
    将不会更新DOM属性,即使元素将显示并报告更新的值。如果目标是处理DOM属性,唯一正确的方法是使用
    hasaAttribute/setAttribute


    我一直致力于为不同的函数调用导出一个“公平”的微基准,但这相当困难,而且会发生很多不同的优化。这里,我将用它来论证我的观点

    请注意,没有
    if
    removeAttribute
    来混淆结果,我只关注DOM/JS属性访问。而且,我试图统治
    if (elem.hasAttribute("xxx")) {
        elem.removeAttribute("xxx");
    }
    
    elem.removeAttribute("xxx");
    
    if (elem.xxx !== undefined) {
        elem.removeAttribute("xxx");
    }
    
    typeof elem.className !== "undefined"