为什么在这个例子中使用"use strict"可以提高性能10倍?

132

在关注扩展String.prototype的性能问题时,我非常感兴趣,因为仅仅给String.prototype方法添加"use strict"就可以提高10倍性能。由bergi提供的解释很简短,没有给我解释清楚。为什么两个几乎相同的方法之间会有如此明显的差异,仅在开头的"use strict"不同?你能否详细解释一下并说明其背后的理论呢?

String.prototype.count = function(char) {
  var n = 0;
  for (var i = 0; i < this.length; i++)
    if (this[i] == char) n++;
  return n;
};

String.prototype.count_strict = function(char) {
  "use strict";
  var n = 0;
  for (var i = 0; i < this.length; i++)
    if (this[i] == char) n++;
  return n;
};
// Here is how I measued speed, using Node.js 6.1.0

var STR = '0110101110010110100111010011101010101111110001010110010101011101101010101010111111000';
var REP = 1e4;

console.time('proto');
for (var i = 0; i < REP; i++) STR.count('1');
console.timeEnd('proto');

console.time('proto-strict');
for (var i = 0; i < REP; i++) STR.count_strict('1');
console.timeEnd('proto-strict');

结果:

proto: 101 ms
proto-strict: 7.5 ms

1
你能试一下 this[i] === char 的代码,并看看是否得到相同的结果吗? - Niet the Dark Absol
1
我在 DOM 环境中使用 this[i] === char 进行了测试,结果相同。 - Christian Vincenzo Traina
2
Bergi的解释说,当您调用count函数时,必须将this参数转换为字符串对象而不是字符串字面量,而在严格模式下,它不必这样做才能正常运行。为什么会这样我不太清楚,我非常想知道答案。 - Nick Larsen
3
@NickLarsen说:这就是语言规定的方式。传统上JS会确保this始终是一个对象,但在严格模式下它会跳过这一步骤,因此你得到的是原始字符串或提供给this的任何东西。 - user1106925
6
是时候在每个地方都加上"use strict";了,伙计们!嘿! - Jonathan
显示剩余2条评论
1个回答

163

在严格模式下,this上下文不强制为对象。如果你在非对象上调用函数,则this将只是该非对象。

相比之下,在非严格模式下,this上下文总是首先被包装在一个对象中,如果它还不是一个对象的话。例如,(42).toString()首先将42包装在一个Number对象中,然后使用Number对象作为this上下文调用Number.prototype.toString。在严格模式下,this上下文保持不变,并使用42作为this上下文调用Number.prototype.toString

(function() {
  console.log(typeof this);
}).call(42); // 'object'

(function() {
  'use strict';
  console.log(typeof this);
}).call(42); // 'number'

在您的情况下,非严格模式版本会花费大量时间将原始的string包装成String对象封装体,然后再转回来。而严格模式版本直接处理原始的string,这可以提高性能。

1
而且据我所知,删除with也有助于每个变量查找。 - zzzzBov
2
@zzzzBov 是错误的。移除 with 会有很大帮助,因为它允许浏览器推断变量表达式指的是哪个变量。 - John Dvorak
3
对我来说,非对象this比始终为对象this更加"严格"似乎不太直观。 - IS4
2
@IllidanS4:这主要涉及到thisnullundefined的情况,这将在松散模式下成为全局对象。 - Bergi
7
如果你愿意,可以将其想象为“实际 this”与“包装器 this”。对象包装器是一个不应该存在的笨拙解决方法,因此在可能的情况下,严格模式会更加避免使用它们。 - Ry-
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接