正确使用const来定义JavaScript中的函数

时间:2015-10-09 14:22:01

标签: javascript function const ecmascript-6

我感兴趣的是,在JavaScript中使用const在特定函数中可以设置哪些类型的值有任何限制。这有效吗?虽然它确实有效,但是出于任何原因它被认为是不好的做法?

const doSomething = () => {
   ...
}

是否应该在ES6中以这种方式定义所有功能?如果是这样的话,似乎并没有这样。

感谢您的任何评论!

7 个答案:

答案 0 :(得分:165)

你所做的事情没有问题,但你必须记住函数声明和函数表达式之间的区别。

一个函数声明,即:

function doSomething () {}

完全悬挂在范围的顶部(与letconst一样,它们也是块范围的。)

这意味着以下内容可行:

doSomething() // works!
function doSomething() {}

函数表达式,即:

[const | let | var] = function () {} (or () =>

是创建匿名函数(function () {})还是创建变量,然后将该匿名函数赋值给该变量。

因此,范围内变量提升的通常规则 - 块范围变量(letconst)不会将undefined提升到其块范围的顶部。< / p>

这意味着:

if (true) {
    doSomething() // will fail
    const doSomething = function () {}
}

由于未定义doSomething,因此会失败。 (它将抛出ReferenceError

如果您切换到使用var,您可以将变量挂起,但会将其初始化为undefined,以便上面的代码块仍无效。 (这将抛出TypeError,因为doSomething在您调用它时不是函数)

就标准做法而言,您应该始终使用适当的工具。

Axel Rauschmayer在范围和悬挂方面有一篇很棒的文章,包括es6语义:Variables and Scoping in ES6

答案 1 :(得分:61)

虽然使用const来定义函数看起来像是一个黑客,但它带来了一些很大的优势,使它更优越(在我看来)

  1. 它使函数不可变,因此您不必担心该函数会被其他一些代码更改。

  2. 您可以使用胖箭头语法,它更短且更简单。清洁剂。

  3. 使用箭头功能会为您处理this绑定。

  4. function

    的示例

    &#13;
    &#13;
    // define a function
    function add(x, y) { return x + y; }
    
    // use it
    console.log(add(1, 2)); // 3
    
    // oops, someone mutated your function
    add = function (x, y) { return x - y; };
    
    // now this is not what you expected
    console.log(add(1, 2)); // -1
    &#13;
    &#13;
    &#13;

    const

    相同的示例

    &#13;
    &#13;
    // define a function (wow! that is 8 chars shorter)
    const add = (x, y) => x + y;
    
    // use it
    console.log(add(1, 2)); // 3
    
    // someone tries to mutate the function
    add = (x, y) => x - y; // Uncaught TypeError: Assignment to constant variable.
    // the intruder fails and your function remains unchanged
    &#13;
    &#13;
    &#13;

答案 2 :(得分:10)

问这个问题已经三年了,但是我现在遇到了这个问题。由于此答案离堆栈很遥远,请允许我重复一下:

  

问:我感兴趣的是,什么类型的值可以有限制   在JavaScript中使用const设置-特定功能。这有效吗?   虽然它确实有效,但是它被认为对任何人都是不良做法   原因?

在观察到一个多产的JavaScript编码器后,即使没有明显的理由/好处,我总是愿意做const的{​​{1}}语句,所以我有动机进行一些研究。 / p>

在回答“ 出于任何原因是否被认为是不良做法?”,IMO,是的,是的,或者至少在使用方面有优势 functions声明。

在我看来,这在很大程度上取决于偏好和风格。上面提供了一些很好的论据,但没有一个像本文中所讲的那么清晰:

Constant confusion: why I still use JavaScript function statements由medium.freecodecamp.org/Bill Sourour,JavaScript专家,顾问和老师共同完成。

即使您已经做出决定,我也希望所有人都阅读该文章。

以下是要点:

  

与[const]函数相比,函数语句有两个明显的优点   表达式:

     

优点#1:意图清晰性

  每天有成千上万的代码行,这对于弄清楚   尽可能快而轻松地实现程序员的意图。
  

     

优势2:声明顺序==执行顺序

     

理想情况下,我想或多或少按我声明的顺序声明代码   希望它会被执行。

     

这是我的首选:使用const声明的任何值   在执行之前无法访问关键字。

     

我上面所描述的迫使我们编写看起来像这样的代码   上下翻转。我们必须从最低级别的功能开始   我们上路。

     

我的大脑无法正常工作。我要在细节之前输入上下文。

     

大多数代码是由人类编写的。因此,大多数人的   理解顺序大致遵循大多数代码的执行顺序。

答案 3 :(得分:6)

使用const有一些非常重要的好处,有些人会说应该尽可能使用它,因为它有多么刻意和指示性。

就我所知,它是JavaScript中最具指示性和可预测性的变量声明,也是最有用的一个,因为它有多么受限制。为什么?因为它消除了varlet声明可用的一些可能性。

当您阅读const时,您能推断出什么?您只需阅读const声明语句即可知道以下所有内容,并且不扫描对该变量的其他引用:

  • 该值绑定到该变量(尽管其底层对象不是深层不可变的)
  • 无法在其直接包含的块
  • 之外访问它
  • 由于时间死区(TDZ)规则,在声明之前永远不会访问绑定。

以下引用来自an article,主张letconst的好处。它还更直接地回答了关于关键字约束/限制的问题:

  

letconst提供的约束是使代码更易于理解的强大方法。尝试在您编写的代码中尽可能多地产生这些约束。限制代码片段意味着什么的声明性约束越多,人类在将来阅读,解析和理解一段代码的速度就越快,越快。

     

当然,const声明的规则多于var声明的规则:块范围,TDZ,声明时分配,不重新分配。而var语句仅表示函数作用域。然而,规则计算并没有提供很多见解。最好在复杂性方面权衡这些规则:规则是增加还是减少复杂性?在const的情况下,块作用域意味着比函数作用域更窄的范围,TDZ意味着我们不需要从声明中向后扫描作用域以便在声明之前发现使用,并且赋值规则意味着绑定将始终保留相同的引用。

     

约束语句越多,一段代码就越简单。当我们为语句的含义添加约束时,代码变得不那么难以预测。这是静态类型程序通常比动态类型程序更容易阅读的最大原因之一。静态类型给程序编写器带来了很大的限制,但它也对程序的解释方式提出了很大的限制,使代码更容易理解。

     

考虑到这些论点,建议您尽可能使用const,因为这是让我们思考的可能性最小的陈述。

来源:https://ponyfoo.com/articles/var-let-const

答案 4 :(得分:1)

在某些特殊情况下, arrow functions不能解决问题:

  1. 如果我们要更改外部API的方法,并且需要对象的引用。

  2. 如果我们需要使用function表达式专有的特殊关键字:argumentsyieldbind等。 欲获得更多信息: Arrow function expression limitations

示例:

我在Highcharts API中将此函数分配为事件处理程序。 它是由库触发的,因此this关键字应与特定对象匹配。

export const handleCrosshairHover = function (proceed, e) {
  const axis = this; // axis object
  proceed.apply(axis, Array.prototype.slice.call(arguments, 1)); // method arguments
};

使用箭头函数,this将匹配声明范围,并且我们将无法访问API obj:

export const handleCrosshairHover = (proceed, e) => {
  const axis = this; // this = undefined
  proceed.apply(axis, Array.prototype.slice.call(arguments, 1)); // compilation error
};

答案 5 :(得分:-1)

另一种情况是常量函数可能有用。如果代码中有很多常量并且需要一个专门针对这些常量运行的函数,那么将该函数转换为常量本身可能是个好主意:

const FLAG_ONE   = 1;
const FLAG_TWO   = 2;
const FLAG_THREE = 4;
// etc.

// resolves flag into string for debugging purposes:
const FLAG_NAME = flag => {
    switch ( flag ) {
        case FLAG_ONE: return 'one';
        // etc.
    }
};

以任何方式将FLAG_NAME定义为常量,但它会提高代码的易读性。

答案 6 :(得分:-2)

根据我的经验,我建议在ES6中使用继承:

class Animal {
	constructor(_type) {
		this._type = _type;
	}
	speak() {
		console.log(this._type === 'dog' ? 'Grruuu' : 'Meowww');
	}
}

class Dog extends Animal {
	constructor() {
		super('dog');
	}
	set speak(value) {
		return super.speak;
		// or throw any exception message here...
        // throw new Error('This method cannot be overriden.');
	}
	get speak() {
		return (...args) => super.speak.call(this, ...args);
	}
}

class Cat extends Animal {
	constructor() {
		super('cat');
	}
	set speak(value) {
		return super.speak;
	}
	get speak() {
		return (...args) => super.speak.call(this, ...args);
	}
}

let dog = new Dog();
dog.speak();

let cat = new Cat();
cat.speak();

cat.speak = 'foo';

cat.speak(); // Meowww