我最近开始保持别人的JavaScript代码,我正在修复错误,添加功能,也试图更新代码并使其更加一致。

以前的开发人员使用了两种方式来宣布功能,我无法解决是否有原因。

兩種方式是:

var functionOne = function() {
    // Some code
};
function functionTwo() {
    // Some code
}

使用这两种不同的方法的原因是什么?每个方法的优点和缺点是什么?可以用一种方法做些什么,不能用另一种方法做些什么?


当前回答

function x() {
    console.log('x');
}

x(); // Works even though it's above the declaration
function x() {
    console.log('x');
}

if (someCondition) {
    function foo() {    // <===== HERE THERE
    }                   // <===== BE DRAGONS
}

"use strict";
if (someCondition) {
    foo();               // Works just fine
    function foo() {
    }
}
console.log(typeof foo); // "undefined" (`foo` is not in scope here
                         // because it's not in the same block)

var y = function () {
    console.log('y');
};

名称函数表达式

var z = function w() {
    console.log('zw')
};

var z = function w() {
    console.log(typeof w); // "function"
};
console.log(typeof w);     // "undefined"

配件功能启动器(ES5+)

var obj = {
    value: 0,
    get f() {
        return this.value;
    },
    set f(v) {
        this.value = v;
    }
};
console.log(obj.f);         // 0
console.log(typeof obj.f);  // "number"

您还可以使用 Object.defineProperty、Object.defineProperties 和 Object.create 更不熟悉的第二个论点创建附件功能。

Arrow 功能表达式(ES2015+)

var a = [1, 2, 3];
var b = a.map(n => n * 2);
console.log(b.join(", ")); // 2, 4, 6

看到 n => n * 2 隐藏在地图() 呼叫? 这是一个函数。

关于箭头功能的一些事情:

他們沒有自己的這一點. 相反,他們關閉了他們所定義的背景的這一點. (他們也關閉了論點,在相關的情況下,超級.) 這意味著他們內在的這一點是相同的這一點,在那裡他們是創造的,並且不能改變。

var a = [1, 2, 3];
var b = a.map((n, i) => n * i);
console.log(b.join(", ")); // 0, 2, 6

如果您正在做一个单一表达式以上,请使用 {} 和一个明确的回报(如果您需要返回值),如正常:

var a = [
  {first: "Joe", last: "Bloggs"},
  {first: "Albert", last: "Bloggs"},
  {first: "Mary", last: "Albright"}
];
a = a.sort((a, b) => {
  var rv = a.last.localeCompare(b.last);
  if (rv === 0) {
    rv = a.first.localeCompare(b.first);
  }
  return rv;
});
console.log(JSON.stringify(a));

对象初步化方法宣言(ES2015+)

var o = {
    foo() {
    }
};

var o = {
    foo: function foo() {
    }
};

ES2015为我们提供类合成,包括声明的建筑师和方法:

class Person {
    constructor(firstName, lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
    }

    getFullName() {
        return this.firstName + " " + this.lastName;
    }
}

其他回答

鉴于“名称函数在轨道上出现”的论点,现代的JavaScript引擎实际上非常能够代表匿名函数。

至于这篇文章,V8,SpiderMonkey,Chakra和Nitro总是提到他们的名字命名的函数,他们几乎总是提到一个匿名函数,它的识别器,如果它有一个。

SpiderMonkey 可以从另一个函数返回的匿名函数的名称。

如果你真的,真的想要你的 iterator 和成功的呼叫回复出现在轨道上,你可以命名那些也。

[].forEach(function iterator() {});

但是,大多数情况下,它不值得强调。

哈里斯(Fiddle)

'use strict';

var a = function () {
    throw new Error();
},
    b = function b() {
        throw new Error();
    },
    c = function d() {
        throw new Error();
    },
    e = {
        f: a,
        g: b,
        h: c,
        i: function () {
            throw new Error();
        },
        j: function j() {
            throw new Error();
        },
        k: function l() {
            throw new Error();
        }
    },
    m = (function () {
        return function () {
            throw new Error();
        };
    }()),
    n = (function () {
        return function n() {
            throw new Error();
        };
    }()),
    o = (function () {
        return function p() {
            throw new Error();
        };
    }());

console.log([a, b, c].concat(Object.keys(e).reduce(function (values, key) {
    return values.concat(e[key]);
}, [])).concat([m, n, o]).reduce(function (logs, func) {

    try {
        func();
    } catch (error) {
        return logs.concat('func.name: ' + func.name + '\n' +
                           'Trace:\n' +
                           error.stack);
        // Need to manually log the error object in Nitro.
    }

}, []).join('\n\n'));

V8

func.name: 
Trace:
Error
    at a (http://localhost:8000/test.js:4:11)
    at http://localhost:8000/test.js:47:9
    at Array.reduce (native)
    at http://localhost:8000/test.js:44:27

func.name: b
Trace:
Error
    at b (http://localhost:8000/test.js:7:15)
    at http://localhost:8000/test.js:47:9
    at Array.reduce (native)
    at http://localhost:8000/test.js:44:27

func.name: d
Trace:
Error
    at d (http://localhost:8000/test.js:10:15)
    at http://localhost:8000/test.js:47:9
    at Array.reduce (native)
    at http://localhost:8000/test.js:44:27

func.name: 
Trace:
Error
    at a (http://localhost:8000/test.js:4:11)
    at http://localhost:8000/test.js:47:9
    at Array.reduce (native)
    at http://localhost:8000/test.js:44:27

func.name: b
Trace:
Error
    at b (http://localhost:8000/test.js:7:15)
    at http://localhost:8000/test.js:47:9
    at Array.reduce (native)
    at http://localhost:8000/test.js:44:27

func.name: d
Trace:
Error
    at d (http://localhost:8000/test.js:10:15)
    at http://localhost:8000/test.js:47:9
    at Array.reduce (native)
    at http://localhost:8000/test.js:44:27

func.name: 
Trace:
Error
    at e.i (http://localhost:8000/test.js:17:19)
    at http://localhost:8000/test.js:47:9
    at Array.reduce (native)
    at http://localhost:8000/test.js:44:27

func.name: j
Trace:
Error
    at j (http://localhost:8000/test.js:20:19)
    at http://localhost:8000/test.js:47:9
    at Array.reduce (native)
    at http://localhost:8000/test.js:44:27

func.name: l
Trace:
Error
    at l (http://localhost:8000/test.js:23:19)
    at http://localhost:8000/test.js:47:9
    at Array.reduce (native)
    at http://localhost:8000/test.js:44:27

func.name: 
Trace:
Error
    at http://localhost:8000/test.js:28:19
    at http://localhost:8000/test.js:47:9
    at Array.reduce (native)
    at http://localhost:8000/test.js:44:27

func.name: n
Trace:
Error
    at n (http://localhost:8000/test.js:33:19)
    at http://localhost:8000/test.js:47:9
    at Array.reduce (native)
    at http://localhost:8000/test.js:44:27

func.name: p
Trace:
Error
    at p (http://localhost:8000/test.js:38:19)
    at http://localhost:8000/test.js:47:9
    at Array.reduce (native)
    at http://localhost:8000/test.js:44:27 test.js:42

蜘蛛侠

func.name: 
Trace:
a@http://localhost:8000/test.js:4:5
@http://localhost:8000/test.js:47:9
@http://localhost:8000/test.js:54:1


func.name: b
Trace:
b@http://localhost:8000/test.js:7:9
@http://localhost:8000/test.js:47:9
@http://localhost:8000/test.js:54:1


func.name: d
Trace:
d@http://localhost:8000/test.js:10:9
@http://localhost:8000/test.js:47:9
@http://localhost:8000/test.js:54:1


func.name: 
Trace:
a@http://localhost:8000/test.js:4:5
@http://localhost:8000/test.js:47:9
@http://localhost:8000/test.js:54:1


func.name: b
Trace:
b@http://localhost:8000/test.js:7:9
@http://localhost:8000/test.js:47:9
@http://localhost:8000/test.js:54:1


func.name: d
Trace:
d@http://localhost:8000/test.js:10:9
@http://localhost:8000/test.js:47:9
@http://localhost:8000/test.js:54:1


func.name: 
Trace:
e.i@http://localhost:8000/test.js:17:13
@http://localhost:8000/test.js:47:9
@http://localhost:8000/test.js:54:1


func.name: j
Trace:
j@http://localhost:8000/test.js:20:13
@http://localhost:8000/test.js:47:9
@http://localhost:8000/test.js:54:1


func.name: l
Trace:
l@http://localhost:8000/test.js:23:13
@http://localhost:8000/test.js:47:9
@http://localhost:8000/test.js:54:1


func.name: 
Trace:
m</<@http://localhost:8000/test.js:28:13
@http://localhost:8000/test.js:47:9
@http://localhost:8000/test.js:54:1


func.name: n
Trace:
n@http://localhost:8000/test.js:33:13
@http://localhost:8000/test.js:47:9
@http://localhost:8000/test.js:54:1


func.name: p
Trace:
p@http://localhost:8000/test.js:38:13
@http://localhost:8000/test.js:47:9
@http://localhost:8000/test.js:54:1

查克拉

func.name: undefined
Trace:
Error
   at a (http://localhost:8000/test.js:4:5)
   at Anonymous function (http://localhost:8000/test.js:47:9)
   at Global code (http://localhost:8000/test.js:42:1)


func.name: undefined
Trace:
Error
   at b (http://localhost:8000/test.js:7:9)
   at Anonymous function (http://localhost:8000/test.js:47:9)
   at Global code (http://localhost:8000/test.js:42:1)


func.name: undefined
Trace:
Error
   at d (http://localhost:8000/test.js:10:9)
   at Anonymous function (http://localhost:8000/test.js:47:9)
   at Global code (http://localhost:8000/test.js:42:1)


func.name: undefined
Trace:
Error
   at a (http://localhost:8000/test.js:4:5)
   at Anonymous function (http://localhost:8000/test.js:47:9)
   at Global code (http://localhost:8000/test.js:42:1)


func.name: undefined
Trace:
Error
   at b (http://localhost:8000/test.js:7:9)
   at Anonymous function (http://localhost:8000/test.js:47:9)
   at Global code (http://localhost:8000/test.js:42:1)


func.name: undefined
Trace:
Error
   at d (http://localhost:8000/test.js:10:9)
   at Anonymous function (http://localhost:8000/test.js:47:9)
   at Global code (http://localhost:8000/test.js:42:1)


func.name: undefined
Trace:
Error
   at e.i (http://localhost:8000/test.js:17:13)
   at Anonymous function (http://localhost:8000/test.js:47:9)
   at Global code (http://localhost:8000/test.js:42:1)


func.name: undefined
Trace:
Error
   at j (http://localhost:8000/test.js:20:13)
   at Anonymous function (http://localhost:8000/test.js:47:9)
   at Global code (http://localhost:8000/test.js:42:1)


func.name: undefined
Trace:
Error
   at l (http://localhost:8000/test.js:23:13)
   at Anonymous function (http://localhost:8000/test.js:47:9)
   at Global code (http://localhost:8000/test.js:42:1)


func.name: undefined
Trace:
Error
   at Anonymous function (http://localhost:8000/test.js:28:13)
   at Anonymous function (http://localhost:8000/test.js:47:9)
   at Global code (http://localhost:8000/test.js:42:1)


func.name: undefined
Trace:
Error
   at n (http://localhost:8000/test.js:33:13)
   at Anonymous function (http://localhost:8000/test.js:47:9)
   at Global code (http://localhost:8000/test.js:42:1)


func.name: undefined
Trace:
Error
   at p (http://localhost:8000/test.js:38:13)
   at Anonymous function (http://localhost:8000/test.js:47:9)
   at Global code (http://localhost:8000/test.js:42:1)

尼特

func.name: 
Trace:
a@http://localhost:8000/test.js:4:22
http://localhost:8000/test.js:47:13
reduce@[native code]
global code@http://localhost:8000/test.js:44:33

func.name: b
Trace:
b@http://localhost:8000/test.js:7:26
http://localhost:8000/test.js:47:13
reduce@[native code]
global code@http://localhost:8000/test.js:44:33

func.name: d
Trace:
d@http://localhost:8000/test.js:10:26
http://localhost:8000/test.js:47:13
reduce@[native code]
global code@http://localhost:8000/test.js:44:33

func.name: 
Trace:
a@http://localhost:8000/test.js:4:22
http://localhost:8000/test.js:47:13
reduce@[native code]
global code@http://localhost:8000/test.js:44:33

func.name: b
Trace:
b@http://localhost:8000/test.js:7:26
http://localhost:8000/test.js:47:13
reduce@[native code]
global code@http://localhost:8000/test.js:44:33

func.name: d
Trace:
d@http://localhost:8000/test.js:10:26
http://localhost:8000/test.js:47:13
reduce@[native code]
global code@http://localhost:8000/test.js:44:33

func.name: 
Trace:
i@http://localhost:8000/test.js:17:30
http://localhost:8000/test.js:47:13
reduce@[native code]
global code@http://localhost:8000/test.js:44:33

func.name: j
Trace:
j@http://localhost:8000/test.js:20:30
http://localhost:8000/test.js:47:13
reduce@[native code]
global code@http://localhost:8000/test.js:44:33

func.name: l
Trace:
l@http://localhost:8000/test.js:23:30
http://localhost:8000/test.js:47:13
reduce@[native code]
global code@http://localhost:8000/test.js:44:33

func.name: 
Trace:
http://localhost:8000/test.js:28:30
http://localhost:8000/test.js:47:13
reduce@[native code]
global code@http://localhost:8000/test.js:44:33

func.name: n
Trace:
n@http://localhost:8000/test.js:33:30
http://localhost:8000/test.js:47:13
reduce@[native code]
global code@http://localhost:8000/test.js:44:33

func.name: p
Trace:
p@http://localhost:8000/test.js:38:30
http://localhost:8000/test.js:47:13
reduce@[native code]
global code@http://localhost:8000/test.js:44:33

区别在于,函数One 是一种函数表达式,因此只有在到达该行时才定义,而函数Two 是一种函数声明,并在其周围函数或脚本执行后才定义。

例如,函数表达式:

// TypeError: functionOne 不是函数函数One(); var 函数One = 函数() { console.log(“Hello!”); };

还有一个功能声明:

// 输出: “Hello!”函数Two();函数函数Two() { console.log(“Hello!”); }

“使用严格”; { // 注意此区块! 函数三() { console.log(“Hello!”); } } 函数三(); // 参考错误

兩個函數之間的另一個區別是函數One 可以用作可持有多個函數的變量,而函數Two 持有某些代碼區塊,在呼叫時全部執行。

   var functionOne = (function() {
      return {

         sayHello: function(){
                console.log('say hello')

         },
         redirectPage:function(_url){
                window.location.href = _url;
         }

      }
})();

您有一个选项,该函数将被称为. e.g 函数One.sayHello 或函数One. redirectPage. 如果您呼叫函数Two 那么整个代码块将被执行。

function xyz(){
  function abc(){};
  // abc is defined here...
}
// ...but not here

其次,可以结合两种风格:

var xyz = function abc(){};

var xyz = function abc(){
  // xyz is visible here
  // abc is visible here
}
// xyz is visible here
// abc is undefined here

function abc(){};
var xyz = abc;

console.log(xyz === abc); // prints "true"

function abc(){};
console.log(abc.name); // prints "abc"

var abc = function(){};
console.log(abc.name); // prints ""

它的名字是空的 - 我们创建了一个匿名函数,并将其分配给一些变量。

使用合并风格的另一个好理由是使用一个简短的内部名称来引用自己,同时为外部用户提供一个长而不冲突的名称:

// Assume really.long.external.scoped is {}
really.long.external.scoped.name = function shortcut(n){
  // Let it call itself recursively:
  shortcut(n - 1);
  // ...
  // Let it pass itself as a callback:
  someFunction(shortcut);
  // ...
}

在上面的例子中,我们可以用外部名称做同样的事情,但它会太不多(而且更慢)。

function abc(){}

abc在这里在当前范围内在任何地方都被定义:

// We can call it here
abc(); // Works

// Yet, it is defined down there.
function abc(){}

// We can call it again
abc(); // Works

// We can call it here
abc(); // Works
return;
function abc(){}

这是一个功能表达:

var xyz = function(){};

xyz 在这里从分配点定义:

// We can't call it here
xyz(); // UNDEFINED!!!

// Now it is defined
xyz = function(){}

// We can call it here
xyz(); // works

函数声明与函数表达是格雷格所证明的差异的真正原因。

有趣的事实:

var xyz = function abc(){};
console.log(xyz.name); // Prints "abc"

var abc = function(){};

我知道我定义了函数本地,当我定义了函数如

abc = function(){};

function abc(){};

它取决于背景,可能会让你猜测它实际上在哪里定义,特别是在 eval()的情况下 - 答案是: 它取决于浏览器。

名称功能 vs. 匿名功能

第一函数合成是匿名函数表达式:

var functionOne = function() {
  // do something...
};

但是,第二个是功能宣言:

function functionTwo () {
  // do something...
}

兩者之間的主要區別是函數名稱,因為匿名函數沒有呼叫的名稱. 匿名函數是快速且容易宣告的,許多圖書館和工具往往鼓勵這種愚蠢的代碼風格. 然而,匿名函數有一些缺點:

可读性:匿名函数忽略了一个名称,可能会导致更少可读的代码。 解密: 匿名函数没有名称,可以使解密更困难。

名称函数表达式

為您的功能表達提供一個名稱,非常有效地解決所有這些缺點,並且沒有實際的缺點。

setTimeout(function timeHandler() { // <-- look, a name here!
  console.log("I've waited 1 second");
}, 1000);

名称 IIFEs(即时启发功能表达)

(function IIFE(str) { // <-- look, always name IIFEs!
  console.log(str); // "Hello!"
})('Hello!');

对于一个变量的函数,这个函数的名称,在这种情况下,不太常见,可能会导致混乱,在这种情况下,箭头函数可能是一个更好的选择。