对象的深复制和浅复制
深复制: 在对象的json是安全的情况下,使用varnewObj=JSON.parse(JSON.stringify( someObj ) );
浅复制就是单纯的赋值即可,在es6中也可以使用Object.assign()方法,但是源对象的特殊性质就是通过Object.getOwnPropertyDescriptor()取到的,如writable将不会被保留。
对象的属性访问:
[[GET]] 一个对象的属性访问实际上对一个对象进行默认的内建 [[Get]] 操作,会 首先 检查对象,寻找一个拥有被请求的名称的属性,如果找到,就返回相应的值。如果没有找到就遍历[[Prototype]]链,如果还是没有找到就返回undefined.
引发的问题:如何区分返回undefined是对象的属性赋值了undefined还是没有找到该属性
Anwser: Object.prototype.hasOwnProperty.call(object,property) 返回true/false
或者使用in操作符,此时要注意属性的enumerable属性设置为false的将返回false.
如果直接使用object.hasOwnProperty()会导致遍历[[Prototype]]链,在不想遍历原型链只检查当前对象的情况下使用上述方法,而且不会由于对象的高层原型链为空发生异常。
注意事项:
in 和 hasOwnProperty(..) 区别于它们是否查询 [[Prototype]] 链,而 Object.keys(..) 和 Object.getOwnPropertyNames(..) 都 只 考察直接给定的对象。
for..in 循环迭代一个对象上(包括它的 [[Prototype]] 链)所有的可迭代属性。
对象的属性赋值:
[[Put]] 如果属性存在,[[Put]] 算法将会大致检查:
这个属性是访问器描述符吗? 如果是,而且是 setter,就调用 setter。
这个属性是 writable 为 false 数据描述符吗?如果是,在非 strict mode 下无声地失败,或者在 strict mode 下抛出 TypeError。
否则,像平常一样设置既存属性的值
引发的属性访问器描述符: setter, getter
编码规范,同时声明gtter和setter,避免不是期望的结果出现。比如只对属性进行的getter声明,然后强制返回一个值,此时即使对属性进行赋值操作也是没有意义的。
由一个对象赋值语句引发的反应: myObject.foo="bar";
1. 如果 myObject 对象已经直接拥有了普通的名为 foo 的数据访问器属性,那么这个赋值就和改变既存属性的值一样简单。
2. 如果属性名 foo 同时存在于 myObject 本身和从 myObject 开始的 [[Prototype]] 链的更高层,这样的情况称为 遮蔽。直接存在于 myObject 上的 foo 属性会 遮蔽 任何出现在链条高层的 foo 属性,因为 myObject.foo 查询总是在寻找链条最底层的 foo 属性。
3. 当 foo 不直接存在 于 myObject,但 存在 于 myObject 的 [[Prototype]] 链的更高层时:
3.1 如果一个普通的名为 foo 的数据访问属性在 [[Prototype]] 链的高层某处被找到,而且没有被标记为只读(writable:false),那么一个名为 foo 的新属性就直接添加到 myObject 上,形成一个 遮蔽属性。
3.2 如果一个 foo 在 [[Prototype]] 链的高层某处被找到,但是它被标记为 只读(writable:false) ,那么设置既存属性和在 myObject 上创建遮蔽属性都是 不允许 的。如果代码运行在 strict mode 下,一个错误会被抛出。否则,这个设置属性值的操作会被无声地忽略。不论怎样,没有发生遮蔽。
3.3 如果一个 foo 在 [[Prototype]] 链的高层某处被找到,而且它是一个 setter(见第三章),那么这个 setter 总是被调用。没有 foo 会被添加到(也就是遮蔽在)myObject 上,这个 foo setter 也不会被重定义。
一定要注意区分这三种情况。
未完待续。。。