从ECMAScript规范解读this,深入之从【永利澳门游戏网址304】

前言

在《JavaScript深切之推行上下文栈》中讲到,当JavaScript代码试行一段可进行代码(executable
code)时,会创建对应的推行上下文(execution context)。

对此各类试行上下文,都有八个第一性质

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

今日至关重大讲讲this,但是倒霉讲。

……

因为我们要从ECMASciript5专门的学业早先讲起。

先奉上ECMAScript 5.1正式地点:

英文版:

中文版:

让我们带头精晓标准吧!

2、决断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)());

foo.bar()
在示范第11中学,MemberExpression 总括的结果是 foo.bar,那么 foo.bar
是否二个 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.

大家精晓foo.bar的Reference值为:

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

借下来遵照2.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,示例1的结果便是2!

(foo.bar)()
看示例2:console.log((foo.bar)());
foo.bar被()包住,查看标准11.1.6The 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)()
看示例3,有赋值操作符,查看标准 11.13.1 Simple Assignment ( = ):
计量的第三步:

3.Let rval be GetValue(rref).

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

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

this 为 undefined,非严峻情势下,this 的值为 undefined
的时候,其值会被隐式调换为大局对象。

(false || foo.bar)()
看示例4,逻辑与算法,查看标准 11.11 Binary Logical Operators:

2.Let lval be GetValue(lref).

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

(foo.bar, foo.bar)()
看示例5,逗号操作符,查看标准11.14 Comma Operator ( , )
计量第二步:

2.Call GetValue(lref).

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

JavaScript 深刻之从 ECMAScript 规范解读 this

2017/05/17 · JavaScript
· this

原版的书文出处: 冴羽   

何以明确this值

有关 Reference 讲了那么多,为何要讲 Reference 呢?到底 Reference
跟本文的主旨 this
有啥样关系呢?倘使您能耐心看完以前的剧情,以下开头进入高能阶段。
看规范 11.2.3 Function Calls:
此处讲了当函数调用的时候,怎么着规定 this 的取值。
只看率先步、第六步、第七步:

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.

翻译一下正是:
1、将MemberExpression的结果赋值给ref
2、决断ref是或不是多个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

GetValue

除了,紧接着标准中就讲了多个GetValue方法,在8.7.1章

简简单单模拟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呢?

at last

固然我们能够轻易的明亮 this
为调用函数的指标,要是是那样的话,怎么样分解上面那几个事例吗?

var value = 1;

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

别的,又何以明显调用函数的靶子是什么人啊?

深刻体系

JavaScript浓郁种类估摸写十五篇左右,意在帮我们捋顺JavaScript底层知识,入眼传授如原型、功用域、施行上下文、变量对象、this、闭包、按值传递、call、apply、bind、new、承袭等难处概念,与罗列它们的用法差别,那一个类别更讲求通过写demo,捋过程、模拟实现,结合ES标准等艺术来说授。

负有文章和demo都得以在github上找到。若是有荒唐也许相当的大心的地点,请必需给予指正,拾分多谢。借使喜欢只怕持有启发,招待star,对作者也是一种鞭笞。

本系列:

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

    1 赞 收藏
    评论

永利澳门游戏网址304 1

具体拆解分析

怎样鲜明this的值

看规范11.2.3 Function Calls。

此地讲了当函数调用的时候,怎么着明确this的取值

看率先步 第六步 第七步:

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.

让我们陈诉一下:

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

2.论断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权威指南第四章》
  • 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是否一个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 };

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

接下来那些因为base value是二个对象,所以IsPropertyReference(ref)是true,

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

嗳呀妈呀,为了注脚this指向foo,累死作者了!

剩余的就便捷了:

看试验2,使用了()包住了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是同一的。

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

总括的第三步:

3.Let rval be GetValue(rref).

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

看试验4,逻辑云算法

翻看标准11.11 Binary Logical Operators:

计量第二步:

2.Let lval be GetValue(lref).

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

看试验5,逗号操作符
查阅规范11.14 Comma Operator ( , )

测算第二步:

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,所以试验3会报错

终极,忘记了贰个最最日常的景色:

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

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

MemberExpression是foo,剖判标记符
翻开标准10.3.1 Identifier Resolution

会重回贰个 Reference类型

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

查阅规范10.2.1.1.6

一向重临undefined

进而最终this的值是undefined

最简便易行的情形
function foo() {
    console.log(this)
}

foo(); 

MemberExpression 是 foo,解析标志符,查看标准 10.3.1 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.1.1.6,ImplicitThisValue 方法的牵线:该函数始终重回undefined。
所以最后 this 的值正是 undefined。

多说一句

就算大家不恐怕去显著每贰个this的针对都从标准的角度去思辨,长年累月,大家就能够总括各样状态来报告大家这种气象下this的针对性,可是能从职业的角度去对待this的指向,相对是二个差异的角度,该文有不严慎的地点,还请大神指正!

结果发表

据此结果正是

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,所以示例 3 会报错。

Types

首先是第8章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类型。

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
标准中还或然有一种只设有于职业中的类型,它们的成效是用来描述语言底层行为逻辑。

发表评论

电子邮件地址不会被公开。 必填项已用*标注