• Smallfly
    2020-02-08
    1. [] 的求值过程

    一开始没明白题目的意思,看到留言区的提示才理解,题目考察的是 JS 的类型转换,[] 属于对象类型,对象类型到值类型的转换过程是什么样的?

    对象转值类型的规范过程称为:ToPrimitive

    分为三个步骤:

    1. 判断对象是否实现 [Symbol.toPrimitive] 属性,如果实现调用它,并判断返回值是否为值类型,如果不是,执行下一步。
    2. 如果转换类型为 string,依次尝试调用 toString() 和 valueOf() 方法,如果 toString() 存在,并正确返回值类型就不会执行 valueOf()。
    3. 如果转换类型为 number/default,依次尝试调用 valueOf() 和 toString(),如果 valueOf() 存在,并正确返回值类型就不会执行 toString()。

    数组默认没有实现 [Symbol.toPrimitive] 属性,因此需要考察 2、3 两步。

    [] + ’‘ 表达式为 string 转换,会触发调用 toString() 方法,结果为空字符,等价于 ’’ + ‘’ 结果为 ‘’。
    +[] 表达式是 number 转换,会先触发调用 valueOf() 方法,该方法返回的是空数组本身,它不属于值类型,因此会再尝试调用 toString() 方法,返回空字符,+‘’ 结果为 0;

    展开

    作者回复: 加分加分。呵呵~ ^^.

    
     1
  • 青史成灰
    2020-01-12
    老师,关于这句话有个疑问:“这个包装的过程发生于函数调用运算“( )”的处理过程中,或者将“x.toString”作为整体来处理的过程中。也就是说,仅仅是“对象属性存取”这个行为本身,并不会触发一个普通“值类型数据”向它的包装类型转换”

    只是前半句好理解,但是后半句“对象属性存取这个行为本身”,这个对象是发生包装转化后的对象吗?如果是,那怎么感觉就变成了“先有鸡还是先有蛋”的问题了。。。如果不是,那么原始类型不存在属性存取这一说法啊

    作者回复: 关键确实就在“对象属性存取这个行为本身”。

    原始类型(中的值类型)的对象属性存取行为,例如“`true.toString`”会发生什么呢?它仍然是一次有效的属性存取,但它的结果(Result)并不会被立即求值。之前我们说过了,必须等到决定它是作为rhs/lhs之后,才能确定它是用来“求值”,还是只是“作为一个引用”,对不对?

    那么,当得到操作`true.toString`的结果(Result)之后,在决定下一个可能的操作之前,它是一个什么状态呢?——这种情况下,它是作为一个“引用(规范类型)”来传递的。考虑到“引用(规范类型)”作为一个原始语言(例如C)中的结构/记录类型,那么它的ref.base域存放的,将是“值true”,而ref.name域中存放的,将是属性名“toString”。

    所以你看,在这个阶段中,“包装(boxing)”这个行其实并没有发生。true还是true值,并没有“变成”Object(true),对不对?

    所以说,确实存在一个“将对象属性存取这个行为(的结果)——作为一个整体”的阶段,这个存取行为并没有发生包装。但是,如果如下发生后一步的行为(也就是“作为整体来处理的过程中),那么,“包装”就会发生了。例如,GetValue(ref),那么就会先将ref.base中的值转换成对象;又例如,true.toString(),就会先将ref.true转换为对象然后作为this值传入toString()。

    所以,“包装(亦即是‘转换为对象’)”这个行为,其实是发生在`GetValue()这个内部操作`或`()这个运算符`等等这样的运算过程中的。

    所以回到最开始的,总之,“对象属性存取”这个行为本身,就是还没有触发“包装”。但它得到了包装要用的材料,亦即是ref.base和ref.name,不过还得需要“下一步”的具体操作,才能决定“包装是否会发生”。

    
    
  • Elmer
    2020-01-03
    我觉得两题的本质都是再说对象如何转换为值类型。[]的求值过程在于[]所处的表达式环境需要number还是string,然后执行array.prototype上对应的方法转换。 题二中+-*/都是需要number,所以只要不出现0/0的情况即可。

    作者回复: 题二其实是没有标准答案的。不过多做一点提示,就是+/-其实也是一正值和负值运算符,不一定非得当成加减号来用。正值和负值运算符一样也会导致类型转换。

    
    
  • kittyE
    2019-12-13
    1. 我理解,[] 作为单值表达式,要GetValue(v),但为啥结果是 [],不太明白,ecma关于GetValue的描述,感觉好复杂。
    2. []*[]/++[[]][+[]]-[+[]] 我随便写了一个 还真的能有值,不知道这样理解对不对,求老师解惑

    作者回复: 第2题你的理解是对的,不过表达式可以再简一些。^^.
    关于第一个问题,思考方向不是GetValue,而是toPrimitive。还有,它的结果不是[],它的求值结果是0。

    
    
  • Astrogladiator-埃蒂...
    2019-12-11
    试述表达式[]的求值过程。
    对照http://www.ecma-international.org/ecma-262/5.1/#sec-9.1
    http://www.ecma-international.org/ecma-262/5.1/#sec-8.12.8
    step1: []不是一个原始类型,需要转化成原始类型求值
    step2: 这个隐式转换是通过宿主对象中的[[DefaultValue]]方法来获取默认值
    step3: 一般在没有指定preferredType的情况下,会隐式转换为number类型的默认值
    step4: []默认值为0

    可以这么理解?这个preferredType在什么设置?

    在上述表达式中加上符号“+-*/”并确保结果可作为表达式求值。
    这个是不是只要保证表达式中是对象或者number类型或者设置了preferredType的其他l类型(除了null, undefined, NaN)
    展开

    作者回复: 第1个问题, 这样解释是不对的。[[DefaultValue]]是用在那些值类型的包装对象上的,例如5和new Number(5)之间的关系。而preferredType是另外一个问题,涉及JavaScript对“预期转换目标类型”的管理,不同的运算之间还不同(但都与具体的运算操作有关),与当前这个问题却没有太大的关系。

    第2个问题的意思,是如何使一个表达式里面只出现“+-*/”和"[]",并且表达式还可以通过语法检测并计算求值。

    
    
  • 许童童
    2019-12-11
    老师讲得非常好,JavaScript中的面向对象设计确实很独特,早期我们还称其为基于对象,不过随着我们对JavaScript了解的深入,现在都已经改口了。对象存取的结果是面向对象运行时中结果的体现,如果属性不是自有的,就由原型决定,如果属性是存取方法,就由方法求值决定。另外,属性描述符有两种主要形式:数据描述符和存取描述符。
    
    
我们在线,来聊聊吧