1. execution context(执行环境/执行上下文)
  2. ThisBinding(this 绑定)
  3. 函数调用的内部执行过程
    1. F.[[call]]
  4. 访问属性的内部执行过程
    1. 函数作为属性调用时,内部 this 指向
  5. 访问标识符(变量)时,内部的执行过程
    1. GetIdentifierReference(lex, name, strict)
    2. 函数作为标识符调用时,内部的 this 指向
  6. 使用 new 调用函数时,其内部的运行过程
    1. 运行过程
    2. F.[[constuct]]
    3. 构造函数内部 this 的指向
  7. Function.prototype.apply (thisArg, argArray)
    1. 用 apply 调用函数,函数内部 this 的指向
  8. Function.prototype.call (thisArg [ , arg1 [ , arg2, … ] ] )
  9. Function.prototype.bind (thisArg [, arg1 [, arg2, …]])
    1. 15.3.4.5.1 [[Call]]
    2. 15.3.4.5.2 [[Construct]]
    3. 15.3.4.5.3 [[HasInstance]] (V)
  10. 参考

this

Es5 关于 this 的定义如下:
ECMAScript Language Specification - ECMA-262 Edition 5.1

The this keyword evaluates to the value of the ThisBinding of the current execution context.
关键字"this"指向当前所在 execution context(执行环境)的 ThisBinding

execution context(执行环境/执行上下文)

execution context 的说明在 10.3
ECMAScript Language Specification - ECMA-262 Edition 5.1
ES5 可执行代码与执行环境

When control is transferred to ECMAScript executable code, control is entering an execution context. Active execution contexts logically form a stack. The top execution context on this logical stack is the running execution context. A new execution context is created whenever control is transferred from the executable code associated with the currently running execution context to executable code that is not associated with that execution context. The newly created execution context is pushed onto the stack and becomes the running execution context.

当控制器进入 ECMAScript executable code(可执行代码)时, 控制器会进入一个 execution context(执行环境/执行上下文).所有活动的 execution context 在逻辑上组成一个栈结构,栈顶的 execution context 叫 running execution context.当控制器从当前的 executable code(与 running execution context 相关的)转移到另一个 executable code(与 running execution context 无关的)时,会创建一个新的 execution context.然后将这个新创建的 execution context 推入栈中,使其成为新的 running execution context.

执行函数里的代码时, 会创建一个容器来保存函数所处环境(上下文)中的变量.这些装变量的容器又被储存在一个栈结构中.JS 引擎通过这些环境容器来查找对应的变量,如果没找到就到下一个容器里去找,直到全局环境容器为止.

当进入函数时,控制器会创建一个执行环境,然后推入环境栈

有如下函数:

1
2
3
4
function a() {
console.log("hello");
}
a();

在调用 a 函数之前,环境栈的结构为:

1
2
3
4
5
6
7
8
9
10
11
12
13
[
{
LexicalEnvironment: {
Environment Record: Global Object
outer Lexical Environment: null
},
VariableEnvironment: {
Environment Record: Global Object
outer Lexical Environment: null
},
Thisbinding: Global Object
}
]

当执行到 a 函数中的代码时,环境栈的结构变为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
[
{
LexicalEnvironment: {
Environment Record: Declarative Environment Record
outer Lexical Environment: Global Environment
},
VariableEnvironment: {
Environment Record: Declarative Environment Record
outer Lexical Environment: Global Environment
},
Thisbinding: Global Object
},
{
LexicalEnvironment: {
Environment Record: Global Object
outer Lexical Environment: null
},
VariableEnvironment: {
Environment Record: Global Object
outer Lexical Environment: null
},
Thisbinding: Global Object
}
]

Execution Context 有三个组件:

  • LexicalEnvironment Component // 静态(词法)环境组件,用于储存 let const 这类不会被提升的变量
  • VariableEnvironment Component // 变量环境组件,用于储存 var function 这类会被提升的变量
  • Thisbinding Component // this 绑定组件

新建 execution context 时,起初 LexicalEnvironment Component 和 VariableEnvironment Component 的值是相同的. 在执行(execution context 中的)代码时, VariableEnvironmentComponent 不会发生变化, 而 LexicalEnvironment Component 可能被改变.(例如执行 catch /with 里的代码时会创建新的 LexicalEnvironment)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
!function() {
try {
var foo = 1;
} catch(err) {
var bar = 2;
}
console.log(foo, bar) // 1 undefined
}()

!function () {
with ({}) {
var foo = 1;
}
console.log(foo)
}()

ThisBinding(this 绑定)

Thisbinding 决定了当前执行环境中,this 关键字的值.

而 Thisbinding 是什么则取决于如何调用函数.
进入函数时, 控制器将 Thisbinding 指向调用者提供的参数(thisArg).

以调用函数为例, thisArg 的传递过程如下:

1 Function Calls

ECMAScript Language Specification - ECMA-262 Edition 5.1
ES5/表达式 - HTML5 Chinese Interest Group Wiki

thisArg由执行MemberExpression的返回结果决定

函数的产生式为 CallExpression : MemberExpression Arguments
其中的MemberExpression是通常意义上的函数, Arguments是参数 ,该产生式会按照文档11.2.3的步骤执行
调用函数时,先获取MemberExpression的执行结果(以下称该结果为ref)
然后按照MemberExpression的返回结果设置thisValue
最后用thisValue作为参数调用函数的内部方法[[call]],最后按照文档10.4.3创建执行环境

整个过程为:
解析 MemberExpression --> <11.2.3> Function Calls --> <13.2.1> 调用F.[[call]] --> <10.4.3>Entering Function Code

函数调用的内部执行过程

ECMAScript Language Specification - ECMA-262 Edition 5.1
https://www.w3.org/html/ig/zh/wiki/ES5/表达式#.E5.87.BD.E6.95.B0.E8.B0.83.E7.94.A8

The production CallExpression : MemberExpression Arguments is evaluated as follows:  
1 Let ref be the result of evaluating MemberExpression.
2 Let func be GetValue(ref).  
3 Let argList be the result of evaluating Arguments, producing an internal list of argument values (see 11.2.4).  
4 If Type(func) is not Object, throw a TypeError exception.
5 If IsCallable(func) is false, throw a TypeError exception.
6 If Type(ref) is Reference, then
    a If IsPropertyReference(ref) is true, then
        i Let thisValue be GetBase(ref).
    b Else, the base of ref is an Environment Record
        i Let thisValue be the result of calling the ImplicitThisValue concrete method of GetBase(ref).
7 Else, Type(ref) is not Reference.
    a Let thisValue be undefined.
8 Return the result of calling the [[Call]] internal method on func, providing thisValue as the this value and providing the list argList as the argument values.
1 令 ref 为执行 MemberExpression 的结果
2 令 func 为调用 GetValue(ref)的结果
3 令 argList 为执行 Arguments 的结果
4 如果 func 不是 Object,抛出 TypeError
5 如果 func 没有内部属性[[call]],抛出 TypeError
6 如果 ref 是 Reference
    a 如果 ref 的基值是 Boolean String Number Object //作为属性调用(Es6 新增 Symbol)
        i 令 thisValue 为调用 GetBase(ref)的结果
    b 否则, ref 的基值是环境记录 //作为变量调用
        i 令 thisValue 为调用 GetBase(ref).ImplicitThisValue 的结果
7 否则,ref 不是 Reference
    a 令 thisValue 为 undefined // 进入函数时, thisVaule 为 undefined 会让 this 指向 window 全局对象
8 return func.[[call]](thisValue, argList)

部分过程的注释:

1 这里的 MemberExpression 指的是括号前的部分. 例如函数"foo.bar()",只得就是括号前 foo.bar 的执行结果(返回一个 Reference).
2 内部方法 GetValue(ref)会返回 ref 真正的值.例如: 如果 ref 是一个 reference, 则会调用 GetBase(ref)返回 ref 的 BaseValue(基值).
4 判断 func 是否是对象(函数也是对象)
5 判断 func 是否是函数(是否有内部方法[[call]])
6 如果 ref 是引用类型
    a 如果函数被作为对象的属性调用, 例如 foo.bar()
        i 将对象作为 this
    b 作为变量调用 例如 var foo = function() {}; foo()
        i 将 undefined 作为 this, ImplicitThisValue 通常返回 undefined,除非 provideThis 值为 true(在 with 语句)
7 如果 ref 不是引用类型, 例如 (function(){})()
    a 将 undefined 作为 this
8 调用函数对象的内部方法[[call]]

F.[[call]]

When the [[Call]] internal method for a Function object F is called with a this value and a list of arguments, the following steps are taken:  
1 Let funcCtx be the result of establishing a new execution context for function code using the value of F's [[FormalParameters]] internal property, the passed arguments List args, and the this value as described in 10.4.3.  
2 Let result be the result of evaluating the FunctionBody that is the value of F's [[Code]] internal property. If F does not have a [[Code]] internal property or if its value is an empty FunctionBody, then result is (normal, undefined, empty).  
3 Exit the execution context funcCtx, restoring the previous execution context.  
4 If result.type is throw then throw result.value.  
5 If result.type is return then return result.value.  
6 Otherwise result.type must be normal. Return undefined.
用 this 和 arguments 作为参数调用函数 F 的内部方法[[call]]时,执行如下步骤:
1 用形参列表,实参列表和 this 创建新的 execution context(将其压入 execution context stack),根据文档 10.4.3(Entering Function Code)的步骤建立执行环境  
2 运行函数内部代码((调用内部属性[[code]])),将结果赋值给 result.如果没有返回结果/没有属性[[code]],result = (normal, undefined, empty)  
3 退出步骤 1 创建的 execution context  
4 如果出错,抛出错误  
5 如果正常,且有返回值(return),返回运行结果  
6 如果没有返回值,返回 undefined

访问属性的内部执行过程

属性可以通过"."或"[]"访问,二者等价

1
2
MemberExpression . IdentifierName
CallExpression . IdentifierName
1
2
MemberExpression [ Expression ]
CallExpression [ Expression ]

内部执行过程 ECMAScript Language Specification - ECMA-262 Edition 5.1

The production MemberExpression : MemberExpression [ Expression ] is evaluated as follows:  
1 Let baseReference be the result of evaluating MemberExpression.  
2 Let baseValue be GetValue(baseReference).  
3 Let propertyNameReference be the result of evaluating Expression.  
4 Let propertyNameValue be GetValue(propertyNameReference).  
5 Call CheckObjectCoercible(baseValue).  
6 Let propertyNameString be ToString(propertyNameValue).  
7 If the syntactic production that is being evaluated is contained in strict mode code, let strict be true, else let strict be false.  
8 Return a value of type Reference whose base value is baseValue and whose referenced name is propertyNameString, and whose strict mode flag is strict.  
1 令 baseReference 为执行 MemberExpression 的结果  
2 令 baseValue 为 GetValue(baseReference)的结果 // 获取 baseValue 的真实值  
3 令 propertyNameReference 为执行 Expression 的结果  
4 令 propertyNameValue 为 GetValue(propertyNameReference)的结果  
5 执行 CheckObjectCoercible(baseValue) // 如果 baseValue 值为 null/undefined,抛出 TypeError  
6 令 propertyNameString 为执行 ToString(propertyNameValue)的结果 // 将属性名转为字符串  
7 返回一个 Reference, 其基值为 baseValue, 引用名为 propertyNameString,严格模式标记为 strict

函数作为属性调用时,内部 this 指向

作为属性调用的 ref 是一个 Reference, 基值为该属性所在的对象(以下记作对象 O)
当 ref 是 Reference 时,根据步骤 6 a,令 thisValue 值为该 Reference 的基值
运行函数内部代码时,函数内部的 this 指向对象 O

1
2
3
4
5
6
var obj = {
fun: function() {
console.log(this);
},
};
obj.fun(); // {fun: ƒ}

访问标识符(变量)时,内部的执行过程

ECMAScript Language Specification - ECMA-262 Edition 5.1

Identifier resolution is the process of determining the binding of an Identifier using the LexicalEnvironment of the running execution context. During execution of ECMAScript code, the syntactic production PrimaryExpression : Identifier is evaluated using the following algorithm:  

1 Let env be the running execution context’s LexicalEnvironment.  
2 If the syntactic production that is being evaluated is contained in a strict mode code, then let strict be true, else let strict be false.  
3 Return the result of calling GetIdentifierReference function passing env, Identifier, and strict as arguments.

The result of evaluating an identifier is always a value of type Reference with its referenced name component equal to the Identifier String.
1 令 env 为 running execution context(执行环境)的 LexicalEnvironment 组件  
2 如果为严格模式,令 strict 为 true.否则令 strict 为 false  
3 调用 GetIdentifierReference(env, Identifier, strict),返回结果

返回结果永远是一个 Reference,其基值为 undefined/Environment Record,referenced name 为标识符字符(变量名)

GetIdentifierReference(lex, name, strict)

The abstract operation GetIdentifierReference is called with a Lexical Environment lex, an identifier String name, and a Boolean flag strict. The value of lex may be null. When called, the following steps are performed:

1 If lex is the value null, then
    a Return a value of type Reference whose base value is undefined, whose referenced name is name, and whose strict mode flag is strict.
2 Let envRec be lex’s environment record.  
3 Let exists be the result of calling the HasBinding(N) concrete method of envRec passing name as the argument N.  
4 If exists is true, then  
    a Return a value of type Reference whose base value is envRec, whose referenced name is name, and whose strict mode flag is strict.  
5 Else  
    a Let outer be the value of lex’s outer environment reference.  
    b Return the result of calling GetIdentifierReference passing outer, name, and strict as arguments.

1 如果 lex 为 null
    a 返回一个Reference,其基值为undefined,引用名为name, 严格模式符号为strict // 递归基,全局对象的outer environment reference为null
2 令 env 为 lex 的 environment record  
3 让 exists 为调用 envRec.HasBinding(name)的结果  
4 如果 exists 为 true  
    a 返回一个 Reference,其基值为 envRec, 引用名为 name, 严格模式符号为 strict  
5  否则  
    a 令 outer 为 lex 的 outer environment reference  
    b 返回 GetIdentifierReference(outer,name,strict)

函数作为标识符调用时,内部的 this 指向

作为变量调用的 ref 是一个 Reference, 基值为 undefined/Environment Record
当 ref 是 Reference 且基值为 undefined 时,根据步骤 2,抛出 ReferenceError(GetValue(V) -> IsUnresolvableReference(V))
当 ref 是 Reference 且基值为 Environment Record 时,根据步骤 6 b, thisValue 值为 undefined/Object Environment Records(with 语句)
运行函数内部代码时,函数内部的 this 指向全局对象

1
2
3
4
function fun() {
console.log(this);
}
fun(); // Window

使用 new 调用函数时,其内部的运行过程

运行过程

ECMAScript Language Specification - ECMA-262 Edition 5.1

The production NewExpression : new NewExpression is evaluated as follows:  
1 Let ref be the result of evaluating NewExpression.  
2 Let constructor be GetValue(ref).  
3 If Type(constructor) is not Object, throw a TypeError exception.  
4 If constructor does not implement the [[Construct]] internal method, throw a TypeError exception.  
5 Return the result of calling the [[Construct]] internal method on constructor, providing no arguments (that is, an empty list of arguments).

The production MemberExpression : new MemberExpression Arguments is evaluated as follows:  
1 Let ref be the result of evaluating MemberExpression.  
2 Let constructor be GetValue(ref).  
3 Let argList be the result of evaluating Arguments, producing an internal list of argument values (11.2.4).  
4 If Type(constructor) is not Object, throw a TypeError exception.  
5 If constructor does not implement the [[Construct]] internal method, throw a TypeError exception.  
6 Return the result of calling the [[Construct]] internal method on constructor, providing the list argList as the argument values.

产生式 NewExpression : new NewExpression 按照如下步骤执行 // 不加括号  
1 令 ref 为执行 NewExpression 的结果  
2 令 constructor 为执行 GetValue(ref)的结果 // constructor 就是函数对象  
3 如果 constructor 不是 Object,抛出 TypeError  
4 如果 constructor 没有内部方法[[constuct]],抛出 TypeError  
5 调用 constructor 的内部方法[[constuct]](),返回结果

产生式 NewExpression : new NewExpression Arguments 按照如下步骤执行 // 加括号  
1 令 ref 为执行 NewExpression 的结果  
2 令 constructor 为执行 GetValue(ref)的结果 // constructor 就是函数对象  
3 令 argList 为制定 Arguments 的结果 // argList 就是调用时的实参  
4 如果 constructor 不是 Object,抛出 TypeError  
5 如果 constructor 没有内部方法[[constuct]],抛出 TypeError  
6 调用 constructor 的内部方法[[constuct]](argList),返回结果

new 的使用方式有两种,加括号/不加括号
根据不加括号步骤 5, 不加括号当作无参数来处理,仍可正常执行

1
2
3
4
function per(age= 1){this.age = age}

new per // per {age: 1}
new per(2) // per {age: 2}

F.[[constuct]]

调用构造函数本质上就是调用函数对象的内部方法[[constuct]],其内部运行过程如下
ECMAScript Language Specification - ECMA-262 Edition 5.1

When the [[Construct]] internal method for a Function object F is called with a possibly empty list of arguments, the following steps are taken:  
1 Let obj be a newly created native ECMAScript object.  
2 Set all the internal methods of obj as specified in 8.12.  
3 Set the [[Class]] internal property of obj to "Object".  
4 Set the [[Extensible]] internal property of obj to true.  
5 Let proto be the value of calling the [[Get]] internal property of F with argument "prototype".  
6 If Type(proto) is Object, set the [[Prototype]] internal property of obj to proto.  
7 If Type(proto) is not Object, set the [[Prototype]] internal property of obj to the standard built-in Object prototype object as described in 15.2.4.  
8 Let result be the result of calling the [[Call]] internal property of F, providing obj as the this value and providing the argument list passed into [[Construct]] as args.  
9 If Type(result) is Object then return result.  
10 Return obj.
当使用参数 arguments(可能为空)调用函数 F 的内部方法 [[constuct]],执行如下步骤  
1 令 obj 为新创建的原生 ECMAScript Object  
2 依步骤 8.12 设置 obj 的内部方法  
3 设置 obj.[[Class]]为"Object"  
4 设置 obj.[[Extensible]为 true  
5 令 proto 为调用 F.[[Get]]('prototype')的结果  
6 如果 proto 是 Object,设置 obj.[[Prototype]]为 proto  
7 如果 proto 不是 Object,设置 obj.[[Prototype]]为 standard built-in Object prototype object(就是 Object.prototype)(15.2.4)  
8 调用 F.[[call]](obj, arguments),将结果赋值给 result  
9 如果 result 是 Object,返回 result // 调用构造函数,如果 return 的是对象,则使 return 的对象  
10 否者, 返回 obj // 如果不是,则使用 this 指向的那个对象

构造函数内部 this 的指向

步骤 1 中,新创建的对象 obj 会一直作为参数,向下传递给 thisValue(F.[[constuct]] --> F.[[call]] --> Entering Function Code)
因此,在构造函数中 this 指向一个新创建的对象
如果构造函数没有返回对象类型的值,则返回这个新创建的 obj

没有 return,返回 this 指向的新建对象

1
2
3
4
function per(age = 1) {
this.age = age;
}
new per(10); // per {age: 10}

return 值为对象时,返回对象

1
2
3
4
5
function per(age = 1) {
this.age = age;
return {};
}
new per(10); // {}

return 值不是对象,返回 this 指向的新建对象

1
2
3
4
5
function per(age = 1) {
this.age = age;
return 1;
}
new per(10); // per {age: 10}

Function.prototype.apply (thisArg, argArray)

ECMAScript Language Specification - ECMA-262 Edition 5.1

When the apply method is called on an object func with arguments thisArg and argArray, the following steps are taken:  
1 If IsCallable(func) is false, then throw a TypeError exception.  
2 If argArray is null or undefined, then
    a Return the result of calling the [[Cal]] internal method of func, providing thisArg as the this value and an empty list of arguments.
3 If Type(argArray) is not Object, then throw a TypeError exception.  
4 Let len be the result of calling the [[Get]] internal method of argArray with argument "length".  
5 Let n be ToUint32(len).  
6 Let argList be an empty List.  
7 Let index be 0.  
8 Repeat while index < n  
    a Let indexName be ToString(index).  
    b Let nextArg be the result of calling the [[Get]] internal method of argArray with indexName as the argument.  
    c Append nextArg as the last element of argList.  
    d Set index to index + 1.  
9 Return the result of calling the [[Call]] internal method of func, providing thisArg as the this value and argList as the list of arguments.  
The length property of the apply method is 2.

NOTE The thisArg value is passed without modification as the this value. This is a change from Edition 3, where a undefined or null thisArg is replaced with the global object and ToObject is applied to all other values and that result is passed as the this value.
当使用 thisArg 和 argArray 作为参数,调用 func 的 apply 方法时,执行下列步骤  
1 如果 IsCallable(func)返回 false, 抛出 TypeError  
2 如果 argArray 为 null/undfined,则
    a 以thisArg和空列表为参数,执行func的内部方法[[call]],返回结果

3 如果 argArray 不是 Object, 抛出 TypeError  
4 以"length"为参数,执行 argArray 的内部方法[[Get]],令 len 为结果  
5 令 n 为执行 ToUint32(len)的结果  
6 令 argList 为空 List  
7 令 index 为 0  
8 当 index < n 时  
    a 让 indexName 为 ToString(index)  
    b 以 indexName 为参数,调用 argArray 内部方法[[Get]],让 nextArg 为结果  
    c 添加 nextArg 到 argList  
    d index += 1  
9 以 thisArg(作为 this)和 argList(作为 list of arguments)为参数,调用 func 的内部方法[[call]],返回结果

用 apply 调用函数,函数内部 this 的指向

apply 方法直接使用第一个参数(以下记作: 参数 A)作为 this,调用内部方法[[call]]
运行函数内部代码时,函数内部的 this 指向参数 A

1
2
3
4
function per(){
console.log(this)
}
per.apply({a:1}) // {a: 1}

Function.prototype.call (thisArg [ , arg1 [ , arg2, … ] ] )

call 和 apply 类似,区别为 apply 接受一个参数列表,call 接受多个参数作为调用函数时传入的参数
ECMAScript Language Specification - ECMA-262 Edition 5.1

Function.prototype.bind (thisArg [, arg1 [, arg2, …]])

ECMAScript Language Specification - ECMA-262 Edition 5.1

The bind method takes one or more arguments, thisArg and (optionally) arg1, arg2, etc, and returns a new function object by performing the following steps:  
1 Let Target be the this value.  
2 If IsCallable(Target) is false, throw a TypeError exception.  
3 Let A be a new (possibly empty) internal list of all of the argument values provided after thisArg (arg1, arg2 etc), in order.  
4 Let F be a new native ECMAScript object .  
5 Set all the internal methods, except for [[Get]], of F as specified in 8.12.  
6 Set the [[Get]] internal property of F as specified in 15.3.5.4.  
7 Set the [[TargetFunction]] internal property of F to Target.  
8 Set the [[BoundThis]] internal property of F to the value of thisArg.  
9 Set the [[BoundArgs]] internal property of F to A.  
10 Set the [[Class]] internal property of F to "Function".  
11 Set the [[Prototype]] internal property of F to the standard built-in Function prototype object as specified in 15.3.3.1.  
12 Set the [[Call]] internal property of F as described in 15.3.4.5.1.  
13 Set the [[Construct]] internal property of F as described in 15.3.4.5.2.  
14 Set the [[HasInstance]] internal property of F as described in 15.3.4.5.3.  
15 If the [[Class]] internal property of Target is "Function", then
    a Let L be the length property of Target minus the length of A.
    b Set the length own property of F to either 0 or L, whichever is larger.
16 Else set the length own property of F to 0.  
17 Set the attributes of the length own property of F to the values specified in 15.3.5.1.  
18 Set the [[Extensible]] internal property of F to true.  
19 Let thrower be the [[ThrowTypeError]] function Object (13.2.3).  
20 Call the [[DefineOwnProperty]] internal method of F with arguments "caller", PropertyDescriptor {[[Get]]: thrower, [[Set]]: thrower, [[Enumerable]]: false, [[Configurable]]: false}, and false.  
21 Call the [[DefineOwnProperty]] internal method of F with arguments "arguments", PropertyDescriptor {[[Get]]: thrower, [[Set]]: thrower, [[Enumerable]]: false, [[Configurable]]: false}, and false.  
22 Return F.  
The length property of the bind method is 1.  
NOTE Function objects created using Function.prototype.bind do not have a prototype property or the [[Code]], [[FormalParameters]], and [[Scope]] internal properties.
bind 方法接受 thisArg 和 arg1,arg2...(可选)作为参数.按照以下步骤执行,返回一个新的函数  
1 让 Target 为 this value  
2 如果 IsCallable(Target)为 false, 抛出 TypeError 错误  
3 令 A 为新的内部列表(可能为空), 该列表包含所有 thisArg 之后的参数(arg1,arg2...)  
4 令 F 为一个新的原生 ECMAScript 对象(native ECMAScript object)  
5 依照 8.12,设置 F 的所有的内部方法([[Get]]除外)  
6 依照 15.3.5.4,设置 F 的内部方法[[Get]]  
7 设置 F 的内部属性 [[TargetFunction]] 为 Target  
8 设置 F 的内部属性[[BoundThis]]为 thisArg  
9 设置 F 的内部属性[[BoundArgs]]为 A  
10 设置 F 的内部属性[[Class]]为"Function"  
11 依照 15.3.3.1,设置 F 的内部属性[[Prototype]]为标准的内建函数属性对象(standard built-in Function prototype object )  
12 依照 15.3.4.5.1, 设置 F 的内部属性[[Call]]  
13 依照 15.3.4.5.2, 设置 F 的内部属性[[Construct]]  
14 依照 15.3.4.5.3, 设置 F 的内部属性[[HasInstance]]  
15 如果 Target 的内部属性[[Class]]是"Function",则
    a 令L为 Taget的length属性减A的长度
    b 设置F的length属性为max(0, L)
16 否则, 设置 F 的 length 属性为 0  
17 Set the attributes of the length own property of F to the values specified in 15.3.5.1.  
18 设置 F 的内部属性[[Extensible]]为 true  
19 令 thrower 为[[ThrowTypeError]]函数对象(13.2.3)  
20 以"caller",属性描述(PropertyDescriptor){[[Get]]: thrower, [[Set]]: thrower, [[Enumerable]]: false, [[Configurable]]: false}, false 作为参数,调用 F 的内部方法[[DefineOwnProperty]]  
21 以"arguments",属性描述(PropertyDescriptor){[[Get]]: thrower, [[Set]]: thrower, [[Enumerable]]: false, [[Configurable]]: false}, false 作为参数,调用 F 的内部方法[[DefineOwnProperty]]  
22 返回 F  
bind 方法的 length 属性值为 1  
注意 使用 Function.prototype.bind 创建的函数没有属性 prototype 或内部方法[[Code]] [[FormalParameters]]和 [[Scope]]

15.3.4.5.1 [[Call]]

[ECMAScript Language Specification - ECMA-262 Edition 5.1](http://ecma-international.org/ecma-262/5.1/#sec-15.3.4.5.1)

When the [[Call]] internal method of a function object, F, which was created using the bind function is called with a this value and a list of arguments ExtraArgs, the following steps are taken:  
1 Let boundArgs be the value of F’s [[BoundArgs]] internal property.  
2 Let boundThis be the value of F’s [[BoundThis]] internal property.  
3 Let target be the value of F’s [[TargetFunction]] internal property.  
4 Let args be a new list containing the same values as the list boundArgs in the same order followed by the same values as the list ExtraArgs in the same order.  
5 Return the result of calling the [[Call]] internal method of target providing boundThis as the this value and providing args as the arguments.
当用 this value 和参数列表 ExtraArgs(a list of arguments ExtraArgs)作为参数,调用 bind 创建的函数对象 F 的内部方法[[call]]时,执行如下步骤  
1 让 boundArgs 为 F 的内部属性[[BoundArgs]]  
2 让 boundThis 为 F 的内部属性[[BoundThis]]  
3 让 target 为 F 的内部属性[[TargetFunction]]  
4 让 args 为一个新列表,该列表包含和 boundArgs 相同的值,紧接着包含和 ExtraArgs 相同的值(译者注: 相当于 args = [...boundArgs, ...ExtraArgs])  
5 以 boundThis(作为 this value)和 args(作为 arguments)作为参数,调用 target 的内部方法[[Call]],返回结果

15.3.4.5.2 [[Construct]]

[ECMAScript Language Specification - ECMA-262 Edition 5.1](http://ecma-international.org/ecma-262/5.1/#sec-15.3.4.5.2)

When the [[Construct]] internal method of a function object, F that was created using the bind function is called with a list of arguments ExtraArgs, the following steps are taken:  
1 Let target be the value of F’s [[TargetFunction]] internal property.  
2 If target has no [[Construct]] internal method, a TypeError exception is thrown.  
3 Let boundArgs be the value of F’s [[BoundArgs]] internal property.  
4 Let args be a new list containing the same values as the list boundArgs in the same order followed by the same values as the list ExtraArgs in the same order.  
5 Return the result of calling the [[Construct]] internal method of target providing args as the arguments.
当用 ExtraArgs(a list of arguments ExtraArgs)作为参数,调用 bind 创建的函数对象 F 的内部方法[[Construct]]时,执行如下步骤  
1 令 target 为 F 的内部属性[[TargetFunction]]  
2 如果 target 没有内部方法[[Construct]],抛出 TypeError  
3 令 boundArgs 为 F 的内部属性[[BoundArgs]]  
4 令 boundArgs 为一个新列表,该列表包含和 boundArgs 相同的值,紧接着包含和 ExtraArgs 相同的值(译者注: 相当于 args = [...boundArgs, ...ExtraArgs])  
5 以 args(作为 arguments)作为参数,调用 target 的内部方法[[Call]],返回结果

15.3.4.5.3 [[HasInstance]] (V)

[ECMAScript Language Specification - ECMA-262 Edition 5.1](http://ecma-international.org/ecma-262/5.1/#sec-15.3.4.5.3)

When the [[HasInstance]] internal method of a function object F, that was created using the bind function is called with argument V, the following steps are taken:  
1 Let target be the value of F’s [[TargetFunction]] internal property.  
2 If target has no [[HasInstance]] internal method, a TypeError exception is thrown.  
3 Return the result of calling the [[HasInstance]] internal method of target providing V as the argument.
当用 V 作为参数,调用 bind 创建的函数对象 F 的内部方法[[HasInstance]]时,执行如下步骤  
1 令 target 为 F 的内部属性[[TargetFunction]]  
2 如果 target 没有内部属性[[HasInstance]],抛出 TypeError  
3 用 V 作为参数,调用 target 的内部属性[[HasInstance]], 返回结果

参考

JavaScript 深入之从 ECMAScript 规范解读 this
ecmascript 6 - The effect of parenthesis with this binding in javascript - Stack Overflow
The ECMAScript “Executable Code and Execution Contexts” chapter explained
ECMAScript Language Specification - ECMA-262 Edition 5.1
JavaScript RunTime Model - Plectica
[译]理解 Javascript 关键字 this