2

I noticed that this returned from bound function doesn't strictly equal primitive value passed when binding.

According to MDN when the original function is called [[BoundThis]] gets passed.

What is this returned from bound function? Is it [[BoundThis]]?

const fn = function() { return this }
const strBound = fn.bind('111')
const numBound = fn.bind(111)
const boolBound = fn.bind(true)

console.log(strBound()) // [String: '111']
console.log(strBound() == '111') // true
console.log(strBound() === '111') // false

console.log(numBound()) // [Number: 111]
console.log(numBound() == 111) // true
console.log(numBound() === 111) // false

console.log(boolBound()) // [Boolean: true]
console.log(boolBound() == true) // true
console.log(boolBound() === true) // false

3 Answers3

2

Your function is not in strict mode, which means it will always implicitly cast its received this value to an object (and uses the global object upon receiving null/undefined). Your code will work as expected with

function fn() {
    "use strict";
    return this;
}

Notice that one could reproduce the issue without bind.

Bergi
  • 630,263
  • 148
  • 957
  • 1,375
2

This behaviour, as always, has been defined by the ECMAScript specification. In this case it takes a while to actually follow the different specifications, but if you are interested in the details, here you go.

19.2.3.2 Function.prototype.bind ( thisArg , ...args)

[...]

  1. Let F be BoundFunctionCreate(Target, thisArg, args).

[...]

  1. Return F.

9.4.1.3 BoundFunctionCreate (targetFunction, boundThis, boundArgs)

[...]

  1. Set the [[Call]] internal method of obj as described in 9.4.1.1.

9.4.1.1 [[Call]] ( thisArgument, argumentsList)

[...]

  1. Return Call(target, boundThis, args).

7.3.12 Call(F, V, [argumentsList])

[...]

  1. Return F.[[Call]](V, argumentsList).

9.2.1 [[Call]] ( thisArgument, argumentsList)

[...]

  1. Perform OrdinaryCallBindThis(F, calleeContext, thisArgument).

9.2.1.2 OrdinaryCallBindThis ( F, calleeContext, thisArgument )

[...]

  1. If thisMode is strict, let thisValue be thisArgument.
  2. Else
    • if thisArgument is null or undefined, then
      Let thisValue be calleeRealm.[[globalThis]].
    • Else
      Let thisValue be ToObject(thisArgument).

7.1.13 ToObject ( argument )

[...]

Number: Return a new Number object whose [[NumberData]] internal slot is set to the value of argument. See 20.1 for a description of Number objects.

String: Return a new String object whose [[StringData]] internal slot is set to the value of argument. See 21.1 for a description of String objects.

  • A primitive string is not strictly equal to a string object with the same value.
  • A primitive number is not strictly equal to a number object with the same value.
str
  • 42,689
  • 17
  • 109
  • 127
1

Binding a function to a string primitive implicitly converts the string primitive into a String object.

When type coercion is in play, a string primitive and String object will match.

Without type coercion, they won't.

Ditto other kinds of primitives.

const prim = "x";
const obj = new String("x");

console.log(prim instanceof String);
console.log(obj instanceof String);
console.log(prim == obj);
console.log(prim === obj);
Quentin
  • 914,110
  • 126
  • 1,211
  • 1,335
  • The first sentence is objectively wrong. Binding the function doesn't convert anything. – Bergi Jan 13 '19 at 21:16