块内定义的函数会不会影响块外的作用域?
发布于 5 年前 作者 q86002618 2991 次浏览 来自 问答

以下是我的个人思考

非严格模式下

首先我是看了阮一峰的ES6 标准的一个例子

function f(){ console.log(' I am outside'); }
(function (){
    if(false){
    //重复声明一次函数f
    function f() { console.log('I am inside'); }
    }

    f();
}());

按照阮一峰的讲解,ES6支持块级作用域,不管会不会进入到if代码,其内部声明的函数皆不会影响到块级作用域的外部,在ES6中输出结果应该为"I am outside"

我在Node.js v7.9.0在非严格模式下运行的时候发生了错误 TypeError: f is not a function。

这说明 f是已经声明了,但它还不是一个函数。我又把代码中false改成了true。

function f(){ console.log(' I am outside'); }
(function (){
    if(true){
    //重复声明一次函数f
    function f() { console.log('I am inside'); }
    }

    f();
}());

结果控制台输出"I am inside"。 所以我觉得在非严格模式下,不管块会不会被执行,块内定义的函数都会影响块外的作用域,会有类似”变量提升“的效果。 就像下面这段代码那样:

function f(){ console.log(' I am outside'); }
(function (){
	var f;
    if(false){
    //给f赋值
    f = function() { console.log('I am inside'); }
    }

    f();
}());

严格模式下

但是在严格模式下,就不会有影响

'use strict'
(function(){
    if(false){
        function f(){
            console.log("I am inside!");
        }
    }
    console.log(typeof f);
    console.log(f.toString());
    f();
})();

输出结果:

/*
function
function f(){
    console.log("I am outside!");
}
I am outside!
*/

按照阮一峰的说法,严格模式下,函数只能在顶层作用域和函数作用域内声明,其他情况就会报错,可是我在Node.js下用严格模式运行并没有报错。 那我就在想,会不会在严格模式下,在块级作用域内定义的函数根本就声明不了?那也就不存在会不会影响块外作用域的事情了。 我又把代码改了下:

function f(){
    console.log("I am outside!");
}
(function(){
    if(true){
        function f(){
            console.log("I am inside!");
        }
        console.log(typeof f);
        console.log(f.toString());
    }
    console.log(typeof f);
    console.log(f.toString());
    f();
})();

输出结果:

/*
function
function f(){
            console.log("I am inside!");
        }
function
function f(){
    console.log("I am outside!");
}
I am outside!
*/

6 回复

好复杂呀,但我觉得没必要搞清楚那么复杂的问题。其实,在嵌套的函数中,最好别使用这种语法,而是使用

let f = function() {};

@zhanzhenzhen 能不能再讲清楚一点?😝

来自酷炫的 CNodeMD

根据Douglas Crockford的《JavaScript精粹》一书,函数最好都不要使用function f()这种形式,而应该使用f=function()这种形式(原因我忘了)。似乎很多“函数式语言”,例如F#,就是只支持后者的形式。该书作者是JSON的设计者。

我猜想原因可能就是容易搞清楚前后顺序吧。所以我从很多年前开始,就使用这种方式了。而且这种方式和ES2015箭头函数的区别也小。比较“兼容”。

@zhanzhenzhen 正好最近阅读日买了这本书,回头去看看,谢谢啦

来自酷炫的 CNodeMD

回到顶部