Functions API Flashcards

1
Q

Function() constructor

A

The Function() constructor creates Function objects. Calling the constructor directly can create functions dynamically, but suffers from security and similar (but far less significant) performance issues as eval(). However, unlike eval (which may have access to the local scope), the Function constructor creates functions which execute in the global scope only.

Syntax

new Function(functionBody)
new Function(arg1, functionBody)
new Function(arg1, arg2, functionBody)
new Function(arg1, arg2, /* …, */ argN, functionBody)

Function(functionBody)
Function(arg1, functionBody)
Function(arg1, arg2, functionBody)
Function(arg1, arg2, /* …, */ argN, functionBody)

Note: Function() can be called with or without new. Both create a new Function instance.

Parameters

  • arg1, …, argN Optional - Names to be used by the function as formal argument names. Each must be a string that corresponds to a valid JavaScript parameter (any of plain identifier, rest parameter, or destructured parameter, optionally with a default), or a list of such strings separated with commas.

As the parameters are parsed in the same way as function expressions, whitespace and comments are accepted. For example: "x", "theValue = 42", "[a, b] /* numbers */" — or "x, theValue = 42, [a, b] /* numbers */". ("x, theValue = 42", "[a, b]" is also correct, though very confusing to read.)

  • functionBody - A string containing the JavaScript statements comprising the function definition.

Examples:

// Example can be run directly in your JavaScript console

// Create a function that takes two arguments, and returns the sum of those arguments
const adder = new Function("a", "b", "return a + b");

// Call the function
adder(2, 6);
// 8
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
2
Q

Function.prototype.arguments

A

Deprecated: This feature is no longer recommended.

The arguments accessor property of Function instances returns the arguments passed to this function. For strict, arrow, async, and generator functions, accessing the arguments property throws a TypeError.

The value of arguments is an array-like object corresponding to the arguments passed to a function.

In the case of recursion, i.e. if function f appears several times on the call stack, the value of f.arguments represents the arguments corresponding to the most recent invocation of the function.

Examples:

function f(n) {
  g(n - 1);
}

function g(n) {
  console.log(`before: ${g.arguments[0]}`);
  if (n > 0) {
    f(n);
  }
  console.log(`after: ${g.arguments[0]}`);
}

f(2);

console.log(`returned: ${g.arguments}`);

// Logs:
// before: 1
// before: 0
// after: 0
// after: 1
// returned: null
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
3
Q

Function: length data property

A

The length data property of a Function instance indicates the number of parameters expected by the function. i.e. the number of formal parameters. This number excludes the rest parameter and only includes parameters before the first one with a default value. By contrast, arguments.length is local to a function and provides the number of arguments actually passed to the function.

The Function constructor is itself a Function object. Its length data property has a value of 1.

Value

A number.

Examples:

console.log(Function.length); // 1

console.log((() => {}).length); // 0
console.log(((a) => {}).length); // 1
console.log(((a, b) => {}).length); // 2 etc.

console.log(((...args) => {}).length);
// 0, rest parameter is not counted

console.log(((a, b = 1, c) => {}).length);
// 1, only parameters before the first one with
// a default value are counted
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
4
Q

Function: name data property

A

The name data property of a Function instance indicates the function’s name as specified when it was created, or it may be either anonymous or '' (an empty string) for functions created anonymously.

The name property is read-only and cannot be changed by the assignment operator.

Value
A string.

Examples:

// -- someModule.js --
export default function () {}

// -- main.js --
import someModule from "./someModule.js";

someModule.name; // "default"

new Function().name; // "anonymous"

const someFunction = function someFunctionName() {};
someFunction.name; // "someFunctionName"

(function () {}).name; // ""
(() => {}).name; // ""

const f = function () {};
const object = {
  someMethod: function () {},
};

console.log(f.name); // "f"
console.log(object.someMethod.name); // "someMethod"
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
5
Q

Function: prototype data property

A

The prototype data property of a Function instance is used when the function is used as a constructor with the new operator. It will become the new object’s prototype.

Value
An object.

Description

When a function is called with new, the constructor’s prototype property will become the resulting object’s prototype.

function Ctor() {}
const inst = new Ctor();
console.log(Object.getPrototypeOf(inst) === Ctor.prototype); // true

A function having a prototype property is not sufficient for it to be eligible as a constructor. Generator functions have a prototype property, but cannot be called with new:

async function* asyncGeneratorFunction() {}
function* generatorFunction() {}

Instead, generator functions’ prototype property is used when they are called without new. The prototype property will become the returned Generator object’s prototype.

In addition, some functions may have a prototype but throw unconditionally when called with new. For example, the Symbol() and BigInt() functions throw when called with new, because Symbol.prototype and BigInt.prototype are only intended to provide methods for the primitive values, but the wrapper objects should not be directly constructed.

The following functions do not have prototype, and are therefore ineligible as constructors, even if a prototype property is later manually assigned:

const method = { foo() {} }.foo;
const arrowFunction = () => {};
async function asyncFunction() {}

The following are valid constructors that have prototype:

class Class {}
function fn() {}

A bound function does not have a prototype property, but may be constructable. When it’s constructed, the target function is constructed instead, and if the target function is constructable, it would return a normal instance.

const boundFunction = function () {}.bind(null);

A function’s prototype property, by default, is a plain object with one property: constructor, which is a reference to the function itself. The constructor property is writable, non-enumerable, and configurable.

If the prototype of a function is reassigned with something other than an Object, when the function is called with new, the returned object’s prototype would be Object.prototype instead. (In other words, new ignores the prototype property and constructs a plain object.)

function Ctor() {}
Ctor.prototype = 3;
console.log(Object.getPrototypeOf(new Ctor()) === Object.prototype); // true
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
6
Q

Function.prototype[@@hasInstance]()

A

The [@@hasInstance]() method of Function instances specifies the default procedure for determining if a constructor function recognizes an object as one of the constructor’s instances. It is called by the instanceof operator.

The instanceof operator calls the @@hasInstance method of the right-hand side.

Syntax

func[Symbol.hasInstance](value)

Parameters

value - The object to test. Primitive values always return false.

Return value
true if func.prototype is in the prototype chain of value; otherwise, false. Always returns false if value is not an object or this is not a function. If this is a bound function, returns the result of a instanceof test on value and the underlying target function.

Exceptions

TypeError - Thrown if this is not a bound function and this.prototype is not an object.

Examples:

class Foo {}
const foo = new Foo();
console.log(foo instanceof Foo === Foo[Symbol.hasInstance](foo)); // true

You may want to use this method if you want to invoke the default instanceof behavior, but you don’t know if a constructor has a overridden [@@hasInstance]() method.

class Foo {
  static [Symbol.hasInstance](value) {
    // A custom implementation
    return false;
  }
}

const foo = new Foo();
console.log(foo instanceof Foo); // false
console.log(Function.prototype[Symbol.hasInstance].call(Foo, foo)); // true
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
7
Q

Function.prototype.apply()

A

The apply() method of Function instances calls this function with a given this value, and arguments provided as an array (or an array-like object).

Syntax

apply(thisArg)
apply(thisArg, argsArray)

Parameters

  • thisArg - The value of this provided for the call to func. If the function is not in strict mode, null and undefined will be replaced with the global object, and primitive values will be converted to objects.
  • argsArray Optional - An array-like object, specifying the arguments with which func should be called, or null or undefined if no arguments should be provided to the function.

Return value
The result of calling the function with the specified this value and arguments.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
8
Q

What limitations do the Function.prototype.apply() and the spread syntax have with respect to function arguments?

A

Using apply() (or the spread syntax) with an arbitrarily long arguments list, you run the risk of exceeding the JavaScript engine’s argument length limit.

The consequences of calling a function with too many arguments (that is, more than tens of thousands of arguments) is unspecified and varies across engines. (The JavaScriptCore engine has a hard-coded argument limit of 65536.) Most engines throw an exception; but there’s no normative specification preventing other behaviors, such as arbitrarily limiting the number of arguments actually passed to the applied function. To illustrate this latter case: if such an engine had a limit of four arguments (actual limits are of course significantly higher), it would be as if the arguments 5, 6, 2, 3 had been passed to apply in the examples above, rather than the full array.

If your value array might grow into the tens of thousands, use a hybrid strategy: apply your function to chunks of the array at a time:

function minOfArray(arr) {
  let min = Infinity;
  const QUANTUM = 32768;

  for (let i = 0; i < arr.length; i += QUANTUM) {
    const submin = Math.min.apply(
      null,
      arr.slice(i, Math.min(i + QUANTUM, arr.length)),
    );
    min = Math.min(submin, min);
  }

  return min;
}

const min = minOfArray([5, 6, 2, 3, 7]);
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
9
Q

Function.prototype.bind()

A

The bind() method of Function instances creates a new function that, when called, calls this function with its this keyword set to the provided value, and a given sequence of arguments preceding any provided when the new function is called.

Syntax

bind(thisArg)
bind(thisArg, arg1)
bind(thisArg, arg1, arg2)
bind(thisArg, arg1, arg2, /* …, */ argN)

Parameters

  • thisArg - The value to be passed as the this parameter to the target function func when the bound function is called. If the function is not in strict mode, null and undefined will be replaced with the global object, and primitive values will be converted to objects. The value is ignored if the bound function is constructed using the new operator.
  • arg1, …, argN Optional - Arguments to prepend to arguments provided to the bound function when invoking func.

Return value

A copy of the given function with the specified this value, and initial arguments (if provided).

Examples:

// Top-level 'this' is bound to 'globalThis' in scripts.
this.x = 9;
const module = {
  x: 81,
  getX() {
    return this.x;
  },
};

// The 'this' parameter of 'getX' is bound to 'module'.
console.log(module.getX()); // 81

const retrieveX = module.getX;
// The 'this' parameter of 'retrieveX' is bound to 'globalThis' in non-strict mode.
console.log(retrieveX()); // 9

// Create a new function 'boundGetX' with the 'this' parameter bound to 'module'.
const boundGetX = retrieveX.bind(module);
console.log(boundGetX()); // 81
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
10
Q

Given the following code:

"use strict"; // prevent `this` from being boxed into the wrapper object

function log(...args) {
  console.log(this, ...args);
}
const boundLog = log.bind("this value", 1, 2);
const boundLog2 = boundLog.bind("new this value", 3, 4);
boundLog2(5, 6); 

What will boundLog2(5, 6) print?

A

It will print:

"this value", 1, 2, 3, 4, 5, 6

Explanation:

The bind() function creates a new bound function. Calling the bound function generally results in the execution of the function it wraps, which is also called the target function. The bound function will store the parameters passed — which include the value of this and the first few arguments — as its internal state. You can generally see

const boundFn = fn.bind(thisArg, arg1, arg2)

as being equivalent to

const boundFn = (...restArgs) => fn.call(thisArg, arg1, arg2, ...restArgs)

for the effect when it’s called (but not when boundFn is constructed).

A bound function can be further bound by calling boundFn.bind(thisArg, /* more args */), which creates another bound function boundFn2. The newly bound thisArg value is ignored, because the target function of boundFn2, which is boundFn, already has a bound this. When boundFn2 is called, it would call boundFn, which in turn calls fn. The arguments that fn ultimately receives are, in order:

  1. the arguments bound by boundFn,
  2. arguments bound by boundFn2, and
  3. the arguments received by boundFn2.
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
11
Q

What happens when you call a bounded function with the new operator?

A

A bound function may also be constructed using the new operator if its target function is constructable. Doing so acts as though the target function had instead been constructed. The prepended arguments are provided to the target function as usual, while the provided this value is ignored (because construction prepares its own this, as seen by the parameters of Reflect.construct). If the bound function is directly constructed, new.target will be the target function instead. (That is, the bound function is transparent to new.target.)

class Base {
  constructor(...args) {
    console.log(new.target === Base);
    console.log(args);
  }
}

const BoundBase = Base.bind(null, 1, 2);

new BoundBase(3, 4); // true, [1, 2, 3, 4]

However, because a bound function does not have the prototype property, it cannot be used as a base class for extends.

class Derived extends class {}.bind(null) {}
// TypeError: Class extends value does not have valid prototype property undefined
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
12
Q

What happens when using a bound function as the right-hand side of instanceof operator?

A

When using a bound function as the right-hand side of instanceof, instanceof would reach for the target function (which is stored internally in the bound function) and read its prototype instead.

class Base {}
const BoundBase = Base.bind(null, 1, 2);
console.log(new Base() instanceof BoundBase); // true
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
13
Q

What properties does a bound function have?

A

The bound function has the following properties:

  • length - The length of the target function minus the number of arguments being bound (not counting the thisArg parameter), with 0 being the minimum value.
  • name
    The name of the target function plus a "bound " prefix.

The bound function also inherits the prototype chain of the target function. However, it doesn’t have other own properties of the target function (such as static properties if the target function is a class).

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
14
Q

Function.prototype.call()

A

The call() method of Function instances calls this function with a given this value and arguments provided individually.

Syntax

call(thisArg)
call(thisArg, arg1)
call(thisArg, arg1, arg2)
call(thisArg, arg1, arg2, /* …, */ argN)

Parameters

  • thisArg - The value to use as this when calling func. If the function is not in strict mode, null and undefined will be replaced with the global object, and primitive values will be converted to objects.
  • arg1, …, argN Optional - Arguments for the function.

Return value

The result of calling the function with the specified this value and arguments.

Note: This function is almost identical to apply(), except that the function arguments are passed to call() individually as a list, while for apply() they are combined in one object, typically an array — for example, func.call(this, "eat", "bananas") vs. func.apply(this, ["eat", "bananas"]).

Examples:

function greet() {
  console.log(this.animal, "typically sleep between", this.sleepDuration);
}

const obj = {
  animal: "cats",
  sleepDuration: "12 and 16 hours",
};

greet.call(obj); // cats typically sleep between 12 and 16 hours
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
15
Q

What happens if you use call() to invoke a function without specifying the first argument?

A

If the first thisArg parameter is omitted, it defaults to undefined. In non-strict mode, the this value is then substituted with globalThis (which is akin to the global object).

globalThis.globProp = "Wisen";

function display() {
  console.log(`globProp value is ${this.globProp}`);
}

display.call(); // Logs "globProp value is Wisen"

In strict mode, the value of this is not substituted, so it stays as undefined.

"use strict";

globalThis.globProp = "Wisen";

function display() {
  console.log(`globProp value is ${this.globProp}`);
}

display.call(); // throws TypeError: Cannot read the property of 'globProp' of undefined
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
16
Q

Function.prototype.toString()

A

The toString() method of Function instances returns a string representing the source code of this function.

The toString() method will throw a TypeError exception ("Function.prototype.toString called on incompatible object"), if its this value object is not a Function object.

Function.prototype.toString.call("foo"); // throws TypeError

If the toString() method is called on built-in function objects, a function created by Function.prototype.bind(), or other non-JavaScript functions, then toString() returns a native function string which looks like

function someName() { [native code] }

Syntax

toString()

Parameters
None.

Return value
A string representing the source code of the function.

Examples:

function test(fn) {
  console.log(fn.toString());
}

function f() {}
class A {
  a() {}
}
function* g() {}

test(f); // "function f() {}"
test(A); // "class A { a() {} }"
test(g); // "function* g() {}"
test((a) => a); // "(a) => a"
test({ a() {} }.a); // "a() {}"
test({ *a() {} }.a); // "*a() {}"
test({ [0]() {} }[0]); // "[0]() {}"
test(Object.getOwnPropertyDescriptor({ get a() {} }, "a").get); // "get a() {}"
test(Object.getOwnPropertyDescriptor({ set a(x) {} }, "a").set); // "set a(x) {}"
test(Function.prototype.toString); // "function toString() { [native code] }"
test(function f() {}.bind(0)); // "function () { [native code] }"
test(Function("a", "b")); // function anonymous(a\n) {\nb\n}