起因
众所周知,基本类型如 var str = 'hello';
中的 str
可以调用所有的 String
对象方法。
很多文章把这种行为解释为自动装箱机制,类似以下工作流程:
var str = 'hello';
var index = str.indexOf('h');
// 相当于
var temp = new String(str);
var index = temp.indexOf('h');
temp = null;
这固然是种非常容易理解的模式,但是如果在同一上下文中,每调用一次方法,就去创建一个 String
对象,是否性能过差,浏览器是否真如上面所说的这样进行工作的呢,以 chrome
为例(不同内核浏览器表现的有差异),我开始了探索。
探索
劫持 new String
最开始,我想通过一种方式,看看浏览器在执行字符串方法时,是否真的 new
了一个 String
对象。通过探索我找到下面这种方式,
var bind = Function.bind;
var unbind = bind.bind(bind);
function instantiate(constructor, args) {
return new (unbind(constructor, null).apply(null, args));
}
String = function (String) {
MyString.prototype = String.prototype;
return MyString;
function MyString() {
console.log('new String');
var str = instantiate(String, arguments);
return str;
}
}(String);
var copyFunc = String.prototype.indexOf;
String.prototype.indexOf = function (s) { console.log('My indexOf', this.valueOf(), arguments); return copyFunc.call(this.valueOf(), s); }
var a = '123';
console.log(a.indexOf('1'));
console.log(a.indexOf('2'));
在 Chrome
执行后发现,我们在使用 indexOf
方法时,并没有 new String
。但是 String
原型链上的 indexOf
确实被调用了,说明 v8
可以不创建一个完整的 String
对象下直接使用字符串的方法。
其他资料
带着想了解 v8
此处机制的目的,我找到了一些资料,来自 javascript.info
和 StackOverflow
.
在 javascript.info
中介绍基本类型的文章中提到。
而在 StackOverflow
中的介绍更加的清晰,这位老哥回答到,这非常依赖引擎的实现,他尝试以 v8
为例,解释一下工作原理。一个基本类型的字符串在 v8
中会被解析为 v8::String
,方法可以被直接调用。
总结
这个小知识从 MDN
复习到原始数据时,看到一句基本类型是既非对象也无方法的数据,引发思考的。
通过资料的查证和学习,对这块的了解也变得更加清晰了,对 v8
的实现也觉得没有那么神秘了,^_^ !