JS这两种写法有什么不同

1

var getLength = (function(){
               .....
   })();

2

  function getLength (){
                    .....
    }
阅读 10.9k
7 个回答
// 写法1
var getLength = function(){
    .....
};
// 写法2
function getLength (){
    .....
}

我觉得你想问的应该是这两种写法的区别是什么。

从执行的时候效果来看,两种写法都可以通过 getLength() 这种方式来调用去执行。

但是实际上这两种写法是不一样的。

写法1

我暂时给这种写法取个名字:变量声明及函数表达式的引用赋值。

写法1中包含了三层意思

  1. 声明一个变量 getLength
  2. 声明一个匿名函数
  3. 变量 getLength 赋值为匿名函数的引用

就是说,写法1中的“函数声明”是在代码执行期——代码执行的时候——去“声明”的。

如果你想要执行 getLength(),就必须在该行代码执行以后才能成功调用。

例如

getLength();  // 在赋值前执行
// TypeError: undefined is not a function
// 语法分析阶段不会报错,当代码执行到上面时,就会报 TypeError,因为 getLength 尚未赋值

var getLength = function(){
                   .....
};

写法2

写法2 可以是正宗的函数声明。

其作用就是声明一个名为 getLength 的函数。

函数声明是在语法分析阶段就已经完成(代码执行前)。故我们可以这样

getLength();  // 完全OK

function getLength(){
         .....
};

语法糖?

不是语法糖,不是语法糖。

前文已经分析过,这两种书写方式对解释器来说是在不同阶段完成对函数的“声明”。

一个是在代码执行期完成“声明”,一个是在语法分析阶段完成声明。

// 例如下面的代码是用来获取函数的函数名,我们可以发现两种方式声明的函数是不一样的
var f = function() { console.log(arguments.callee.name) }
f();
// 此时返回 "" (空字符串)

function f() { console.log(arguments.callee.name) }
f();
// 此时返回 "f"

应用场景

一般场景下,两种都能用。用法也差不多。只不过函数表达式赋值方式需要前置,而函数声明可以后置。

如果需要函数自己引用自己,这个时候推荐使用函数声明。因为 arguments.callee 在 ES5 strict mode 是禁用的。

例如

function F(n) {
  if(n < 1) {
    return 1   
  }
  return F(n-1) + n;
}

如果是对象的方法声明,可以使用函数表达式赋值的方式。

例如

var obj = {
  getValue : function() {return 'obj';}
}

又或者你要延迟声明函数,或者动态修改函数内容,可以使用函数表达式赋值方式。

其他场景,怎么舒服怎么用呗。

PS

文中用引号包裹起来的声明其效果就是赋值。

var getLength = (function(){
    .....
})();

关于作者原文中的这个函数。用一句话概括。

声明一个变量 getLength,并将一个匿名函数的返回值赋值给他。

如果你了解面向对象思想的话,前者是js以类的形式表示,后者是以面向过程的的方式展示。

最近在拜读《JavaScript语言精粹》。书中113页相关内容如下:

function语句对比function表达式

JavaScript既有function语句,同时也有function表达式。这令人困惑,因为它们看起来好像就是相同的。一个function语句就是其值为一个函数的var语句的速记形式。

下面的语句:

  function foo() {}

意思相当于:

  var foo = function foo() {};

在整本书中,我一直使用的是第2种形式,因为它能明确表示foo是一个包含一个函数值的变量。要用好这门语言,理解函数就是数值是很重要的。

function语句在解析时会发生被提升的情况。这意味着不管function被放置在哪里,它会被移动到被定义时所在作用域的顶层。这放宽了函数必须先声明后使用的要求,而我认为这会导致混乱。在if语句中使用function语句也是被禁止的。结果表明大多数的浏览器都允许在if语句里使用function语句,但它们在解析时的处理各不相同。这就造成了可移植性的问题。

一个语句不能以一个函数表达式开头,因为官方的语法假定以单词function开头的语句是一个function语句。解决方法时把函数调用括在一个圆括号之中。

  (function () {
      var hidden_variable;

      //这个函数可能对环境有一些影响,但不会引入新的全局变量。
  }());

第一种情况getLength的值是自运行匿名函数返回的值,而不是函数;第二种情况getLength才是函数。

不同意见 @HJin.me

方法一

var getlength = (function(){console.log("run")})()

申明一个getlength变量,但是并没有给它赋值

(function(){})() 是一个立即执行的函数

getlength 能得到的是这个匿名函数的返回值

不认同你所说的变量 getLength 赋值为匿名函数的引用

如果是引用那么getlength() 就应该是个可执行的函数

但是考虑下

var getlength = (function(){
    console.log("this is a test");
})()

对getlength typeof 发现会是一个undefined

@HJin.me 回答的非常棒!但是有一点补充一下,就是即使在 ES5 strict mode 下,要调用自己也是可以用匿名函数的方式的:

var a = 0,
    b = 111,
    c = function b() {
      if (a == 2) {return}
      a++
      b()
    }

c()

最终 a == 2 && b == 111

如果在函数 b 外部调用 b() ,会报错说:"TypeError: number is not a function"

这样的写法也可以用于 shim JavaScript 在低级浏览器下没有 .name 属性的困境,通过将函数 .toString() 然后通过正则表达式就能够提取出函数的名称了。

简单来说 function fun() 这种方法声明的函数全局可用,在声明的前面也可以用 具有预载特性,第二种 fun=function() 要执行了之后才能被访问, 一般我推荐前者声明比较多,而后者看出js的概念和灵活性

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
宣传栏