The printer operation is implementation-defined. It accepts a log level indicating severity, and a List of arguments to print (which are either JavaScript objects, of any type, or are implementation-specific representations of printable things, as produced by the %o and %O specifiers). How the implementation prints args is up to the implementation, but implementations should separate the objects by a space or something similar, as that has become a developer expectation.
// SharedFunctionInfo describes the JSFunction information that can be
// shared by multiple instances of the function.
class SharedFunctionInfo: public HeapObject {
public:
// [name]: Function name.
DECL_ACCESSORS(name, Object)
if (op == Token::ASSIGN) {
Traits::SetFunctionNameFromIdentifierRef(right, expression);
}
// ...
}
這樣就實現了前面引用的ES6對函數對象的"name"屬性的值的規定。
============================================較老版本的V8里有一套相對複雜的「推導匿名函數的函數名」的實現。例如說,參考這個版本:GitHub - v8/v8 at chromium/2370其中有一個FuncNameInferrer類,
// FuncNameInferrer is a stateful class that is used to perform name
// inference for anonymous functions during static analysis of source code.
// Inference is performed in cases when an anonymous function is assigned
// to a variable or a property (see test-func-name-inference.cc for examples.)
//
// The basic idea is that during parsing of LHSs of certain expressions
// (assignments, declarations, object literals) we collect name strings,
// and during parsing of the RHS, a function literal can be collected. After
// parsing the RHS we can infer a name for function literals that do not have
// a name.
在Parser里的fni_欄位指向它的一個實例。它會在parse過程中收集信息,例如:
Expression* ParserTraits::ExpressionFromIdentifier(const AstRawString* name,
int start_position,
int end_position,
Scope* scope,
AstNodeFactory* factory) {
if (parser_-&>fni_ != NULL) parser_-&>fni_-&>PushVariableName(name);
// ...
}
String* Map::constructor_name() {
Object* maybe_constructor = GetConstructor();
if (maybe_constructor-&>IsJSFunction()) {
JSFunction* constructor = JSFunction::cast(maybe_constructor);
String* name = String::cast(constructor-&>shared()-&>name());
if (name-&>length() &> 0) return name;
String* inferred_name = constructor-&>shared()-&>inferred_name();
if (inferred_name-&>length() &> 0) return inferred_name;
Object* proto = prototype();
if (proto-&>IsJSObject()) return JSObject::cast(proto)-&>constructor_name();
}
// TODO(rossberg): what about proxies?
// If the constructor is not present, return "Object".
return GetHeap()-&>Object_string();
}