-
Notifications
You must be signed in to change notification settings - Fork 52
读ES规范笔记
当将 Function 作为函数来调用,而不是作为构造器,它会创建并初始化一个新函数对象。所以函数调用 Function(…) 与用相同参数的 new Function(…) 表达式创建的对象相同。
Function (p1, p2, … , pn, body)
当以 p1, p2, … , pn, body 作为参数调用 Function 函数(这里的 n 可以是 0,也就是说没有“p”参数,这时还可以不提供 body),采用如下步骤:创建并返回一个新函数对象,它仿佛是用相同参数给标准内置构造器 Function (15.3.2.1). 用一个 new 表达式创建的。
笔记:由于Function和new Function的结果是完全一样的,所以,可以省略掉new 来创建一个Function对象
产生式 RelationalExpression : RelationalExpression in ShiftExpression 按照下面的过程执行 :
1. 令 lref 为解释执行 RelationalExpression 的结果 .
2. 令 lval 为 GetValue(lref).
3. 令 rref 为解释执行 ShiftExpression 的结果 .
4. 令 rval 为 GetValue(rref).
5. 如果 Type(rval) 不是 Object ,抛出一个 TypeError 异常 .
6. 返回以参数 ToString(lval). 调用 rval 的 `[[HasProperty]]` 内置方法的结果
关于[[HasProperty]]
:
这是一个所有对象(native object 和 host object)都要实现的属性
返回一个 Boolean 值,说明对象是否含有给定名称的属性。
笔记:可以看到,关于in操作符,并没有说可遍历属性的事儿,所以,in操作符是不管这个属性可不可遍历,不管这个属性是自有属性还是继承属性,都会被in操作符检索出来
function Person(name2){ this.name2 = name2};
function Student(id){ this.id = 123};
var p = new Person('李彦峰');
Object.defineProperty(p,'qq',{value:455322185});// 定义一个不可遍历属性age
Student.prototype = p // Student继承Person的一个实例
var s = new Student;
Object.defineProperty(s,'age',{value:23});// 定义一个不可遍历属性age
"name2" in s; // true
"age" in s; // true
"qq" in s; // true
Object返回该对象的默认值。(调用该对象的内部方法[[DefaultValue]]
一樣)。
[[DefaultValue]]
SpecOp (Hint) → primitive Hint 是一个字符串。返回对象的默认值
所有对象(包括宿主对象)必须实现表 8 中列出的所有内部属性。然而,对某些对象的 [[DefaultValue]]
内部方法,可以简单的抛出 TypeError 异常。
当用字符串 hint 调用 O 的 [[DefaultValue]]
内部方法,采用以下步骤:
令 toString 为用参数 "toString" 调用对象 O 的 [[Get]]
内部方法的结果。
如果 IsCallable(toString) 是 true,则
令 str 为用 O 作为 this 值,空参数列表调用 toString 的 [[Call]]
内部方法的结果。
如果 str 是原始值,返回 str。
令 valueOf 为用参数 "valueOf" 调用对象 O 的 [[Get]]
内部方法的结果。
如果 IsCallable(valueOf) 是 true,则
令 val 为用 O 作为 this 值,空参数列表调用 valueOf 的 [[Call]]
内部方法的结果。
如果 val 是原始值,返回 val。
抛出一个 TypeError 异常。
当用数字 hint 调用 O 的 [[DefaultValue]]
内部方法,采用以下步骤:
令 valueOf 为用参数 "valueOf" 调用对象 O 的 [[Get]]
内部方法的结果。
如果 IsCallable(valueOf) 是 true,则
令 val 为用 O 作为 this 值,空参数列表调用 valueOf 的 [[Call]]
内部方法的结果。
如果 val 是原始值,返回 val。
令 toString 为用参数 "toString" 调用对象 O 的 [[Get]]
内部方法的结果。
如果 IsCallable(toString) 是 true,则
令 str 为用 O 作为 this 值,空参数列表调用 toString 的 [[Call]]
内部方法的结果。
如果 str 是原始值,返回 str。
抛出一个 TypeError 异常。
当不用 hint 调用 O 的 [[DefaultValue]]
内部方法,O 是 Date 对象的情况下仿佛 hint 是字符串一样解释它的行为,除此之外仿佛 hint 是数字一样解释它的行为。
上面说明的 [[DefaultValue]]
在原生对象中只能返回原始值。如果一个宿主对象实现了它自身的 [[DefaultValue]]
内部方法,那么必须确保其 [[DefaultValue]]
内部方法只能返回原始值。
笔记:先计算
obj.valueOf()
,如果结果是原始值,则返回此结果;否则计算obj.toString()
,如果值是原始值,则返回此结果,否则抛出异常。 注:此处有个例外,即Date类型的对象,它会先调用toString()方法.
The addition operator either performs string concatenation or numeric addition.
产生式 AdditiveExpression : AdditiveExpression + MultiplicativeExpression 按照下面的过程执行 :
令 lref 为解释执行 AdditiveExpression 的结果 .
令 lval 为 GetValue(lref).
令 rref 为解释执行 MultiplicativeExpression 的结果 .
令 rval 为 GetValue(rref).
令 lprim 为 ToPrimitive(lval).
令 rprim 为 ToPrimitive(rval).
如果 Type(lprim) 为 String 或者 Type(rprim) 为 String,则:
返回由 ToString(lprim) 和 ToString(rprim) 连接而成的字符串
返回将加法运算作用于 ToNumber(lprim) 和 ToNumber(rprim) 的结果。参见 11.6.3 后的注解。
在步骤5和6中的ToPrimitive调用没有提供hint,除了Date对象之外所有ECMAScript对象将缺少hint的情况当做Number处理;Date对象将缺少hint的情况当做hint为字符串。宿主对象可能将缺少hint的情况当做别的处理。
步骤7与关系运算符比较算法中的步骤3不同,它使用逻辑或运算符而不是逻辑与运算符
组件 作用目的 词法环境组件 指定一个词法环境对象,用于解析该执行环境内的代码创建的标识符引用。 变量环境组件 指定一个词法环境对象,其环境数据用于保存由该执行环境内的代码通过 VariableStatement 和 FunctionDeclaration 创建的绑定。 this 绑定 指定该执行环境内的 ECMA 脚本代码中 this 关键字所关联的值。
词法环境由词法环境和变量环境组成,可以认为词法环境和变量环境为执行环境上的一个属性。
其中执行环境的词法环境组件和变量环境组件始终为词法环境对象。当创建一个执行环境时,其词法环境组件和变量环境组件最初是同一个值。在该执行环境相关联的代码的执行过程中,变量环境组件永远不变,而词法环境组件有可能改变。
在本标准中,通常情况下,只有正在运行的执行环境(执行环境栈里的最顶层对象)会被算法直接修改。因此当遇到“词法环境组件”、“变量环境组件”、“this 绑定组件”这三个术语时,指的是正在运行的执行环境的对应组件。
执行环境是一个纯粹的标准机制,并不代表任何 ECMA 脚本实现的工件。在 ECMA 脚本程序中是不可能访问到执行环境的。
规范描述:
从
[[prototype]]
对象继承来的命名数据属性(作为子对象的属性可见)是为了[[get]]
请求,但无法用户[[put]]
请求 命名访问器属性会把[[get]]
和[[put]]
都继承
解读:
这都规范的意思是:如果是数据属性,那么给对象赋值的话,会赋值到对象本身,而不会赋值到对象的原型链上的同名属性上去
如果是访问器属性,那么给对象赋值的话,会调用原型链上的set方法
代码验证:
var object = {};
var obj = Object.create(object);
Object.defineProperties(object,{
name: {
value: '李彦峰',
writable: true,
enumerable: true,
configurable: true
},
age: {
get: function(){
return this._age;
},
set: function(age){
console.log("[[put]]触发");
this._age = age;
},
enumerable: true,
configurable: true
}
});
console.log(obj);
console.group('测试数据属性');
console.log(Object.getOwnPropertyDescriptor(obj,'name'));
console.log(Object.getOwnPropertyDescriptor(object,'name'));
console.log(obj.name);
obj.name = '李燕山';
console.log(obj.name);
console.log(obj);
console.groupEnd('测试数据属性');
console.group('测试访问器属性');
console.log(Object.getOwnPropertyDescriptor(obj,'age'));
console.log(Object.getOwnPropertyDescriptor(object,'age'));
console.log(obj.age);
// 原来obj对象并没有age属性,给obj的age属性赋值的话
// 会调用obj对象的原型对象即object的age访问器属性的set方法
obj.age = 26;
console.log(obj.age);
console.log(obj);
console.groupEnd('测试访问器属性');