New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
ES规范解读之赋值操作符&属性访问器 #24
Comments
我来水一发 |
只水不star都是耍流氓 @ynCode |
Nice Post. |
@codezyc thx |
Simple Assignment 中的第一步的 Evaluate LeftHandSideExpression 一直不太明白 let foo
foo = 'hello' 在上面这个例子中,Evaluate LeftHandSideExpression 的结果不是 |
@mage3k Evaluate 操作并不取值,只是拿到表达式,只有执行了 GetValue 才会取值 |
@kuitos 感谢回复。最近被网上那个连续赋值问题弄的有点困惑,网上也有不少分析文章的,但是都没有从规范上讲通的。这几天一直在看规范,从赋值到属性访问到引用,总算是明白了。这篇文章在这个过程中起了很大的作用。🙏 |
@kuitos 如果 Evaluate 不取值的话, |
你的例子里,Result(1) 就是 |
那 |
@mage3k 不是,你可以理解成它们的 Reference |
@kuitos 你说的
如果都是是规范里的 |
规范现在读起来还是有点吃力 |
ES规范解读之赋值操作符&属性访问器
事情起源于某天某妹子同事在看angular文档中关于Scope的说明Understanding Scopes(原文) 理解angular作用域(译文)时,对于文章中的例子有一点不理解,那个例子抽离细节之后大致是这样的:
当我们访问scopeInstance上的属性时,假如scopeInstance上不存在该属性,则js解释器会从原型链上一层层往上找,直到找到有该属性,否则返回undefined。
而当我们往scopeInstance上某一属性设值时,它并不会触发原型链查找,而是直接给对象自身设值,如果对象上没有该属性则创建一个该属性。
总结起来,关于对象的属性的set和get操作看上去有这样一些特性:
没错,这是最基本的原型链机制,我以前一直是这么理解的,然后我也是这么跟妹子解释的,然而文章后面的例子打了我脸。。。例子大致是这样的:
WTF!!!
按照我的理解,写操作跟原型链无关,在对象自身操作。
顺着这个思路,那么
scope2.array[1]=1
这行代码压根就会报错啊,因为scope2在创建array属性之前压根就没有自身的array属性啊!可是它竟然没报错还把Scope.prototype给改了!于是我又在想,是不是这种引用类型(array,object)都会触发原型链查找,所以会出现这个结果?
然而我又想起前面那段代码:
这下彻底斯巴达了😂
从表象来看,
scopeInstance.array[1]
的读写操作都会触发原型链查找,而为啥scopeInstance.array
的写操作就不会触发。如果说引用类型都会触发,那么scopeInstace.array=[]
就等价于Scope.prototype.array = []
,但是事实并不是这样。。。碰到这种时候我只有祭出神器了(ecmascript),google什么的绝对不好使相信我。
翻到ecmascript关于赋值操作符那一小节,es是这样描述的
Simple Assignment (= )
前面三步都知道,关键点在第四步,
PutValue(Result(1), Result(3))
我们再来看看PutValue干了啥
PutValue(V, W)
第二步有一个
GetBase(V)
操作,然后第四步依赖第二步的计算结果做最终赋值。那么
GetBase(V)
究竟做了什么呢(V即我们赋值操作时候的左值)GetBase(V)
翻译下来就是:返回引用V的基础对象组件。
那么什么是
基础对象组件
呢,举两个例子:我们再来看看属性访问器(Property Accessors),就是括号
[]
操作符及点号.
操作符都做了什么属性访问器(Property Accessors)
也就是说括号跟点号对解释器而言是一样的。
跟到
GetValue
GetValue(V)
第四步的私有方法[[Get]]是关键:
[[Get]]
意思很明显,
[[Get]]
会触发原型链查找.我们再回到赋值操作符的
PutValue
操作,走到第四步这里的
Result(2)
就是GetBase(V)
的结果,拿上面的例子也就是GetBase(this.array[2]) == this.array
再看看
[[Put]]
操作干了什么事情:[[Put]]
很简单,就是给对象o的属性P赋值时,o存在属性P就直接覆盖,没有就新建属性。此时无关原型链。
此时再结合我们自己的案例来看,
scopeInstance.array[1]=2
跟scopeInstance.array=[]
究竟都干了啥(忽略不相关细节):scopeInstance.array[1]=2
scopeInstance.array=[]
完美解释所有现象!
如果思考的比较深入的同学可能会问,scopeInstance又从哪儿取来的呢?也是类似原型链这样一层层往上查出来的么?这涉及到另一点知识,js中的作用域,具体可以看我的另一篇文章一道js面试题引发的思考
The text was updated successfully, but these errors were encountered: