Javascript的声明

系统 1958 0
Quiz

 

下面Javascript代码为什么能运行?

      
        hello();


      
      
        function
      
      
         hello(){
    alert(
      
      "Hello, world!"
      
        );
}
      
    

但对于C,这么写会报错:

      #include 
      
        "
      
      
        stdio.h
      
      
        "
      
      
        void
      
      
         main(){
    hello();
}


      
      
        void
      
      
         hello(){
    printf(
      
      
        "
      
      
        Hello, world\n
      
      
        "
      
      
        );
}
      
    

由于hello没有被预先声明,代码“hello()”被认为是隐式声明,而隐式声明返回类型是int,所以提示hello类型错误。

通过预先声明或者将main函数放在hello函数的后面可以很容易解决这个问题。

那么对于Javascript却能运行,这代表了什么呢?

 

被提升的声明

Javascript引擎会先对代码解释,将声明提升,然后再执行。例如为了判断一个变量定义与否,如果我们如此写是会出引用错误的:

      
        if
      
      (someVar ===
      
         undefined){
    alert(
      
      "someVar未定义"
      
        );
}
      
    

但如果这样却不会出错:

      
        if
      
      (someVar ===
      
         undefined){
    
      
      
        var
      
      
         someVar = 1;
    alert(
      
      "someVar未定义"
      
        );
}
      
    

可见声明被提升了,但只有声明被提升了,因为someVar依然等于undefined,而不是1。

值得一提的是,这样子写也会报错:

      
        if
      
      (someVar ===
      
         undefined){
    someVar 
      
      = 1
      
        ;
    alert(
      
      "someVar未定义"
      
        );
}
      
    

这证明在解释阶段,隐式声明是没有作用的!而且为了让代码逻辑清晰,还是用显式声明吧!

 

chrome浏览器的诡异现象

 chrome浏览器(至少在本文签写时的最新版本 22.0.1229.94 m依然是如此 )有个诡异的现象:

      
        var
      
       name = 20
      
        ;
alert(
      
      
        typeof
      
      (name));    
      
        //
      
      
        string
      
      
name += 12
      
        ;
alert(name);    
      
      
        //
      
      
        2012
      
    

所以请不要把name定义为除字符串的其他类型,当然可以的话也尽量避免使用这个全局变量吧。

 

函数的两种创建方式

函数申明:

function  函数名  ( 参数 可选 ){  函数体   }

函数表达式:

function 函数名 可选  (参数 可选 ){ 函数体   }

Syntax
FunctionDeclaration :
function Identifier ( FormalParameterList opt ) { FunctionBody }
FunctionExpression :
function Identifier opt  ( FormalParameterListopt ) { FunctionBody }

—— Standard ECMA-262 ECMAScript Language Specification   . ECMA

为什么函数要分声明( Function Declaration)和表达式( Function Expression)呢?

译注:实际上FunctionDeclaration和FunctionExpression都是函数产生的语法,这和一般编程语言中函数声明只是定义接受参数数量及类型与返回值类型不太相同。或者说,这根本不是字面意义上的函数声明。我们可以理解对于Javascript的函数声明(FunctionDeclaration)其实是声明式(即需要提升的)函数产生语法,而函数表达式(FunctionExpression)则是表达式式(即执行时产生)函数产生语法。

—— WhiteSnow

主要为了区分函数的创建是否需要被提升,如果是函数声明就需要被提升创建,但如果是表达式,那么可以在执行时再创建。这样是很必要的,比如我们可以利用表达式动态定义函数:

      
        var
      
      
         foo;


      
      
        if
      
      
        (Condition){
    foo 
      
      = 
      
        function
      
      
        (){
        
      
      
        //
      
      
        do something
      
      
            }
}
      
      
        else
      
      
        {
    foo 
      
      = 
      
        function
      
      
        (){
        
      
      
        //
      
      
        do anything else
      
      
            }
}
      
    

再比如对于匿名函数:

      (
      
        function
      
      
        (){
    
      
      
        //
      
      
        do something
      
      
})();
    

声明提升也没什么意义,因为它不会在别的地方被引用。

 

如何判断函数声明与函数表达式

  • 匿名函数必然是函数表达式
  • 如果有名字的函数作为赋值表达式的一部分那么他也是一个表达式
  • 如果有名字的函数被括号“()”括住,那么他也是一个表达式

本文不准备深入命名函数表达式(named function expressions),具体可参见参考文献,不过一般应当避免命名函数表达式的使用,因为大部分功能都可以用匿名函数找到替代方案,或者说实际使用中不必考虑命名函数表达式。

 

匿名函数立刻执行

我们经常希望匿名函数定义好后立刻执行,但这么写会抛出语法错误:

      
        function
      
      
        (){
    alert(
      
      1
      
        );
}();
      
    

正确写法如下。

  • 声明一个函数对象,然后执行它:
      (
      
        function
      
      
        (){
    alert(
      
      1
      
        );
})();
      
    
  • 用括号强制执行:
      (
      
        function
      
      
        (){
    alert(
      
      1
      
        );
}());
      
    
  • 使用void操作符:
      
        void
      
      
        function
      
      
        (){
    alert(
      
      1
      
        );
}();
      
    

 

总结

  • Javascript中声明会被提升;
  • 对于变量显式声明提升的仅仅是声明,赋值并未被提升;
  • 对于函数声明由于其赋值和声明是一体的,所以提升的是整个函数的定义;
  • 变量隐式声明和函数表达式不会被提升。

 

思考题

1.  如果我们用函数表达式来创建函数,而不是用函数声明来创建,刚开始的题目会如何呢?

      
        hello();


      
      
        var
      
       hello = 
      
        function
      
      
        (){
    alert(
      
      "Hello, world!"
      
        );
}
      
    

 2.  下面是一个Button类,并创建了一个他的实例,我们可以在浏览器中看到一个按钮,但是为什么单机按钮时alert出来的数值不是13,而是空的呢?如何能alert出我们设置的数值?

      
        function
      
      
         Button(clickFunction) {
    
      
      
        this
      
      .button = document.createElement("button"
      
        );
    
      
      
        this
      
      .button.appendChild(document.createTextNode("Test"
      
        ));
    document.body.appendChild(
      
      
        this
      
      
        .button);
    
      
      
        this
      
      .button.onclick = 
      
        function
      
      (){alert(
      
        this
      
      
        .value);}
}

      
      
        var
      
       bt = 
      
        new
      
       Button(13);    
      
        //
      
      
        单击这个button的时候alert出空
      
    

 

 

参考资料

 

Standard ECMA-262 ECMAScript Language Specification   . ECMA .  June 2011

Named function expressions demystified . Juriy "kangax" Zaytsev  .  June 17, 2009

函数式JavaScript编程指南 . ShiningRay (译) . 2008/01/02

Javascript的声明


更多文章、技术交流、商务合作、联系博主

微信扫码或搜索:z360901061

微信扫一扫加我为好友

QQ号联系: 360901061

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描下面二维码支持博主2元、5元、10元、20元等您想捐的金额吧,狠狠点击下面给点支持吧,站长非常感激您!手机微信长按不能支付解决办法:请将微信支付二维码保存到相册,切换到微信,然后点击微信右上角扫一扫功能,选择支付二维码完成支付。

【本文对您有帮助就好】

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描上面二维码支持博主2元、5元、10元、自定义金额等您想捐的金额吧,站长会非常 感谢您的哦!!!

发表我的评论
最新评论 总共0条评论