菜单

JavaScript深入的于ECMAScript规范解读this

2018年11月16日 - JavaScript

怎确定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 :

推选个例:

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)());

于测验1惨遭,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

章可以于本人之 Github
https://github.com/mqyqingfeng/Blog
查看

大多说一样词

尽管我们不容许错过确定各一个this的针对都打标准之角度去思维,久而久之,我们就算会总结各种气象来喻大家这种状况下this的针对性,但是能自正式之角度去看待this的针对,绝对是一个休同等的角度,该文有无谨言慎行的地方,还求大神指正!

现已去简书,原因参见
http://www.jianshu.com/p/0f12350a6b66。

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类型。

即便人微言轻,但为要发生投机的态度。

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有三独片,分别是:

而且base value是undefined, an Object, a Boolean, a String, a Number, or
an environment record其中的一模一样栽

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

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呢?

前言

在《JavaScript深入的履上下文栈》未遭提到,当JavaScript代码执行一段子可尽代码(executable
code)时,会创造对应的实践上下文(execution context)。

对每个执行上下文,都发出三个基本点性质

今着重出口讲this,然而不好说话。

……

因咱们若自ECMASciript5正规开始称起。

先行接受上ECMAScript 5.1正经地方:

英文版:http://es5.github.io/#x15.1

中文版:http://yanhaijing.com/es5/#115

叫咱开询问规范吧!

深深系列

JavaScript深入系列预计写十五篇左右,旨在帮助大家捋顺JavaScript底层知识,重点教学如原型、作用域、执行上下文、变量对象、this、闭包、按值传递、call、apply、bind、new、继承等困难概念,与陈它们的用法不同,这个系列还重通过描写demo,捋过程、模拟实现,结合ES规范等方式来教。

具文章与demo都得以于github上https://github.com/mqyqingfeng/Blog找到。如果起不当或无谨言慎行的地方,请务必与指正,十分谢谢。如果喜欢或者持有启发,欢迎star,对笔者为是同一栽鞭策。

本系列:

  1. JavaScirpt 深入之从原型到原型链
  2. JavaScript
    深入的词法作用域和动态作用域
  3. JavaScript 深入之实践上下文栈
  4. JavaScript 深入的变量对象
  5. JavaScript 深入的图域链

    1 赞 收藏
    评论

图片 1

JavaScript 深入之从 ECMAScript 规范解读 this

2017/05/17 · JavaScript
· this

原稿出处: 冴羽   

相关文章

发表评论

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

网站地图xml地图