深远之从,从ECMAScript标准解读this

JavaScript 深远之从 ECMAScript 规范解读 this

2017/05/17 · JavaScript
· this

原著出处: 冴羽   

事先都以依附函数的运用状态来明白this,分为各类处境:

原版的书文出处

JavaScript深刻之从ECMAScript标准解读this
ECMA-262-3 in detail. Chapter 3.
This
ECMAScript5.1中文版
ECMAScript5.1英文版

世家好,作者是IT修真院柏林(Berlin)分院第06期学员,一枚正直善良的web程序员。

前言

在《JavaScript深切之施行上下文栈》中讲到,当JavaScript代码实践1段可进行代码(executable
code)时,会成立对应的实施上下文(execution context)。

对此每种施行上下文,都有多个第三性质

  • 变量对象(Variable object,VO)
  • 效果域链(Scope chain)
  • this

前几天首要讲讲this,可是不好讲。

……

因为我们要从ECMASciript伍规范初始讲起。

先奉上ECMAScript 5.一业各地方:

英文版:

中文版:

让我们开始通晓标准吧!

  • 1、作为目的方法调用
  • 二、作为一般函数调用
  • 叁、构造器调用
  • 4、Function.prototype.call或Function.prototype.apply调用
    可是前几天看到了一篇作品,是追根溯源的从 ECMASciript 规范教学 this
    的针对,读完感到得到十分大,赶紧记录下来。

Types


先是是第 八 章 Types:

Types are further subclassified into ECMAScript language types and
specification types.

An ECMAScript language type corresponds to values that are directly
manipulated by an ECMAScript programmer using the ECMAScript language.
The ECMAScript language types are Undefined, Null, Boolean, String,
Number, and Object.

A specification type corresponds to meta-values that are used within
algorithms to describe the semantics of ECMAScript language constructs
and ECMAScript language types. The specification types are Reference,
List, Completion, Property Descriptor, Property Identifier, Lexical
Environment, and Environment Record.

我们大约的翻译一下:

ECMAScript 的品种分为语言类型和正规类型。

ECMAScript 语言类型是开垦者间接动用 ECMAScript
可以操作的。其实正是大家常说的Undefined, Null, Boolean, String, Number,
和 Object。

而业内类型也正是 meta-values,是用来用算法描述 ECMAScript 语言结构和ECMAScript 语言类型的。标准类型包蕴:Reference, List, Completion,
Property Descriptor, Property Identifier, Lexical Environment, 和
Environment Record。

没懂?无妨,我们假若明白在 ECMAScript
规范中还有1种只设有俞露规中的类型,它们的作用是用来描述语言底层行为逻辑

明天给大家享用一下,修真院官方网址JS任务中也许会接纳到的知识点:

Types

率先是第7章Types:

Types are further subclassified into ECMAScript language types and
specification types.

An ECMAScript language type corresponds to values that are directly
manipulated by an ECMAScript programmer using the ECMAScript language.
The ECMAScript language types are Undefined, Null, Boolean, String,
Number, and Object.

A specification type corresponds to meta-values that are used within
algorithms to describe the semantics of ECMAScript language constructs
and ECMAScript language types. The specification types are Reference,
List, Completion, Property Descriptor, Property Identifier, Lexical
Environment, and Environment Record.

咱俩大致的翻译一下:

ECMAScript的品种分为语言类型和职业类型。

ECMAScript语言类型是开辟者直接利用ECMAScript能够操作的。其实就是我们常说的Undefined,
Null, Boolean, String, Number, 和 Object。

而正规类型也正是meta-values,是用来用算法描述ECMAScript语言结议和ECMAScript语言类型的。规范类型包罗:Reference,
List, Completion, Property Descriptor, Property Identifier, Lexical
Environment, 和 Environment Record。

没懂?不要紧,大家重要看中间的Reference类型。

问询标准

英文版:http://es5.github.io/\#x15.1
中文版:http://yanhaijing.com/es5/\#115

Reference


那怎么又是 Reference ?

让我们看 8.7 章 The Reference Specification Type

The Reference type is used to explain the behaviour of such operators
as delete, typeof, and the assignment operators.

故此 Reference 类型正是用来分解诸如 delete、typeof
以及赋值等操作行为的。

抄袭尤雨溪大大的话,正是:

此处的 Reference 是二个 Specification Type,也便是“只设有于专门的工作里的架空类型”。它们是为着更加好地描述语言的最底层行为逻辑才存在的,但并不设有于实际的
js 代码中

再看接下去的那段具体介绍 Reference 的内容:

A Reference is a resolved name binding.

A Reference consists of three components, the base value, the
referenced name and the Boolean valued strict reference flag.

The base value is either undefined, an Object, a Boolean, a String, a
Number, or an environment record (10.2.1).

A base value of undefined indicates that the reference could not be
resolved to a binding. The referenced name is a String.

那段讲述了 Reference 的组成,由五个组成都部队分,分别是:

  1. base value: 正是性质所在的靶子恐怕就是EnvironmentRecord,它的值只也许是 undefined, an Object, a Boolean, a
    String。

  2. referenced name: 正是性质的名目。

  3. strict reference: 是不是处在严厉形式。

举个例证:

var foo = 1;

// 对应的Reference是:
var fooReference = {
    base: EnvironmentRecord,
    name: 'foo',
    strict: false
};

再举个例证:

var foo = {
    bar: function () {
        return this;
    }
};

foo.bar(); // foo

// bar对应的Reference是:
var BarReference = {
    base: foo,
    propertyName: 'bar',
    strict: false
};

而且专门的工作中还提供了获得 Reference 组成都部队分的艺术,举例 GetBase 和
IsPropertyReference

那七个艺术极粗略,轻易看1看:

1.GetBase

GetBase(V). Returns the base value component of the reference V.

返回 reference 的 base value

  1. IsPropertyReference

IsPropertyReference(V). Returns true if either the base value is an
object or HasPrimitiveBase(V) is true; otherwise returns false.

粗略的知晓:若是 base value 是一个对象,就回到true

简述Js中this的指向


Reference

那什么样又是Reference?

让我们看八.7章 The Reference Specification Type:

The Reference type is used to explain the behaviour of such operators
as delete, typeof, and the assignment operators.

之所以Reference类型就是用来解释诸如delete、typeof以及赋值等操作行为的。

抄袭尤雨溪大大的话,就是:

那里的 Reference 是三个 Specification Type,相当于“只设有于职业里的用空想来安慰自己类型”。它们是为着越来越好地描述语言的最底层行为逻辑才存在的,但并不设有于实际的
js 代码中。

再看接下去的那段具体介绍Reference的剧情:

A Reference is a resolved name binding.

A Reference consists of three components, the base value, the
referenced name and the Boolean valued strict reference flag.

The base value is either undefined, an Object, a Boolean, a String, a
Number, or an environment record (10.2.1).

A base value of undefined indicates that the reference could not be
resolved to a binding. The referenced name is a String.

那段讲了Reference有四个组成都部队分,分别是:

  • base value
  • referenced name
  • strict reference

还要base value是undefined, an Object, a Boolean, a String, a Number, or
an environment record当中的1种

reference name是字符串。

而是这一个到底是如何吧?

让我们简要的明亮base
value是性质所在的靶子也许正是EnvironmentRecord,referenced
name就是性质的称号

嗯,举个例子:

var foo = 1; var fooReference = { base: EnvironmentRecord, name: ‘foo’,
strict: false };

1
2
3
4
5
6
7
var foo = 1;
 
var fooReference = {
  base: EnvironmentRecord,
  name: ‘foo’,
  strict: false
};

再比如:

var foo = { bar: function () { return this; } }; foo.bar(); // foo var
fooBarReference = { base: foo, propertyName: ‘bar’, strict: false };

1
2
3
4
5
6
7
8
9
10
11
12
13
var foo = {
  bar: function () {
    return this;
  }
};
foo.bar(); // foo
 
var fooBarReference = {
  base: foo,
  propertyName: ‘bar’,
  strict: false
};

再正是专门的学业中还提供了能够收获Reference组成都部队分的方式,例如 GetBase 和
IsPropertyReference

那四个主意很简短,轻松看一看:

1.GetBase

GetBase(V). Returns the base value component of the reference V.

返回reference的base value

2.IsPropertyReference

IsPropertyReference(V). Returns true if either the base value is an
object or HasPrimitiveBase(V) is true; otherwise returns false.

大约的了然:base value是object,就回来true

1、Types

Types are further subclassified into ECMAScript language types and
specification types.

An ECMAScript language type corresponds to values that are directly
manipulated by an ECMAScript programmer using the ECMAScript language.
The ECMAScript language types are Undefined, Null, Boolean, String,
Number, and Object.

A specification type corresponds to meta-values that are used within
algorithms to describe the semantics of ECMAScript language constructs
and ECMAScript language types. The specification types are Reference,
List, Completion, Property Descriptor, Property Identifier, Lexical
Environment, and Environment Record.

翻译过来正是:

品类又再分为ECMAScript语言类型和正式类型。

ECMAScript语言类型是开荒者使用ECMAScript直接操作的档期的顺序。ECMAScript语言类型是Undefined,Null,Boolean,String,
Number, 和Object。

专门的职业类型也正是meta-values,用来用算法来描述ECMAScript
语言结商谈语言类型的。标准类型是:Reference,List,Completion,Property
Descriptor,Property Identifier, Lexical Environment, and Environment
Record。

我们需求明白在 ECMAScript
标准中还有壹种只设有于专门的学业中的类型,它们的功用是用来描述语言底层行为逻辑。

GetValue


除开,紧接着在捌.七.壹 章标准中就讲了三个用于从 Reference
类型获取对应值的章程: GetValue

简易模拟 GetValue 的选取:

var foo = 1;

var fooReference = {
    base: EnvironmentRecord,
    name: 'foo',
    strict: false
};

GetValue(fooReference) // 1;

GetValue 再次来到对象属性真正的值,可是要专注:
调用 GetValue,重回的将是切实的值,而不再是2个 Reference

1.背景介绍

当JavaScript代码实施1段可推行代码(executable
code)时,会创设对应的奉行上下文(execution context)。
对此每一种推行上下文,都有八个注重性质:

  • 变量对象(Variable object,VO)
  • 效益域链(Scope chain)
  • this

GetValue

深远之从,从ECMAScript标准解读this。除此而外,紧接着标准中就讲了二个GetValue方法,在八.7.一章

总结模拟GetValue的利用:

var foo = 1; var fooReference = { base: EnvironmentRecord, name: ‘foo’,
strict: false }; GetValue(fooReference) // 1;

1
2
3
4
5
6
7
8
9
var foo = 1;
 
var fooReference = {
  base: EnvironmentRecord,
  name: ‘foo’,
  strict: false
};
 
GetValue(fooReference) // 1;

GetValue再次来到对象属性真正的值,不过要小心,调用GetValue,再次回到的将是现实的值,而不再是贰个Reference,这几个很入眼。

那干什么要讲References呢?

2、Reference

8.7 章 The Reference Specification Type:

The Reference type is used to explain the behaviour of such operators
as delete, typeof, and the assignment operators.

Reference 类型是用来讲授删除,typeof和赋值操作等表现的。
Reference由三部分构成:

  • base value
  • referenced name
  • strict reference
    回顾领悟,base value 就是性质所在的对象或许就是EnvironmentRecord,它的值只或然是 undefined, an Object, a Boolean, a
    String, a Number, or an environment record 在那之中的1种。

base value 便是性质所在的目标也许就是 EnvironmentRecord,它的值只也许是
undefined, an Object, a Boolean, a String, a Number, or an environment
record 在那之中的1种。
深远之从,从ECMAScript标准解读this。举多少个栗子:

var foo = 1;

// 对应的Reference是:
var fooReference = {
    base: EnvironmentRecord,
    name: 'foo',
    strict: false
};

var foo = {
    bar: function () {
        return this;
    }
};

foo.bar(); // foo

// bar对应的Reference是:
var BarReference = {
    base: foo,
    propertyName: 'bar',
    strict: false
};

正规中还提供了赚取 Reference 组成部分的格局,举个例子 GetBase 和
IsPropertyReference。
GetBase,返回 reference 的 base value。
IsPropertyReference,如若 base value 是1个对象,就重回true。

何以分明this的值


规范 11.2.3 Function Calls

此处讲了当函数调用的时候,怎样规定 this 的取值。
只看率先步、第6步、第玖步:

1.Let ref be the result of evaluating MemberExpression.

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.

让我们描述一下:

  1. 算算 MemberExpression 的结果赋值给 ref

  2. 剖断 ref 是否2个 Reference 类型

     2.1 如果 ref 是 Reference,并且 IsPropertyReference(ref) 是 true, 那么 this 的值为 GetBase(ref)
     2.2 如果 ref 是 Reference,并且 base value 值是 Environment Record, 那么this的值为 ImplicitThisValue(ref)
     2.3 如果 ref 不是 Reference,那么 this 的值为 undefined
    

2.学问剖析

何以规定this的值

看规范11.2.3 Function Calls。

那边讲了当函数调用的时候,如何规定this的取值

看率先步 第四步 第10步:

1.Let ref be the result of evaluating MemberExpression.

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).

1
2
3
4
  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.

JavaScript

a. Let thisValue be undefined.

1
  a. Let thisValue be undefined.

让我们讲述一下:

一.乘除MemberExpression的结果赋值给ref

二.判断ref是还是不是四个Reference类型,

2.1.如果ref是Reference,并且IsPropertyReference(ref)是true, 那么this =
GetBase(ref)
2.2.如果ref是Reference,并且base值是Environment Record, 那么this =
ImplicitThisValue(ref),
2.3.如果ref不是Reference,那么 this = undefined

让大家一步一步看:

  1. 计算MemberExpression

什么是MemberExpression?看规范11.2 Left-Hand-Side Expressions:

MemberExpression :

  • PrimaryExpression // 原始表明式 能够参见《JavaScript权威指南第5章》
  • FunctionExpression // 函数定义表达式
  • MemberExpression [ Expression ] // 属性访问表明式
  • MemberExpression . IdentifierName // 属性访问表明式
  • new MemberExpression Arguments // 对象创造表达式

举个例证:

function foo() { console.log(this) } foo(); // MemberExpression是foo
function foo() { return function() { console.log(this) } } foo()(); //
MemberExpression是foo() var foo = { bar: function () { return this; } }
foo.bar(); // MemberExpression是foo.bar

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
function foo() {
    console.log(this)
}
 
foo(); // MemberExpression是foo
 
function foo() {
    return function() {
        console.log(this)
    }
}
 
foo()(); // MemberExpression是foo()
 
var foo = {
    bar: function () {
        return this;
    }
}
 
foo.bar(); // MemberExpression是foo.bar

就此简单明了MemberExpression其实正是()左侧的一些

接下去正是决断MemberExpression的结果是或不是Reference,这时候将要看标准是何等处理各个MemberExpression,看标准规定这一个操作是还是不是会回去二个Reference类型。

举最终一个例证:

var value = 1; var foo = { value: 2, bar: function () { return
this.value; } } //试验1 console.log(foo.bar()); //试验2
console.log((foo.bar)()); //试验3 console.log((foo.bar = foo.bar)());
//试验4 console.log((false || foo.bar)()); //试验5 console.log((foo.bar,
foo.bar)());

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
var value = 1;
 
var foo = {
  value: 2,
  bar: function () {
    return this.value;
  }
}
 
//试验1
console.log(foo.bar());
//试验2
console.log((foo.bar)());
//试验3
console.log((foo.bar = foo.bar)());
//试验4
console.log((false || foo.bar)());
//试验5
console.log((foo.bar, foo.bar)());

在试验第11中学,MemberExpression总结的结果是foo.bar,那么foo.bar是否1个Reference呢?

翻开标准1一.二.壹 Property
Accessors,那里体现了多少个测算的历程,什么都不管了,就看最后一步

Return a value of type Reference whose base value is baseValue and
whose referenced name is propertyNameString, and whose strict mode
flag is strict.

回来了多个Reference类型!

该值为:

var Reference = { base: foo, name: ‘bar’, strict: false };

1
2
3
4
5
var Reference = {
  base: foo,
  name: ‘bar’,
  strict: false
};

下一场那个因为base value是3个目标,所以IsPropertyReference(ref)是true,

那正是说this = GetBase(ref),也正是foo, 所以this指向foo,试验1的结果就是 2

嗳呀妈呀,为了表明this指向foo,累死小编了!

剩下的就快快了:

看试验2,使用了()包住了foo.bar

查看标准11.一.陆 The Grouping Operator

Return the result of evaluating Expression. This may be of type
Reference.

NOTE This algorithm does not apply GetValue to the result of
evaluating Expression.

实际上()并未对MemberExpression举办测算,所以跟试验壹是同样的。

看试验叁,有赋值操作符
翻开标准1一.一3.一 Simple Assignment ( = ):

总计的第贰步:

3.Let rval be GetValue(rref).

因为运用了GetValue,所以回来的不是reference类型,this为undefined

看试验四,逻辑云算法

查阅标准11.11 Binary Logical Operators:

测算第一步:

2.Let lval be GetValue(lref).

因为使用了GetValue,所以回来的不是reference类型,this为undefined

看试验5,逗号操作符
翻开标准1一.1四 Comma Operator ( , )

计量第3步:

2.Call GetValue(lref).

因为运用了GetValue,所以回来的不是reference类型,this为undefined

不过注意在非严苛情势下,this的值为undefined的时候,其值会被隐式调换为全局对象。

由此最后三个例证的结果是:

var value = 1; var foo = { value: 2, bar: function () { return
this.value; } } //试验1 console.log(foo.bar()); //2 //试验2
console.log((foo.bar)()); //2 //试验3 console.log((foo.bar =
foo.bar)()); //1 //试验4 console.log((false || foo.bar)()); //1 //试验5
console.log((foo.bar, foo.bar)()); //1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
var value = 1;
 
var foo = {
  value: 2,
  bar: function () {
    return this.value;
  }
}
 
//试验1
console.log(foo.bar()); //2
//试验2
console.log((foo.bar)()); //2
//试验3
console.log((foo.bar = foo.bar)()); //1
//试验4
console.log((false || foo.bar)()); //1
//试验5
console.log((foo.bar, foo.bar)()); //1

瞩目:严酷情势下因为this再次回到undefined,所以试验三会报错

最终,忘记了三个最最常见的动静:

function foo() { console.log(this) } foo();

1
2
3
4
5
function foo() {
    console.log(this)
}
 
foo();

MemberExpression是foo,解析标志符
翻开标准十.3.一 Identifier Resolution

会回来多个 Reference类型

唯独 base value是 Environment Record,所以会调用ImplicitThisValue(ref)

翻看标准拾.2.一.壹.陆

一向再次回到undefined

就此最终this的值是undefined

GetValue

除了那些之外,紧接着在 八.7.一 章标准中就讲了二个用来从 Reference
类型获取对应值的措施: GetValue。
粗略模拟 GetValue 的选取:

var foo = 1;

var fooReference = {
    base: EnvironmentRecord,
    name: 'foo',
    strict: false
};
GetValue(fooReference) // 1;

GetValue 再次来到对象属性真正的值,不过要留意:

调用 GetValue,重临的将是现实的值,而不再是三个 Reference

具体分析


让大家一步一步看:

  1. 总结 MemberExpression 的结果赋值给 ref

什么是 MemberExpression?看规范 11.2 Left-Hand-Side Expressions

MemberExpression :

  • PrimaryExpression // 原始表明式 能够参见《JavaScript权威指南第伍章》
  • FunctionExpression // 函数定义表明式
  • MemberExpression [ Expression ] // 属性访问表明式
  • MemberExpression . IdentifierName // 属性访问表明式
  • new MemberExpression Arguments // 对象成立表达式

举个例证:

function foo() {
    console.log(this)
}

foo(); // MemberExpression 是 foo

function foo() {
    return function() {
        console.log(this)
    }
}

foo()(); // MemberExpression 是 foo()

var foo = {
    bar: function () {
        return this;
    }
}

foo.bar(); // MemberExpression 是 foo.bar

于是轻巧明了 MemberExpression 其实正是()右边的有的

二.判定 ref 是还是不是一个 Reference 类型。

驷比不上舌就在于看标准是如何管理各类MemberExpression,重临的结果是还是不是二个Reference类型。

举最终三个例子:

var value = 1;

var foo = {
  value: 2,
  bar: function () {
    return this.value;
  }
}

//示例1
console.log(foo.bar());
//示例2
console.log((foo.bar)());
//示例3
console.log((foo.bar = foo.bar)());
//示例4
console.log((false || foo.bar)());
//示例5
console.log((foo.bar, foo.bar)());
ECMASC奥迪Q7IPT 的品种分为语言类型和正规类型。
  • ECMAScript 语言类型是开拓者直接行使 ECMAScript
    能够操作的。其实正是我们常说的Undefined, Null, Boolean, String,
    Number, 和 Object。
  • ECMAScript
    标准中还有一种只存在杨佳式中的类型,它们的功效是用来描述语言底层行为逻辑。

多说一句

就算大家不容许去分明每三个this的针对性都从标准的角度去观念,久而久之,大家就会总计各样场地来报告我们那种场地下this的对准,可是能从正规的角度去对待this的指向,相对是三个不均等的角度,该文有不审慎的地点,还请大神指正!

何以显著this值

至于 Reference 讲了那么多,为何要讲 Reference 呢?到底 Reference
跟本文的焦点 this
有哪些关系呢?假设你能耐心看完此前的内容,以下开端进入高能阶段。
看规范 11.2.3 Function Calls:
那里讲了当函数调用的时候,怎样规定 this 的取值。
只看率先步、第肆步、第10步:

Let ref be the result of evaluating MemberExpression.

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).
  1. Else, Type(ref) is not Reference.
    a. Let thisValue be undefined.

翻译一下便是:
壹、将MemberExpression的结果赋值给ref
贰、判定ref是否3个Reference类型
3、如果ref是Reference,并且IsPropertyReference(ref)是true,那么this的值为GetBase(ref)
4、如果ref是Reference,并且base value值是Enviroment
Recored,那么this值为ImplicitThisValue(ref)
5、如果ref不是reference,那么this的值为undefined

foo.bar()

在示例 1 中,MemberExpression 总结的结果是 foo.bar,那么 foo.bar
是还是不是2个 Reference 呢?

查看标准 11.2.1 Property
Accessors
,这里展现了一个计算的经过,什么都不管了,就看最后一步:

Return a value of type Reference whose base value is baseValue and
whose referenced name is propertyNameString, and whose strict mode
flag is strict.

我们得知该表明式再次回到了一个 Reference 类型!
听新闻说在此之前的剧情,我们知晓该值为:

var Reference = {
  base: foo,
  name: 'bar',
  strict: false
};

接下去遵照 二.一 的论断流程走:

2.1 如果 ref 是 Reference,并且 IsPropertyReference(ref) 是 true, 那么
this 的值为 GetBase(ref)

该值是 Reference 类型,那么 IsPropertyReference(ref) 的结果是有些啊?

前方大家早已铺垫了 IsPropertyReference 方法,要是 base value
是2个目标,结果回到 true。

base value 为 foo,是一个对象,所以 IsPropertyReference(ref) 结果为
true。

那个时候大家就足以明确 this 的值了:

this = GetBase(ref)

GetBase 也1度铺垫了,获得 base value 值,这一个事例中便是foo,所以 this
的值正是 foo ,示例1的结果正是 二!

其间首若是正是标准类型中的 Reference 类型。它与 this 的针对有着密切的关联。

此地的 Reference 是三个 Specification Type,相当于“只设有邹静之规里的虚幻类型”。它们是为着更加好地描述语言的底层行为逻辑才存在的,但并不存在于实际的
js 代码中。
REFERENCE 的组合,由八个组成都部队分,分别是:

  • base value
  • referenced name
  • strict reference

base value 正是性质所在的靶子也许便是EnvironmentRecord,它的值只或然是 undefined, an Object, a Boolean, a
String, a Number, or an environment record 当中的一种。

referenced name 正是性质的名目。
举个例证:

  var foo = 1;
// 对应的Reference是:
  var fooReference = {
         base: EnvironmentRecord,
         name: 'foo',
         strict: false
    };

并且职业中还提供了收获 REFERENCE 组成都部队分的点子,比方 GETBASE 和
ISPROPERTYREFERENCE。

  • GetBase(reference),再次回到的是reference的值
  • IsPropertyReference(reference),假使 base value
    是一个目的,就回来true。
  • GetValue,GetValue 重回对象属性真正的值,可是要注意:调用
    GetValue,重回的将是现实性的值,而不再是二个 Reference

深深连串

JavaScript深远种类估算写十5篇左右,目的在于帮大家捋顺JavaScript底层知识,重视疏解如原型、成效域、实践上下文、变量对象、this、闭包、按值传递、call、apply、bind、new、继承等难处概念,与罗列它们的用法差异,这些类别更正视通过写demo,捋进程、模拟落成,结合ES规范等方法来教学。

不无小说和demo都能够在github上找到。要是有不当或许不严峻的地点,请务必给予指正,13分多谢。要是喜欢依然具有启发,欢迎star,对小编也是一种鞭策。

本系列:

  1. JavaScirpt 浓厚之从原型到原型链
  2. JavaScript
    深刻之词法功能域和动态功用域
  3. JavaScript 深切之实践上下文栈
  4. JavaScript 深刻之变量对象
  5. JavaScript 深远之功力域链

    1 赞 收藏
    评论

皇家赌场手机版 1

具体分析

(foo.bar)()

看示例2:

console.log((foo.bar)());

foo.bar 被 () 包住,查看规范 11.1.6 The Grouping Operator
直接看结果部分:

Return the result of evaluating Expression. This may be of type
Reference.

NOTE This algorithm does not apply GetValue to the result of
evaluating Expression.

实际上 () 并不曾对 MemberExpression 进行测算,所以实际跟示例 1的结果是同壹的。

当函数调用时,怎样明确THIS的值?

1.划算MemberExpression的结果赋给ref
二.肯定ref是还是不是一个Reference类型
a.假若ref是Reference,并且ref的base value是二个指标,那么 this 的值为 base
value
如果 ref 是 Reference,并且 base value 值是 Environment Record,
那么this的值为 ImplicitThisValue(ref)即为undefind
b.如果 ref 不是 Reference,那么 this 的值为 undefined
举个例证:

                    function foo() {
                       console.log(this)
                    }
                    foo(); // MemberExpression 是 foo
                    function foo() {
                       return function() {
                       console.log(this)
                      }
                    }
                    foo()(); // MemberExpression 是 foo()
                    var foo = {
                       bar: function () {
                       return this;
                       }
                    }
                    foo.bar(); // MemberExpression 是 foo.bar

故而简单明了 MemberExpression 其实就是()左侧的1对。

二.肯定 ref 是否一个 Reference 类型。 关键就在于看规范是怎么管理各类MemberExpression,再次回到的结果是否一个Reference类型。 举最终2个事例:

                    var value = 1;
                    var foo = {
                      value: 2,
                      bar: function () {
                        return this.value;
                      }
                    }
                    //示例1
                    console.log(foo.bar());
                    //示例2
                    console.log((foo.bar)());
                    //示例3
                    console.log((foo.bar = foo.bar)());
                    //示例4
                    console.log((false || foo.bar)());
                    //示例5
                    console.log((foo.bar, foo.bar)());

皇家赌场手机版,foo.bar()在示例 一 中,MemberExpression 计算的结果是 foo.bar,那么
foo.bar 是否贰个 Reference 呢? 查看标准 1一.二.一 Property
Accessors,这里显得了五个划算的历程,什么都不管了,就看最终一步:

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个 Reference
类型!遵照以前的始末,大家知晓该值为:

                    var Reference = {
                      base: foo,
                      name: 'bar',
                      strict: false
                    };

接下去依据 2.一 的决断流程走:该值是 Reference
类型,然后实践IsPropertyReference(ref),假如ref的base
value是一个对象则赶回true,那么 this 的值为 base value 即那个foo

实例叁,四,第55中学,MemberExpression计算结果个别为(foo.bar=foo.bar),(false||foo.var),(f00,bar,foo,bar)

依附专门的学业,逗号操作符,逻辑或操作符和赋值操作符都会施行:

3.Let rval be GetValue(ref).

因为运用了 GetValue,所以回来的不是 Reference 类型,this 为 undefined

this 为 undefined,非严俊情势下,this 的值为 undefined
的时候,其值会被隐式转变为大局对象。
结果:

                    var value = 1;

                    var foo = {
                      value: 2,
                      bar: function () {
                        return this.value;
                      }
                    }

                    //示例1
                    console.log(foo.bar()); // 2
                    //示例2
                    console.log((foo.bar)()); // 2
                    //示例3
                    console.log((foo.bar = foo.bar)()); // 1
                    //示例4
                    console.log((false || foo.bar)()); // 1
                    //示例5
                    console.log((foo.bar, foo.bar)()); // 1

由此这么些this都指向了全局对象


一、将MemberExpression的结果赋值给ref

什么是MemberExpression?
看规范 11.2 Left-Hand-Side Expressions:

  • PrimaryExpression
  • FunctionExpression
  • MemberExpression [ Expression ]
  • MemberExpression . IdentifierName
  • new MemberExpression Arguments
    举个栗子:

function foo() {
   console.log(this)
}
foo(); // MemberExpression 是 foo
function foo() {
   return function() {
       console.log(this)
   }
}
foo()(); // MemberExpression 是 foo()
var foo = {
   bar: function () {
       return this;
   }
}
foo.bar(); // MemberExpression 是 foo.bar

所以轻松掌握 MemberExpression 其实就是()右侧的1对。

(foo.bar = foo.bar)()

看示例三,有赋值操作符,查看标准11.13.1 Simple Assignment ( = ):

3.Let rval be GetValue(rref).

因为使用了 GetValue,所以回来的值不是 Reference 类型

遵从事先讲的论断逻辑:

2.3 如果 ref 不是Reference,那么 this 的值为 undefined

this 为 undefined,非严苛方式下,this 的值为 undefined
的时候,其值会被隐式转变为大局对象

3.大面积难题

一.怎么转移this的针对?


2、剖断ref是或不是二个Reference类型

入眼就在于看标准是何许处理各种MemberExpression,重临的结果是否3个Reference类型。
还举多少个例证:

var value = 1;
var foo = {
  value: 2,
  bar: function () {
    return this.value;
  }
}
//示例1
console.log(foo.bar());
//示例2
console.log((foo.bar)());
//示例3
console.log((foo.bar = foo.bar)());
//示例4
console.log((false || foo.bar)());
//示例5
console.log((foo.bar, foo.bar)());

foo.bar()
在示范第11中学,MemberExpression 总计的结果是 foo.bar,那么 foo.bar
是还是不是1个 Reference 呢?查看标准 1一.二.1 Property
Accessors,那里展现了二个测算的经过,什么都不管了,就看最终一步:

Return a value of type Reference whose base value is baseValue and
whose referenced name is propertyNameString, and whose strict mode
flag is strict.

我们驾驭foo.bar的Reference值为:

var Reference = {
  base: foo,
  name: 'bar',
  strict: false
}

借下来依据二.1的判别流程走。

2.1 如果 ref 是 Reference,并且 IsPropertyReference(ref) 是 true, 那么
this 的值为 GetBase(ref)
该值是reference类型,那么 IsPropertyReference(ref) 是多少啊?
基于前边的只是,若是base value是三个目的,结果回到true。base
value为foo,是三个对象,所以IsPropertyReference(ref)结果为true。
这年大家就能够规定this的值了: this = GetBase(ref);
GetBase能够获得base
value值,那一个例子中是foo,所以this的值就是foo,示例一的结果就是二!

(foo.bar)()
看示例2:console.log((foo.bar)());
foo.bar被()包住,查看标准1一.1.陆The Grouping Operator
直接查看结果部分:

Return the result of evaluating Expression. This may be of type
Reference.
NOTE This algorithm does not apply GetValue to the result of
evaluating Expression.

翻译:

回去施行Expression的结果,它大概是Reference类型。
那壹算法并不会作用GetValue于试行Expression的结果。

实在 () 并不曾对 MemberExpression 进行总括,所以其实跟示例 1的结果是如出壹辙的。

(foo.bar = foo.bar)()
看示例叁,有赋值操作符,查看标准 11.一三.一 Simple Assignment ( = ):
计算的第2步:

3.Let rval be GetValue(rref).

因为运用了 GetValue,所以回来的值不是 Reference
类型。遵照事先的剖断逻辑:

2.3 如果 ref 不是Reference,那么 this 的值为 undefined

this 为 undefined,非严刻情势下,this 的值为 undefined
的时候,其值会被隐式转变为大局对象。

(false || foo.bar)()
看示例4,逻辑与算法,查看规范 1一.1壹 Binary Logical Operators:

2.Let lval be GetValue(lref).

因为使用了 GetValue,所以回来的不是 Reference 类型,this 为 undefined

(foo.bar, foo.bar)()
看示例伍,逗号操作符,查看标准1一.1肆 Comma Operator ( , )
计量第一步:

2.Call GetValue(lref).

因为运用了 GetValue,所以回来的不是 Reference 类型,this 为 undefined

(false || foo.bar)()

看示例4,逻辑与算法,查看规范 11.11 Binary Logical Operators
算算第一步:

2.Let lval be GetValue(lref).

因为使用了 GetValue,所以回来的不是 Reference 类型,this 为 undefined

4.化解方案

答:能够动用call大概apply的情势:

                // 一个对象可以作为call和apply的第一个参数,并且this会被绑定到这个对象。
                var obj = {a: 'Custom'};

                // 这个属性是在global对象定义的。
                var a = 'Global';

                function whatsThis(arg) {
                  console.log(this.a) // this的值取决于函数的调用方式
                }

                whatsThis();          // 'Global'
                whatsThis.call(obj);  // 'Custom'
                whatsThis.apply(obj); // 'Custom'

结果发表

之所以结果就是

var value = 1;

var foo = {
  value: 2,
  bar: function () {
    return this.value;
  }
}

//示例1
console.log(foo.bar()); // 2
//示例2
console.log((foo.bar)()); // 2
//示例3
console.log((foo.bar = foo.bar)()); // 1
//示例4
console.log((false || foo.bar)()); // 1
//示例5
console.log((foo.bar, foo.bar)()); // 1

留意:以上是在非严峻形式下的结果,严俊格局下因为 this 返回undefined,所以示例 三 会报错。

(foo.bar, foo.bar)()

看示例5,逗号操作符,查看规范1壹.1肆 Comma Operator ( , )

总括第3步:

2.Call GetValue(lref).

因为运用了 GetValue,所以回来的不是 Reference 类型,this 为 undefined

5.编码实战


最简易的景色
function foo() {
    console.log(this)
}

foo(); 

MemberExpression 是 foo,解析标记符,查看标准 拾.3.一 Identifier
Resolution,会重回多个 Reference 类型的值:
var fooReference = {
base: EnvironmentRecord,
name: ‘foo’,
strict: false
};
接下去进行剖断:

2.1 如果 ref 是 Reference,并且 IsPropertyReference(ref) 是 true, 那么
this 的值为 GetBase(ref)

因为 base value 是 EnvironmentRecord,并不是贰个 Object
类型,还记得前面讲过的 base value 的取值恐怕吗? 只大概是 undefined, an
Object, a Boolean, a String, a Number, 和 an environment record
中的一种。
IsPropertyReference(ref) 的结果为 false,进入下个判定:

2.2 如果 ref 是 Reference,并且 base value 值是 Environment Record,
那么this的值为 ImplicitThisValue(ref)

base value 正是 Environment Record,所以会调用 ImplicitThisValue(ref)
查看标准 10.2.一.一.陆,ImplicitThisValue 方法的介绍:该函数始终重临undefined。
由此最终 this 的值正是 undefined。

颁发结果

因此最后二个例证的结果是:

var value = 1;

var foo = {
  value: 2,
  bar: function () {
    return this.value;
  }
}

//示例1
console.log(foo.bar()); // 2
//示例2
console.log((foo.bar)()); // 2
//示例3
console.log((foo.bar = foo.bar)()); // 1
//示例4
console.log((false || foo.bar)()); // 1
//示例5
console.log((foo.bar, foo.bar)()); // 1

在意:以上是在非严俊情势下的结果,严刻方式下因为 this 再次来到undefined,所以示例 叁 会报错。

陆.增加思虑

以下代码的this的针对性?

                    function Foo(){
                        getName = function(){
                            console.log(1);
                            };
                        return this
                    }

                    function getName(){
                        console.log(5);
                    }

                    Foo().getName();

at last

即使大家得以总结的掌握 this
为调用函数的靶子,假使是那样的话,怎么着解释上面这些例子吗?

var value = 1;

var foo = {
  value: 2,
  bar: function () {
    return this.value;
  }
}
console.log((false || foo.bar)()); // 1

其它,又怎么样鲜明调用函数的目的是什么人啊?

补充

最末尾,忘记了3个最最日常的情形:

function foo() {
    console.log(this)
}

foo(); 

MemberExpression 是 foo,解析标志符,查看规范 十.三.一 Identifier
Resolution,会回到多少个 Reference 类型的值:

var fooReference = {
    base: EnvironmentRecord,
    name: 'foo',
    strict: false
};

接下去举办判断:

2.1 如果 ref 是 Reference,并且 IsPropertyReference(ref) 是 true, 那么
this 的值为 GetBase(ref)

因为 base value 是 EnvironmentRecord,并不是多个 Object
类型,还记得前边讲过的 base value 的取值只怕啊? 只只怕是 undefined, an
Object, a Boolean, a String, a Number, 和 an environment record
中的1种。

IsPropertyReference(ref) 的结果为 false,进入下个判定:

2.2 如果 ref 是 Reference,并且 base value 值是 Environment Record,
那么this的值为 ImplicitThisValue(ref)

base value 就是 Environment Record,所以会调用 ImplicitThisValue(ref)

翻开规范 拾.二.1.一.陆,ImplicitThisValue 方法的牵线:该函数始终重返undefined

故此最终 this 的值正是 undefined。

7.参考文献

参考一:JavaScript深刻之从ECMAScript标准解读this

参考一:this


捌.越来越多研讨

Q1:构造函数的this指向?
A壹:构造函数的this指向实例对象

Q2:除了call,applay还有任何改换this指向的艺术吧?
A贰:还足以使用new关键字和bing()方法退换this的针对性

Q3:reference是什么?
A叁:reference类型是js中的标准类型,是用来讲述底层行为逻辑的档期的顺序,并不设有于实际的js代码中


视频
PPT

Leave a Comment.