我在网络上找到了这个简短的JavaScript代码段:
var foo = 1;
function bar() {
foo = 10;
return;
function foo() {}
}
bar();
console.log(foo);
我希望忽略函数 bar()中return语句之后的内容,并将变量 foo 结尾等于10。然而,令我惊讶的是,控制台输出了一些非常不同的东西:
1
现在,当我在return语句后删除该行
var foo = 1;
function bar() {
foo = 10;
return;
}
bar();
console.log(foo);
控制台按预期打印出来:
10
有谁能解释一下导致foo在前一版代码中返回1的原因是什么?
答案 0 :(得分:6)
函数声明被提升到其包含上下文的顶部。您实际上是在var foo
功能的顶部创建bar
。
foo
中操纵的bar
是该函数的本地操作,不会影响全局上下文foo
。
http://www.adequatelygood.com/JavaScript-Scoping-and-Hoisting.html
答案 1 :(得分:2)
归功于hoisting
。
编译器基本上将其转换为:
function bar() {
function foo() {}
foo = 10;
return;
}
因此在分配之前有一个本地foo
,您只会覆盖本地。函数foo()
也将消失。
答案 2 :(得分:2)
tl; dr它是由于函数表达式和函数声明如何工作(也是函数提升):https://javascriptweblog.wordpress.com/2010/07/06/function-declarations-vs-function-expressions/
更详细的回复:
将以下console.log放在代码中将帮助您可视化正在发生的事情,我想回答您的问题。
apollo-angular@0.13.0
apollo-client@1.0.4
输出如下:
//same es6 module, above my class definition
const RecentSearchesQuery = gql`
query recentSearch {
recentSearch {
id
query
lastUpdated
userId
}
}
`;
const RecentSearchesMutation = gql`
mutation recentSearchSave($query:String!) {
recentSearchSave(query: $query)
}
`;
...
//my class method
updateRecentSearches(query: string) {
const updateQueries: MutationQueryReducersMap = {
RecentSearch: (prev: Object, {mutationResult}) => {
//execution doesn't get here
debugger;
alert('updateQueries handler in RecentSearchesMutation mutation for recentSearch');
...
}
};
return new Promise((resolve, reject) => {
this.apollo.mutate<any>({
mutation: RecentSearchesMutation,
variables: {query},
updateQueries
})
.subscribe({
next: ({data}) => {
resolve();
},
error: (error: ApolloError) => {
reject(error);
}
});
});
所以你怀疑,console.log('3',foo)和console.log('4',foo)永远不会在return语句之后被调用,这是预期的。你现在的问题可能是“为什么我的console.log('1',foo)被分配给函数foo(){}”,这可以通过以下SO问题回答,该问题描述函数声明与函数表达式,即< / p>
var foo = 1;
console.log('0', foo)
function bar() {
console.log('1', foo)
foo = 10;
console.log('2', foo)
return;
console.log('3', foo)
function foo() {}
console.log('4', foo)
}
console.log('5', foo)
bar();
console.log('6', foo)
VS
'0' 1
'5' 1
'1' function foo() {}
'2' 10
'6' 1
Why can I use a function before it's defined in Javascript?
基本上执行function foo(){}
时,var foo = function(){}
的直接定义变为function(){},但这里的关键概念是bar
的定义是foo
内的本地定义1}}函数,在foo
范围之外,它仍然被赋值为1。
关于函数声明和表达式的另一个好读物:https://javascriptweblog.wordpress.com/2010/07/06/function-declarations-vs-function-expressions/
答案 3 :(得分:0)
这是因为代码转换为;
var foo = 1;
function bar() {
var foo;
foo = 10;
return;
function foo() {}
}
bar();
console.log(foo);
这是因为JavaScript总是将变量声明而不是初始化移动到范围的顶部。