为什么在Console中分多次输入同名const a、const a、class a并不提示Identifier 'a' has already been declared
搜索上面提示中的字符串,找到在 node/deps/v8/src/execution/execution.cc 中有一个NewScriptContext函数:
NewScriptContext
MaybeHandle<Context> NewScriptContext(Isolate* isolate,
Handle<JSFunction> function) {
// Creating a script context is a side effect, so abort if that's not
// allowed.
if (isolate->debug_execution_mode() == DebugInfo::kSideEffects) {
isolate->Throw(*isolate->factory()->NewEvalError(
MessageTemplate::kNoSideEffectDebugEvaluate));
return MaybeHandle<Context>();
}
SaveAndSwitchContext save(isolate, function->context());
SharedFunctionInfo sfi = function->shared();
Handle<Script> script(Script::cast(sfi.script()), isolate);
Handle<ScopeInfo> scope_info(sfi.scope_info(), isolate);
Handle<NativeContext> native_context(NativeContext::cast(function->context()),
isolate);
Handle<JSGlobalObject> global_object(native_context->global_object(),
isolate);
Handle<ScriptContextTable> script_context(
native_context->script_context_table(), isolate);
// Find name clashes. ① 查找名字冲突
for (int var = 0; var < scope_info->ContextLocalCount(); var++) {
// 遍历上下文中所有local变量
Handle<String> name(scope_info->ContextLocalName(var), isolate);
// local变量被声明的方式
// let -> VariableMode::kLet
// const -> VairableMode::kConst
// var -> VariableMode::kVar
VariableMode mode = scope_info->ContextLocalMode(var);
ScriptContextTable::LookupResult lookup;
if (ScriptContextTable::Lookup(isolate, *script_context, *name, &lookup)) {
if (IsLexicalVariableMode(mode) || IsLexicalVariableMode(lookup.mode)) {
Handle<Context> context = ScriptContextTable::GetContext(
isolate, script_context, lookup.context_index);
// If we are trying to re-declare a REPL-mode let as a let or REPL-mode
// const as a const, allow it.
// REPL-mode允许多次声明
if (!(((mode == VariableMode::kLet &&
lookup.mode == VariableMode::kLet) ||
(mode == VariableMode::kConst &&
lookup.mode == VariableMode::kConst)) &&
scope_info->IsReplModeScope() &&
context->scope_info().IsReplModeScope())) {
// ES#sec-globaldeclarationinstantiation 5.b:
// If envRec.HasLexicalDeclaration(name) is true, throw a SyntaxError
// exception.
// ② 这部分算法描述在:
// https://tc39.es/ecma262/#sec-globaldeclarationinstantiation
MessageLocation location(script, 0, 1);
return isolate->ThrowAt<Context>(
isolate->factory()->NewSyntaxError(
MessageTemplate::kVarRedeclaration, name),
&location);
}
}
}
// 如果是let、const声明的变量,还要检查是否与global上的“不可删除的属性名”(configurable=false)冲突
if (IsLexicalVariableMode(mode)) {
LookupIterator it(isolate, global_object, name, global_object,
LookupIterator::OWN_SKIP_INTERCEPTOR);
Maybe<PropertyAttributes> maybe = JSReceiver::GetPropertyAttributes(&it);
// Can't fail since the we looking up own properties on the global object
// skipping interceptors.
CHECK(!maybe.IsNothing());
if ((maybe.FromJust() & DONT_DELETE) != 0) {
// ES#sec-globaldeclarationinstantiation 5.a:
// If envRec.HasVarDeclaration(name) is true, throw a SyntaxError
// exception.
// ES#sec-globaldeclarationinstantiation 5.d:
// If hasRestrictedGlobal is true, throw a SyntaxError exception.
MessageLocation location(script, 0, 1);
return isolate->ThrowAt<Context>(
isolate->factory()->NewSyntaxError(
MessageTemplate::kVarRedeclaration, name),
&location);
}
JSGlobalObject::InvalidatePropertyCell(global_object, name);
}
}
Handle<Context> result =
isolate->factory()->NewScriptContext(native_context, scope_info);
result->Initialize(isolate);
Handle<ScriptContextTable> new_script_context_table =
ScriptContextTable::Extend(script_context, result);
native_context->synchronized_set_script_context_table(
*new_script_context_table);
return result;
}
IsLexicalVariableMode
所有mode=kLet或kConst返回true
inline bool IsLexicalVariableMode(VariableMode mode) {
STATIC_ASSERT(static_cast<uint8_t>(VariableMode::kLet) ==
0); // Implies that mode >= VariableMode::kLet.
return mode <= VariableMode::kLastLexicalVariableMode;
}
VariableMode
// The order of this enum has to be kept in sync with the predicates below.
enum class VariableMode : uint8_t {
// User declared variables:
kLet, // declared via 'let' declarations (first lexical)
kConst, // declared via 'const' declarations (last lexical)
kVar, // declared via 'var', and 'function' declarations
// Variables introduced by the compiler:
kTemporary, // temporary variables (not user-visible), stack-allocated
// unless the scope as a whole has forced context allocation
kDynamic, // always require dynamic lookup (we don't know
// the declaration)
kDynamicGlobal, // requires dynamic lookup, but we know that the
// variable is global unless it has been shadowed
// by an eval-introduced variable
kDynamicLocal, // requires dynamic lookup, but we know that the
// variable is local and where it is unless it
// has been shadowed by an eval-introduced
// variable
// Variables for private methods or accessors whose access require
// brand check. Declared only in class scopes by the compiler
// and allocated only in class contexts:
kPrivateMethod, // Does not coexist with any other variable with the same
// name in the same scope.
kPrivateSetterOnly, // Incompatible with variables with the same name but
// any mode other than kPrivateGetterOnly. Transition to
// kPrivateGetterAndSetter if a later declaration for the
// same name with kPrivateGetterOnly is made.
kPrivateGetterOnly, // Incompatible with variables with the same name but
// any mode other than kPrivateSetterOnly. Transition to
// kPrivateGetterAndSetter if a later declaration for the
// same name with kPrivateSetterOnly is made.
kPrivateGetterAndSetter, // Does not coexist with any other variable with the
// same name in the same scope.
kLastLexicalVariableMode = kConst,
};