你什么时候会在javascript中使用.contat()
When would you use .concat() in javascript
为什么/何时会使用.concat()代替赋值运算符?
即,如果我试图组合以下内容:
var p1 = "My name is ";
var p2 = "Joe";
var sen = p1+p2;
//Or you could use concat to do the same
var sen2 = p1.concat(p2);
//My question is, why would you ever use the latter?
有时最好查阅文档:Array.concat和String.concat.
简单地说,Array.concat()
用于创建一个新数组,相当于所有传入对象(数组或其他)的平面合并。String.concat()
用于创建一个新字符串,相当于合并所有传入的字符串。
然而,正如MDN所暗示的,不应该使用String.concat()
,因为分配+, +=
运算符要快得多。那你为什么要用String.concat()
呢?你不会的。那为什么要呢?这是规范的一部分:见第111-112页(第15.5.4.6节)。
那么关于为什么String.Concat
如此缓慢的问题呢。我对Chrome的V8引擎进行了一些挖掘。首先,在幕后,这就是对String.prototype.concat
的调用:
// ECMA-262, section 15.5.4.6
// https://github.com/v8/v8/blob/master/src/string.js#L64
function StringConcat(other /* and more */) { // length == 1
CHECK_OBJECT_COERCIBLE(this, "String.prototype.concat");
var len = %_ArgumentsLength();
var this_as_string = TO_STRING_INLINE(this);
if (len === 1) {
return this_as_string + other;
}
var parts = new InternalArray(len + 1);
parts[0] = this_as_string;
for (var i = 0; i < len; i++) {
var part = %_Arguments(i);
parts[i + 1] = TO_STRING_INLINE(part);
}
return %StringBuilderConcat(parts, len + 1, "");
}
正如您所看到的,所有实际工作都发生在StringBuilderConcat
中,然后它调用一个StringBuilderConcatHelper
,最后它调用String::WriteToFlat
来构建一个字符串。这些都是非常长的函数,为了简洁起见,我已经删掉了大部分。但如果你想寻找你的自我,可以看看github:
StringBuilderConcat
// https://github.com/v8/v8/blob/master/src/runtime.cc#L7163
RUNTIME_FUNCTION(Runtime_StringBuilderConcat) {
// ...
StringBuilderConcatHelper(*special,
answer->GetChars(),
FixedArray::cast(array->elements()),
array_length);
// ...
}
StringBuilderConcatHelper
template <typename sinkchar>
static inline void StringBuilderConcatHelper(String* special,
sinkchar* sink,
FixedArray* fixed_array,
int array_length) {
// ...
String::WriteToFlat(string, sink + position, 0, element_length);
// ...
}
String::WriteToFlat
// https://github.com/v8/v8/blob/master/src/objects.cc#L8373
template <typename sinkchar>
void String::WriteToFlat(String* src,
sinkchar* sink,
int f,
int t) {
String* source = src;
int from = f;
int to = t;
while (true) {
// ...
// Do a whole bunch of work to flatten the string
// ...
}
}
}
现在,分配途径有什么不同?让我们从JavaScript添加功能开始:
// ECMA-262, section 11.6.1, page 50.
// https://github.com/v8/v8/blob/master/src/runtime.js#L146
function ADD(x) {
// Fast case: Check for number operands and do the addition.
if (IS_NUMBER(this) && IS_NUMBER(x)) return %NumberAdd(this, x);
if (IS_STRING(this) && IS_STRING(x)) return %_StringAdd(this, x);
// Default implementation.
var a = %ToPrimitive(this, NO_HINT);
var b = %ToPrimitive(x, NO_HINT);
if (IS_STRING(a)) {
return %_StringAdd(a, %ToString(b));
} else if (IS_STRING(b)) {
return %_StringAdd(%NonStringToString(a), b);
} else {
return %NumberAdd(%ToNumber(a), %ToNumber(b));
}
}
首先要注意的是,没有循环,与上面的StringConcat
相比,它要短得多。但我们感兴趣的大部分工作都发生在%_StringAdd
函数中:
// https://github.com/v8/v8/blob/master/src/runtime.cc#L7056
RUNTIME_FUNCTION(Runtime_StringAdd) {
HandleScope scope(isolate);
DCHECK(args.length() == 2);
CONVERT_ARG_HANDLE_CHECKED(String, str1, 0);
CONVERT_ARG_HANDLE_CHECKED(String, str2, 1);
isolate->counters()->string_add_runtime()->Increment();
Handle<String> result;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
isolate, result, isolate->factory()->NewConsString(str1, str2));
return *result;
}
实际上,这很简单,一些计数器和对具有左右操作数的NewConsString
的调用。NewConsString
也很简单:
// https://github.com/v8/v8/blob/master/src/ast-value-factory.cc#L260
const AstConsString* AstValueFactory::NewConsString(
const AstString* left, const AstString* right) {
// This Vector will be valid as long as the Collector is alive (meaning that
// the AstRawString will not be moved).
AstConsString* new_string = new (zone_) AstConsString(left, right);
strings_.Add(new_string);
if (isolate_) {
new_string->Internalize(isolate_);
}
return new_string;
}
所以这只是返回一个新的AstConsString
,那是什么:
// https://github.com/v8/v8/blob/master/src/ast-value-factory.h#L117
class AstConsString : public AstString {
public:
AstConsString(const AstString* left, const AstString* right)
: left_(left),
right_(right) {}
virtual int length() const OVERRIDE {
return left_->length() + right_->length();
}
virtual void Internalize(Isolate* isolate) OVERRIDE;
private:
friend class AstValueFactory;
const AstString* left_;
const AstString* right_;
};
这个看起来一点也不像绳子。它实际上是一个"抽象语法树",这个结构形成了一个"绳索",可以有效地修改字符串。事实证明,现在大多数其他浏览器在添加字符串时都使用这种类型或rope结构。
由此得出的结论是,加法途径使用了更有效的数据结构,其中StringConcat
在不同的数据结构下做的工作要多得多。
根据Douglas Crockford的Javascript:The Good Parts:
concat方法通过连接其他字符串来生成新字符串在一起很少使用,因为+运算符更方便
Concat不仅不太方便,而且速度较慢:Benchmark
在MDN的文档页面上:
强烈建议使用赋值运算符(+,+=)而不是concat方法。
Javascript有一些不太理想的部分。每种语言都至少有一些不好的部分。不要认为你必须使用任何语言的每一部分。
- 我什么时候应该把JSON分成更小的部分
- 应该在什么时候使用Javascript条件运算符
- 你什么时候用_.bind和_.bindAll
- 我怎么知道用户什么时候点击了类似Facebook的按钮
- 什么时候在流中的类型别名上使用接口
- 什么时候可以对条件参数使用管道运算符?-JavaScript
- 在 React JS 中,什么时候应该使用存储而不是直接操作视图的状态
- 什么时候字符串不是字符串?当它没有 include() 方法时
- 什么时候需要在javascript中的函数中将对象作为参数传递
- 命令行上的输入在什么时候解析为 node.js 中的 process.argv
- $http在什么时候触发摘要循环开始
- 什么时候函数只能调用一次
- 我什么时候应该在jQuery中使用$.fn.extend()
- 什么时候会如果else打破所有条件javascript
- 我们什么时候应该在角度指令中使用transclude
- 我什么时候才能知道我已经在indexedDB中打开了连接
- dojo中的require()和define()函数的主要区别是什么?我们什么时候使用它们
- 这种设计模式什么时候才能打破
- 什么时候是“;“安全”;以在解析文档时修改给定的html元素/节点
- 你什么时候会在javascript中使用.contat()