From 4b1a9203c547c019fc5398082ae19a3f3d4c3efe Mon Sep 17 00:00:00 2001 From: Peter Bengtsson Date: Tue, 8 Dec 2020 14:41:15 -0500 Subject: initial commit --- .../reference/functions/arrow_functions/index.html | 394 ++++++++++++++ .../web/javascript/reference/functions/index.html | 596 +++++++++++++++++++++ 2 files changed, 990 insertions(+) create mode 100644 files/bg/web/javascript/reference/functions/arrow_functions/index.html create mode 100644 files/bg/web/javascript/reference/functions/index.html (limited to 'files/bg/web/javascript/reference/functions') diff --git a/files/bg/web/javascript/reference/functions/arrow_functions/index.html b/files/bg/web/javascript/reference/functions/arrow_functions/index.html new file mode 100644 index 0000000000..f2efe8ec10 --- /dev/null +++ b/files/bg/web/javascript/reference/functions/arrow_functions/index.html @@ -0,0 +1,394 @@ +--- +title: Arrow functions +slug: Web/JavaScript/Reference/Functions/Arrow_functions +tags: + - Средно напреднали + - Функции + - Функции със стрелка + - референция +translation_of: Web/JavaScript/Reference/Functions/Arrow_functions +--- +
{{jsSidebar("Functions")}}
+ +

Функционалният израз със стрелка има по-кратък синтаксис, отколкото стандартното дефиниране на функция и няма свой собствен this, arguments, super, или new.target. Тези функции не са подходящи за изполване като метод функции(methods) и не могат да бъдат използвани като конструктори.

+ +
{{EmbedInteractiveExample("pages/js/functions-arrow.html")}}
+ +

Синтаксис

+ +

Основен синтаксис

+ +
(param1, param2, …, paramN) => { statements }
+(param1, param2, …, paramN) => expression
+// равнозначно на: => { return expression; }
+
+// Скобите не са задължителни, когато има само един входен параметър:
+(singleParam) => { statements }
+singleParam => { statements }
+
+// Списъка с аргументи за функции без аргументи трябва да бъде написан, като се използват скоби.
+() => { statements }
+
+ +

Напреднал синтаксис

+ +
// Резултата може да бъде ограден в скоби за да бъде върнат под формата на обект(object literal expression):
+params => ({foo: bar})
+
+// Поддържат се Rest оператора и параметри по подразбиране
+(param1, param2, ...rest) => { statements }
+(param1 = defaultValue1, param2, …, paramN = defaultValueN) => {
+statements }
+
+// Деструктуриране на списъка с входни аргументи също се поддържа
+var f = ([a, b] = [1, 2], {x: c} = {x: a + b}) => a + b + c;
+f(); // 6
+
+ +

Описание

+ +

Вижте също "ES6 In Depth: Arrow functions" on hacks.mozilla.org.

+ +

Два фактора повлияха за въвеждането на функциите със стрелка: по-къси функции и липсата на ключовата дума this.

+ +

По-кракти функции

+ +
var elements = [
+  'Hydrogen',
+  'Helium',
+  'Lithium',
+  'Beryllium'
+];
+
+elements.map(function(element) {
+  return element.length;
+}); // извикването на описания код ще върне следния масив: [8, 6, 7, 9]
+
+// Горе описаната функция може да бъде написана и като функция със стрелка по следния начин
+elements.map((element) => {
+  return element.length;
+}); // [8, 6, 7, 9]
+
+// Когато има само един входен параметър можем да премахнем скобите:
+elements.map(element => {
+  return element.length;
+}); // [8, 6, 7, 9]
+
+// Когато единственото нещо в функцията е връщане на резултат, можем да премахнем `return`
+//  и също така да премахнем скобите
+elements.map(element => element.length); // [8, 6, 7, 9]
+
+// In this case, because we only need the length property, we can use destructing parameter:
+// Notice that the string `"length"` corrosponds to the property we want to get whereas the
+//  obviously non-special `lengthFooBArX` is just the name of a variable which can be changed
+//  to any valid variable name you want
+elements.map(({ "length": lengthFooBArX }) => lengthFooBArX); // [8, 6, 7, 9]
+
+// This destructing parameter assignment can be written as seen below. However, note that there
+//   is no specific `"length"` to select which property we want to get. Instead, the literal name
+//   itself of the variable `length` is used as the property we want to retrieve from the object.
+elements.map(({ length }) => length); // [8, 6, 7, 9]
+
+ +

Без отделна ключова дума this

+ +

Допреди функциите със стрелка, всяка нова функция дефинираше своя собствена стойност this  (въз основа на това как се нарича функцията, нов обект в случай на конструктор, недифинарна при извикване на функции в строг режим,основният обект ако функцията се извиква като "object method", etc.). Това се оказа по-малко от идеалното с обектно-ориентирания стил на програмиране.

+ +
function Person() {
+  // The Person() constructor defines `this` as an instance of itself.
+  this.age = 0;
+
+  setInterval(function growUp() {
+    // In non-strict mode, the growUp() function defines `this`
+    // as the global object (because it's where growUp() is executed.),
+    // which is different from the `this`
+    // defined by the Person() constructor.
+    this.age++;
+  }, 1000);
+}
+
+var p = new Person();
+ +

В ECMAScript 3/5, проблемът с  this беше поправим като присвоим стойността на  this към променлива , която може да бъде затворена.

+ +
function Person() {
+  var that = this;
+  that.age = 0;
+
+  setInterval(function growUp() {
+    // The callback refers to the `that` variable of which
+    // the value is the expected object.
+    that.age++;
+  }, 1000);
+}
+ +

Като алтернатива, може да бъде създадена свързана функция  така че  this стойността може да бъде предадена на свързаната целева функция (функцията growUp() в примера по-горе).

+ +

Функцията със стрелка няма свой собствен this; Стойността  this от използвания лексикален контекст и др. Функциите със стрелки следват нормалните правила на промелнива. Така че, докато търсим за  this,  който не присъства в текущият обхват на функцията, те взимат this от околният обхват. По този начин,в следния код,  this в рамките на функцията, която се предава на setInterval функцията, има същата стойност като на тази в околната лексикална функция:

+ +
function Person(){
+  this.age = 0;
+
+  setInterval(() => {
+    this.age++; // |this| properly refers to the Person object
+  }, 1000);
+}
+
+var p = new Person();
+ +

Връзка със строг режим

+ +

Като се има в предвид , че this идва от околния лексикален контекст, строгите правила за режима по отношение на this се игнорират.

+ +
var f = () => { 'use strict'; return this; };
+f() === window; // or the global object
+ +

Всички други правила за строг режим се прилагат нормално

+ +

Извикване чрез повикване или прилагане

+ +

Тъй като функциите със стрелка нямат свой собствен this, методите call() или apply() могат само да предават параметри. thisArg се игнорира.

+ +
var adder = {
+  base: 1,
+
+  add: function(a) {
+    var f = v => v + this.base;
+    return f(a);
+  },
+
+  addThruCall: function(a) {
+    var f = v => v + this.base;
+    var b = {
+      base: 2
+    };
+
+    return f.call(b, a);
+  }
+};
+
+console.log(adder.add(1));         // This would log to 2
+console.log(adder.addThruCall(1)); // This would log to 2 still
+ +

Без обвързване на arguments

+ +

Функциите със стрелка нямат свой собствен обект от аргументи .Следователно в този пример аргументите са просто препратка към аргументите на заобикалящото ги поле:

+ +
var arguments = [1, 2, 3];
+var arr = () => arguments[0];
+
+arr(); // 1
+
+function foo(n) {
+  var f = () => arguments[0] + n; // foo's implicit arguments binding. arguments[0] is n
+  return f();
+}
+
+foo(3); // 6
+ +

В повечето случаи, използването на rest parameters(остатъчни параметри) е добра алтернатива от използването на обект с  аргументи.

+ +
function foo(n) {
+  var f = (...args) => args[0] + n;
+  return f(10);
+}
+
+foo(1); // 11
+ +

Функции със стрелка използвани като методи

+ +

Както бе посочено по-горе, изразите на функциите със стрелките са най-подходящи за функциите, различни от метода. Нека видим какво се случва, когато се опитаме да ги използваме като методи:

+ +
'use strict';
+
+var obj = {
+  i: 10,
+  b: () => console.log(this.i, this),
+  c: function() {
+    console.log(this.i, this);
+  }
+}
+
+obj.b(); // prints undefined, Window {...} (or the global object)
+obj.c(); // prints 10, Object {...}
+ +

Функциите със стрелка нямат свой собствен this. Друг пример затова е : {{jsxref("Object.defineProperty()")}}:

+ +
'use strict';
+
+var obj = {
+  a: 10
+};
+
+Object.defineProperty(obj, 'b', {
+  get: () => {
+    console.log(this.a, typeof this.a, this); // undefined 'undefined' Window {...} (or the global object)
+    return this.a + 10; // represents global object 'Window', therefore 'this.a' returns 'undefined'
+  }
+});
+
+ +

Използване на оператора new

+ +

Функциите със стрелка не мога да бъдат използвани като конструктории ще генерират грешка , когато се изпозват с оператора new.

+ +
var Foo = () => {};
+var foo = new Foo(); // TypeError: Foo is not a constructor
+ +

Използване на свойството prototype

+ +

Функциите със стрелки нямат свойството prototype.

+ +
var Foo = () => {};
+console.log(Foo.prototype); // undefined
+
+ +

Използване на ключовата дума  yield

+ +

Ключовата дума yield не може да бъде използвана в тялото на функцията със стрелка ( освен когато е позволено в рамките на функциите, които са вложени в нея ). В резултат на това функциите със стрелки не могат да се използват като генератори.

+ +

Тялото на функция

+ +

Функциите със стрелка могат да имат или  "сбито тяло" или обичайното "блоково тяло".

+ +

В сбитото тяло е посочен само израз, който се превръща в неявна връщана стойност.  В блоково тяло трябва да използвате изрично return декларация за връщане.

+ +
var func = x => x * x;
+// concise body syntax, implied "return"
+
+var func = (x, y) => { return x + y; };
+// with block body, explicit "return" needed
+
+ +

Връщане на литерали на обекти

+ +

Имайте в предвид , че връщането на литерали на обекти, използвайки сбит синтаксис params => {object:literal} няма да работи според очакванията.

+ +
var func = () => { foo: 1 };
+// Calling func() returns undefined!
+
+var func = () => { foo: function() {} };
+// SyntaxError: function statement requires a name
+ +

Това е защото кодът вътре в скобите ({}) се анализита като оследователност  от изрази (или  fooсе третира като етикет, а не като ключ в буквален обект).

+ +

Запомнете, че трябва да поставяте буквалният обект в скоби , както е показано в примера по-долу.

+ +
var func = () => ({foo: 1});
+ +

Прекъсване на линията

+ +

Функцията със стрелка не може да съдържа прекъсната линия между нейните параметри и стрелка.

+ +
var func = (a, b, c)
+           => 1;
+// SyntaxError: expected expression, got '=>'
+ +

Все пак това може да бъде променено, чрез използване на скоби или поставяне на разделителната линия в аргументите, както е показано в примера по-долу, за да се гарантира, че кодът остава красив и пухкав.

+ +
var func = (
+  a,
+  b,
+  c
+) => (
+  1
+);
+// no SyntaxError thrown
+ + + +

Parsing order

+ +

Въпреки че, стрелката във функцията със стрелка не е оператор, функциите със стрелка имат специални правила, които взаимодействат по различен начин с  оператора за предимство  сравнено с нормалните функции.

+ +
let callback;
+
+callback = callback || function() {}; // ok
+
+callback = callback || () => {};
+// SyntaxError: invalid arrow-function arguments
+
+callback = callback || (() => {});    // ok
+
+ +

Още примери

+ +
// An empty arrow function returns undefined
+let empty = () => {};
+
+(() => 'foobar')();
+// Returns "foobar"
+// (this is an Immediately Invoked Function Expression
+// see 'IIFE' in glossary)
+
+var simple = a => a > 15 ? 15 : a;
+simple(16); // 15
+simple(10); // 10
+
+let max = (a, b) => a > b ? a : b;
+
+// Easy array filtering, mapping, ...
+
+var arr = [5, 6, 13, 0, 1, 18, 23];
+
+var sum = arr.reduce((a, b) => a + b);
+// 66
+
+var even = arr.filter(v => v % 2 == 0);
+// [6, 0, 18]
+
+var double = arr.map(v => v * 2);
+// [10, 12, 26, 0, 2, 36, 46]
+
+// More concise promise chains
+promise.then(a => {
+  // ...
+}).then(b => {
+  // ...
+});
+
+// Parameterless arrow functions that are visually easier to parse
+setTimeout( () => {
+  console.log('I happen sooner');
+  setTimeout( () => {
+    // deeper code
+    console.log('I happen later');
+  }, 1);
+}, 1);
+
+ +

Спецификации

+ + + + + + + + + + + + + + + + + + + +
СпецификацииСтатусКоментар
{{SpecName('ES2015', '#sec-arrow-function-definitions', 'Arrow Function Definitions')}}{{Spec2('ES2015')}}Initial definition.
{{SpecName('ESDraft', '#sec-arrow-function-definitions', 'Arrow Function Definitions')}}{{Spec2('ESDraft')}}
+ +

Съвместимост с браузера

+ +
+ + +

{{Compat("javascript.functions.arrow_functions")}}

+
+ +

Вижте още

+ + diff --git a/files/bg/web/javascript/reference/functions/index.html b/files/bg/web/javascript/reference/functions/index.html new file mode 100644 index 0000000000..adb0d13f05 --- /dev/null +++ b/files/bg/web/javascript/reference/functions/index.html @@ -0,0 +1,596 @@ +--- +title: Functions +slug: Web/JavaScript/Reference/Functions +tags: + - Constructor + - Function + - Functions + - JavaScript + - NeedsTranslation + - Parameter + - TopicStub + - parameters +translation_of: Web/JavaScript/Reference/Functions +--- +
{{jsSidebar("Functions")}}
+ +

Generally speaking, a function is a "subprogram" that can be called by code external (or internal in the case of recursion) to the function. Like the program itself, a function is composed of a sequence of statements called the function body. Values can be passed to a function, and the function will return a value.

+ +

In JavaScript, functions are first-class objects, because they can have properties and methods just like any other object. What distinguishes them from other objects is that functions can be called. In brief, they are Function objects.

+ +

For more examples and explanations, see also the JavaScript guide about functions.

+ +

Description

+ +

Every function in JavaScript is a Function object. See {{jsxref("Function")}} for information on properties and methods of Function objects.

+ +

To return a value other than the default, a function must have a return statement that specifies the value to return. A function without a return statement will return a default value. In the case of a constructor called with the new keyword, the default value is the value of its this parameter. For all other functions, the default return value is {{jsxref("undefined")}}.

+ +

The parameters of a function call are the function's arguments. Arguments are passed to functions by value. If the function changes the value of an argument, this change is not reflected globally or in the calling function. However, object references are values, too, and they are special: if the function changes the referred object's properties, that change is visible outside the function, as shown in the following example:

+ +
/* Declare the function 'myFunc' */
+function myFunc(theObject) {
+  theObject.brand = "Toyota";
+}
+
+/*
+ * Declare variable 'mycar';
+ * create and initialize a new Object;
+ * assign reference to it to 'mycar'
+ */
+var mycar = {
+  brand: "Honda",
+  model: "Accord",
+  year: 1998
+};
+
+/* Logs 'Honda' */
+console.log(mycar.brand);
+
+/* Pass object reference to the function */
+myFunc(mycar);
+
+/*
+ * Logs 'Toyota' as the value of the 'brand' property
+ * of the object, as changed to by the function.
+ */
+console.log(mycar.brand);
+
+ +

The this keyword does not refer to the currently executing function, so you must refer to Function objects by name, even within the function body.

+ +

Defining functions

+ +

There are several ways to define functions:

+ +

The function declaration (function statement)

+ +

There is a special syntax for declaring functions (see function statement for details):

+ +
function name([param[, param[, ... param]]]) {
+   statements
+}
+
+ +
+
name
+
The function name.
+
+ +
+
param
+
The name of an argument to be passed to the function.
+
+ +
+
statements
+
The statements comprising the body of the function.
+
+ +

The function expression (function expression)

+ +

A function expression is similar to and has the same syntax as a function declaration (see function expression for details). A function expression may be a part of a larger expression. One can define "named" function expressions (where the name of the expression might be used in the call stack for example) or "anonymous" function expressions. Function expressions are not hoisted onto the beginning of the scope, therefore they cannot be used before they appear in the code.

+ +
function [name]([param[, param[, ... param]]]) {
+   statements
+}
+
+ +
+
name
+
The function name. Can be omitted, in which case the function becomes known as an anonymous function.
+
+ +
+
param
+
The name of an argument to be passed to the function.
+
statements
+
The statements comprising the body of the function.
+
+ +

Here is an example of an anonymous function expression (the name is not used):

+ +
var myFunction = function() {
+    statements
+}
+ +

It is also possible to provide a name inside the definition in order to create a named function expression:

+ +
var myFunction = function namedFunction(){
+    statements
+}
+
+ +

One of the benefits of creating a named function expression is that in case we encountered an error, the stack trace will contain the name of the function, making it easier to find the origin of the error.

+ +

As we can see, both examples do not start with the function keyword. Statements involving functions which do not start with function are function expressions.

+ +

When functions are used only once, a common pattern is an IIFE (Immediately Invokable Function Expression).

+ +
(function() {
+    statements
+})();
+ +

IIFE are function expressions that are invoked as soon as the function is declared.

+ +

The generator function declaration (function* statement)

+ +

There is a special syntax for generator function declarations (see {{jsxref('Statements/function*', 'function* statement')}} for details):

+ +
function* name([param[, param[, ... param]]]) {
+   statements
+}
+
+ +
+
name
+
The function name.
+
+ +
+
param
+
The name of an argument to be passed to the function.
+
+ +
+
statements
+
The statements comprising the body of the function.
+
+ +

The generator function expression (function* expression)

+ +

A generator function expression is similar to and has the same syntax as a generator function declaration (see {{jsxref('Operators/function*', 'function* expression')}} for details):

+ +
function* [name]([param[, param[, ... param]]]) {
+   statements
+}
+
+ +
+
name
+
The function name. Can be omitted, in which case the function becomes known as an anonymous function.
+
+ +
+
param
+
The name of an argument to be passed to the function.
+
statements
+
The statements comprising the body of the function.
+
+ +

The arrow function expression (=>)

+ +

An arrow function expression has a shorter syntax and lexically binds its this value (see arrow functions for details):

+ +
([param[, param]]) => {
+   statements
+}
+
+param => expression
+
+ +
+
param
+
The name of an argument. Zero arguments need to be indicated with ().  For only one argument, the parentheses are not required. (like foo => 1)
+
statements or expression
+
Multiple statements need to be enclosed in brackets. A single expression requires no brackets. The expression is also the implicit return value of the function.
+
+ +

The Function constructor

+ +
+

Note: Using the Function constructor to create functions is not recommended since it needs the function body as a string which may prevent some JS engine optimizations and can also cause other problems.

+
+ +

As all other objects, {{jsxref("Function")}} objects can be created using the new operator:

+ +
new Function (arg1, arg2, ... argN, functionBody)
+
+ +
+
arg1, arg2, ... argN
+
Zero or more names to be used by the function as formal parameters. Each must be a proper JavaScript identifier.
+
+ +
+
functionBody
+
A string containing the JavaScript statements comprising the function body.
+
+ +

Invoking the Function constructor as a function (without using the new operator) has the same effect as invoking it as a constructor.

+ +

The GeneratorFunction constructor

+ +
+

Note: GeneratorFunction is not a global object, but could be obtained from generator function instance (see {{jsxref("GeneratorFunction")}} for more detail).

+
+ +
+

Note: Using the GeneratorFunction constructor to create functions is not recommended since it needs the function body as a string which may prevent some JS engine optimizations and can also cause other problems.

+
+ +

As all other objects, {{jsxref("GeneratorFunction")}} objects can be created using the new operator:

+ +
new GeneratorFunction (arg1, arg2, ... argN, functionBody)
+
+ +
+
arg1, arg2, ... argN
+
Zero or more names to be used by the function as formal argument names. Each must be a string that conforms to the rules for a valid JavaScript identifier or a list of such strings separated with a comma; for example "x", "theValue", or "a,b".
+
+ +
+
functionBody
+
A string containing the JavaScript statements comprising the function definition.
+
+ +

Invoking the Function constructor as a function (without using the new operator) has the same effect as invoking it as a constructor.

+ +

Function parameters

+ +

Default parameters

+ +

Default function parameters allow formal parameters to be initialized with default values if no value or undefined is passed. For more details, see default parameters.

+ +

Rest parameters

+ +

The rest parameter syntax allows representing an indefinite number of arguments as an array. For more details, see rest parameters.

+ +

The arguments object

+ +

You can refer to a function's arguments within the function by using the arguments object. See arguments.

+ + + +

Defining method functions

+ +

Getter and setter functions

+ +

You can define getters (accessor methods) and setters (mutator methods) on any standard built-in object or user-defined object that supports the addition of new properties. The syntax for defining getters and setters uses the object literal syntax.

+ +
+
get
+
+

Binds an object property to a function that will be called when that property is looked up.

+
+
set
+
Binds an object property to a function to be called when there is an attempt to set that property.
+
+ +

Method definition syntax

+ +

Starting with ECMAScript 2015, you are able to define own methods in a shorter syntax, similar to the getters and setters. See method definitions for more information.

+ +
var obj = {
+  foo() {},
+  bar() {}
+};
+ +

Constructor vs. declaration vs. expression

+ +

Compare the following:

+ +

A function defined with the Function constructor assigned to the variable multiply:

+ +
var multiply = new Function('x', 'y', 'return x * y');
+ +

A function declaration of a function named multiply:

+ +
function multiply(x, y) {
+   return x * y;
+} // there is no semicolon here
+
+ +

A function expression of an anonymous function assigned to the variable multiply:

+ +
var multiply = function(x, y) {
+   return x * y;
+};
+
+ +

A function expression of a function named func_name assigned to the variable multiply:

+ +
var multiply = function func_name(x, y) {
+   return x * y;
+};
+
+ +

Differences

+ +

All do approximately the same thing, with a few subtle differences:

+ +

There is a distinction between the function name and the variable the function is assigned to. The function name cannot be changed, while the variable the function is assigned to can be reassigned. The function name can be used only within the function's body. Attempting to use it outside the function's body results in an error (or undefined if the function name was previously declared via a var statement). For example:

+ +
var y = function x() {};
+alert(x); // throws an error
+
+ +

The function name also appears when the function is serialized via Function's toString method.

+ +

On the other hand, the variable the function is assigned to is limited only by its scope, which is guaranteed to include the scope in which the function is declared.

+ +

As the 4th example shows, the function name can be different from the variable the function is assigned to. They have no relation to each other. A function declaration also creates a variable with the same name as the function name. Thus, unlike those defined by function expressions, functions defined by function declarations can be accessed by their name in the scope they were defined in:

+ +

A function defined by 'new Function' does not have a function name. However, in the SpiderMonkey JavaScript engine, the serialized form of the function shows as if it has the name "anonymous". For example, alert(new Function()) outputs:

+ +
function anonymous() {
+}
+
+ +

Since the function actually does not have a name, anonymous is not a variable that can be accessed within the function. For example, the following would result in an error:

+ +
var foo = new Function("alert(anonymous);");
+foo();
+
+ +

Unlike functions defined by function expressions or by the Function constructor, a function defined by a function declaration can be used before the function declaration itself. For example:

+ +
foo(); // alerts FOO!
+function foo() {
+   alert('FOO!');
+}
+
+ +

A function defined by a function expression or by a function declaration inherits the current scope. That is, the function forms a closure. On the other hand, a function defined by a Function constructor does not inherit any scope other than the global scope (which all functions inherit).

+ +
/*
+ * Declare and initialize a variable 'p' (global)
+ * and a function 'myFunc' (to change the scope) inside which
+ * declare a varible with same name 'p' (current) and
+ * define three functions using three different ways:-
+ *     1. function declaration
+ *     2. function expression
+ *     3. function constructor
+ * each of which will log 'p'
+ */
+var p = 5;
+function myFunc() {
+    var p = 9;
+
+    function decl() {
+        console.log(p);
+    }
+    var expr = function() {
+        console.log(p);
+    };
+    var cons = new Function('\tconsole.log(p);');
+
+    decl();
+    expr();
+    cons();
+}
+myFunc();
+
+/*
+ * Logs:-
+ * 9  - for 'decl' by function declaration (current scope)
+ * 9  - for 'expr' by function expression (current scope)
+ * 5  - for 'cons' by Function constructor (global scope)
+ */
+
+ +

Functions defined by function expressions and function declarations are parsed only once, while those defined by the Function constructor are not. That is, the function body string passed to the Function constructor must be parsed each and every time the constructor is called. Although a function expression creates a closure every time, the function body is not reparsed, so function expressions are still faster than "new Function(...)". Therefore the Function constructor should generally be avoided whenever possible.

+ +

It should be noted, however, that function expressions and function declarations nested within the function generated by parsing a Function constructor 's string aren't parsed repeatedly. For example:

+ +
var foo = (new Function("var bar = \'FOO!\';\nreturn(function() {\n\talert(bar);\n});"))();
+foo(); // The segment "function() {\n\talert(bar);\n}" of the function body string is not re-parsed.
+ +

A function declaration is very easily (and often unintentionally) turned into a function expression. A function declaration ceases to be one when it either:

+ + + +
var x = 0;               // source element
+if (x === 0) {           // source element
+   x = 10;               // not a source element
+   function boo() {}     // not a source element
+}
+function foo() {         // source element
+   var y = 20;           // source element
+   function bar() {}     // source element
+   while (y === 10) {    // source element
+      function blah() {} // not a source element
+      y++;               // not a source element
+   }
+}
+
+ +

Examples

+ +
// function declaration
+function foo() {}
+
+// function expression
+(function bar() {})
+
+// function expression
+x = function hello() {}
+
+
+if (x) {
+   // function expression
+   function world() {}
+}
+
+
+// function declaration
+function a() {
+   // function declaration
+   function b() {}
+   if (0) {
+      // function expression
+      function c() {}
+   }
+}
+
+ +

Block-level functions

+ +

In strict mode, starting with ES2015, functions inside blocks are now scoped to that block. Prior to ES2015, block-level functions were forbidden in strict mode.

+ +
'use strict';
+
+function f() {
+  return 1;
+}
+
+{
+  function f() {
+    return 2;
+  }
+}
+
+f() === 1; // true
+
+// f() === 2 in non-strict mode
+
+ +

Block-level functions in non-strict code

+ +

In a word: Don't.

+ +

In non-strict code, function declarations inside blocks behave strangely. For example:

+ +
if (shouldDefineZero) {
+   function zero() {     // DANGER: compatibility risk
+      console.log("This is zero.");
+   }
+}
+
+ +

ES2015 says that if shouldDefineZero is false, then zero should never be defined, since the block never executes. However, it's a new part of the standard. Historically, this was left unspecified, and some browsers would define zero whether the block executed or not.

+ +

In strict mode, all browsers that support ES2015 handle this the same way: zero is defined only if shouldDefineZero is true, and only in the scope of the if-block.

+ +

A safer way to define functions conditionally is to assign a function expression to a variable:

+ +
var zero;
+if (shouldDefineZero) {
+   zero = function() {
+      console.log("This is zero.");
+   };
+}
+
+ +

Examples

+ +

Returning a formatted number

+ +

The following function returns a string containing the formatted representation of a number padded with leading zeros.

+ +
// This function returns a string padded with leading zeros
+function padZeros(num, totalLen) {
+   var numStr = num.toString();             // Initialize return value as string
+   var numZeros = totalLen - numStr.length; // Calculate no. of zeros
+   for (var i = 1; i <= numZeros; i++) {
+      numStr = "0" + numStr;
+   }
+   return numStr;
+}
+
+ +

The following statements call the padZeros function.

+ +
var result;
+result = padZeros(42,4); // returns "0042"
+result = padZeros(42,2); // returns "42"
+result = padZeros(5,4);  // returns "0005"
+
+ +

Determining whether a function exists

+ +

You can determine whether a function exists by using the typeof operator. In the following example, a test is performed to determine if the window object has a property called noFunc that is a function. If so, it is used; otherwise, some other action is taken.

+ +
 if ('function' === typeof window.noFunc) {
+   // use noFunc()
+ } else {
+   // do something else
+ }
+
+ +

Note that in the if test, a reference to noFunc is used—there are no brackets "()" after the function name so the actual function is not called.

+ +

Specifications

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('ES1')}}{{Spec2('ES1')}}Initial definition. Implemented in JavaScript 1.0
{{SpecName('ES5.1', '#sec-13', 'Function Definition')}}{{Spec2('ES5.1')}} 
{{SpecName('ES6', '#sec-function-definitions', 'Function definitions')}}{{Spec2('ES6')}}New: Arrow functions, Generator functions, default parameters, rest parameters.
{{SpecName('ESDraft', '#sec-function-definitions', 'Function definitions')}}{{Spec2('ESDraft')}} 
+ +

Browser compatibility

+ + + +

{{Compat("javascript.functions")}}

+ +

See also

+ + -- cgit v1.2.3-54-g00ecf