内容简介:In this article, we take a simple function in the spec and try to understand the notation. Let’s go!Even if you know JavaScript, reading its language specification,Let’s start with a concrete example and walk through the spec to understand it. The followin
In this article, we take a simple function in the spec and try to understand the notation. Let’s go!
Even if you know JavaScript, reading its language specification, ECMAScript Language specification, or the ECMAScript spec for short , can be pretty daunting. At least that’s how I felt when I started reading it for the first time.
Let’s start with a concrete example and walk through the spec to understand it. The following code demonstrates usage of Object.prototype.hasOwnProperty
:
const o = { foo: 1 }; o.hasOwnProperty('foo'); // true o.hasOwnProperty('bar'); // false
In the example, o
doesn’t have a property called hasOwnProperty
, so we walk up the prototype chain and look for it. We find it in o
’s prototype, which is Object.prototype
.
To describe how Object.prototype.hasOwnProperty
works, the spec uses pseudocode-like descriptions:
Object.prototype.hasOwnProperty(V)
When the hasOwnProperty
method is called with argument V
, the following steps are taken:
- Let
P
be? ToPropertyKey(V)
. - Let
O
be? ToObject(this value)
. - Return
? HasOwnProperty(O, P)
.
…and…
The abstract operation HasOwnProperty
is used to determine whether an object has an own property with the specified property key. A Boolean value is returned. The operation is called with arguments O
and P
where O
is the object and P
is the property key. This abstract operation performs the following steps:
- Assert:
Type(O)
isObject
. - Assert:
IsPropertyKey(P)
istrue
. - Let
desc
be? O.[[GetOwnProperty]](P)
. - If
desc
isundefined
, returnfalse
. - Return
true
.
But what’s an “abstract operation”? What are the things inside [[ ]]
? Why is there a ?
in front of a function? What do the asserts mean?
Let’s find out!
Language types and specification types
Let’s start with something that looks familiar. The spec uses values such as undefined
, true
, and false
, which we already know from JavaScript. They are all language values , values of language types which the spec also defines.
The spec also uses language values internally, for example, an internal data type might contain a field whose possible values are true
and false
. In contrast, JavaScript engines don’t typically use language values internally. For example, if the JavaScript engine is written in C++, it would typically use the C++ true
and false
(and not its internal representations of the JavaScript true
and false
).
In addition to language types, the spec also uses specification types , which are types that occur only in the spec, but not in the JavaScript language. The JavaScript engine does not need to (but is free to) implement them. In this blog post, we'll get to know the specification type Record (and its subtype Completion Record).
Abstract operations
Abstract operations are functions defined in the ECMAScript spec; they are defined for the purpose of writing the spec concisely. A JavaScript engine doesn’t have to implement them as separate functions inside the engine. They cannot be directly called from JavaScript.
Internal slots and internal methods
Internal slots and internal methods use names enclosed in [[ ]]
.
Internal slots are data members of a JavaScript object or a specification type. They are used for storing the state of the object. Internal methods are member functions of a JavaScript object.
For example, every JavaScript object has an internal slot [[Prototype]]
and an internal method [[GetOwnProperty]]
.
Internal slots and methods are not accessible from JavaScript. For example, you cannot access o.[[Prototype]]
or call o.[[GetOwnProperty]]()
. A JavaScript engine can implement them for their own internal use, but doesn’t have to.
Sometimes internal methods delegate to similarly-named abstract operations, such as in the case of ordinary objects' [[GetOwnProperty]]:
When the [[GetOwnProperty]]
internal method of O
is called with property key P
, the following steps are taken:
Return ! OrdinaryGetOwnProperty(O, P)
.
(We’ll find out what the exclamation mark means in the next chapter.)
OrdinaryGetOwnProperty
is not an internal method, since it’s not associated with any object; instead, the object it operates on is passed as a parameter.
OrdinaryGetOwnProperty
is called “ordinary” since it operates on ordinary objects. ECMAScript objects can be either ordinary or exotic . Ordinary objects must have the default behavior for a set of methods called essential internal methods . If an object deviates from the default behavior, it’s exotic.
The most well-known exotic object is the Array
, since its length property behaves in a non-default way: setting the length
property can remove elements from the Array
.
Essential internal methods are the methods listed here .
Completion records
What about the question marks and exclamation marks? To understand them, we need to look into Completion Records !
Completion Record is a specification type (only defined for spec purposes). A JavaScript engine doesn’t have to have a corresponding internal data type.
A Completion Record is a “record” — a data type which has a fixed set of named fields. A Completion Record has three fields:
Name | Description |
---|---|
[[Type]] |
One of: normal , break , continue , return , or throw . All other types except normal are abrupt completions . |
[[Value]] |
The value that was produced when the completion occurred, for example, the return value of a function or the exception (if one is thrown). |
[[Target]] |
Used for directed control transfers (not relevant for this blog post). |
Every abstract operation implicitly returns a Completion Record. Even if it looks like an abstract operation would return a simple type such as Boolean, it’s implicitly wrapped into a Completion Record with the type normal
(see Implicit Completion Values ).
Note 1: The spec is not fully consistent in this regard; there are some helper functions which return bare values and whose return values are used as is, without extracting the value from the Completion Record. This is usually clear from the context.
Note 2: The spec editors are looking into making the Completion Record handling more explicit.
If an algorithm throws an exception, it means returning a Completion Record with [[Type]]
throw
whose [[Value]]
is the exception object. We’ll ignore the break
, continue
and return
types for now.
ReturnIfAbrupt(argument)
means taking the following steps:
- If
argument
is abrupt, returnargument
- Set
argument
toargument.[[Value]]
That is, we inspect a Completion Record; if it’s an abrupt completion, we return immediately. Otherwise, we extract the value from the Completion Record.
ReturnIfAbrupt
might look like a function call, but it’s not. It causes the function where ReturnIfAbrupt()
occurs to return, not the ReturnIfAbrupt
function itself. It behaves more like a macro in C-like languages.
ReturnIfAbrupt
can be used like this:
- Let
obj
beFoo()
. (obj
is a Completion Record.) -
ReturnIfAbrupt(obj)
-
Bar(obj)
. (If we’re still here,obj
is the value extracted from the Completion Record.)
And now the question mark comes into play: ? Foo()
is equivalent to ReturnIfAbrupt(Foo())
.
Similarly, Let val be ! Foo()
is equivalent to:
- Let
val
beFoo()
- Assert:
val
is not an abrupt completion - Set
val
toval.[[Value]]
.
Using this knowledge, we can rewrite Object.prototype.hasOwnProperty
like this:
Object.prototype.hasOwnProperty(P)
- Let
P
beToPropertyKey(V)
. - If
P
is an abrupt completion, returnP
- Set
P
toP.[[Value]]
- Let
O
beToObject(this value)
. - If
O
is an abrupt completion, returnO
- Set
O
toO.[[Value]]
- Let
temp
beHasOwnProperty(O, P)
. - If
temp
is an abrupt completion, returntemp
- Let
temp
betemp.[[Value]]
- Return
NormalCompletion(temp)
…and we can rewrite HasOwnProperty
like this:
HasOwnProperty(O, P)
- Assert:
Type(O)
isObject
. - Assert:
IsPropertyKey(P)
istrue
. - Let
desc
beO.[[GetOwnProperty]](P)
. - If
desc
is an abrupt completion, returndesc
- Set
desc
todesc.[[Value]]
- If
desc
isundefined
, returnNormalCompletion(false)
. - Return
NormalCompletion(true)
.
We can also rewrite the [[GetOwnProperty]]
internal method without the exclamation mark:
O.[[GetOwnProperty]]
- Let
temp
beOrdinaryGetOwnProperty(O, P)
- Assert:
temp
is not an abrupt completion - Let
temp
betemp.[[Value]]
- Return
NormalCompletion(temp)
Here we assume that temp
is a brand new temporary variable which doesn’t collide with anything else.
We’ve also used the knowledge that when a return statement returns something else than a Completion Record, it’s implicitly wrapped inside a NormalCompletion
.
Side track: Return ? Foo()
The spec uses the notation Return ? Foo()
— why the question mark?
Return ? Foo()
expands to:
- Let
temp
beFoo()
- If
temp
is an abrupt completion, returntemp
- Set
temp
totemp.[[Value]]
- Return
NormalCompletion(temp)
Which is the same as Return Foo()
; it behaves the same way for both abrupt and normal completions.
Asserts in the spec assert invariant conditions of the algorithms. They are added for clarity, but don't add any requirements to the implementation — the implementation doesn’t need to check them.
We have built the understanding needed for reading the spec for simple methods like Object.prototype.hasOwnProperty
and abstract operations like HasOwnProperty
. They still delegate to other abstract operations, but based on this blog post we should be able to figure out what they do. We’ll encounter Property Descriptors, which is just another specification type.
How to Read the ECMAScript Specification : a tutorial which covers much of the material covered in this post, from a slightly different angle.
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
新媒体文案创作与传播
秋叶、叶小鱼、勾俊伟 / 人民邮电出版社 / 2017-4 / 39.80元
《新媒体文案创作与传播》共分三篇。第1篇是新媒体文案基础篇,主要讲述了新媒体文案的基本概念、新媒体文案的岗位要求和职业能力素养;第二篇是新媒体文案创意实务篇,主要讲述了新媒体文案的创作思路、新媒体文案的写作技巧、爆款新媒体文案的打造、新媒体销售文案的写作、新媒体对文案传播的新要求、新媒体品-牌文案的写作,以及不同媒介的特征及发布形式;第三篇为新媒体文案相关技能补充,主要讲述的是策划能力。 《新媒体......一起来看看 《新媒体文案创作与传播》 这本书的介绍吧!