当我使用Chrome打开了一个网页,然后打开了开发者工具,然后在Console面板输入obj.name = 1;,按下回车后,执行这样一段赋值表达式。
- 在控制台会得到什么样的执行结果?
- 会带来什么副作用?
1. obj是null或undefined
var obj = null;
// var obj = undefined;
obj.name = 1;
表达式执行的结果值
- 抛出异常
副作用
- 抛出异常
2. obj是原始值或复合值 ? 复合值 >>> 对象自身或者原型链中的对象hasOwnProperty('name') ? false >>> 对象isExtensible ? false
'use strict';
var obj = {};
Object.preventExtensions(obj);
obj.name = 1;
表达式执行的结果值
- 严格模式下抛出异常
- 非严格模式下为1
副作用
- obj不会增加属性
3. obj是原始值或复合值 ? 复合值 >>> 对象自身或者原型链中的对象hasOwnProperty('name') ? false >>> 对象isExtensible ? true
var obj = {};
obj.name = 1;
表达式执行的结果值
1
副作用
- obj被添加了一个key值为name的值属性,属性描述为 {"value":1,"writable":true,"enumerable":true,"configurable":true}
4. obj是原始值或复合值 ? 复合值 >>> 对象自身或者原型链中的对象hasOwnProperty('name') ? true >>> 属性是存储器属性或值属性 ? 存储器属性 >>> 存储器属性设置了setter函数 ? false
var obj = Object.defineProperty({}, 'name', {
get(val) {
console.log('get value: ', val)
},
set: undefined,
})
obj.name = 1;
表达式执行的结果值
1
副作用
- 无副作用
5. obj是原始值或复合值 ? 复合值 >>> 对象自身或者原型链中的对象hasOwnProperty('name') ? true > 属性是存储器属性或值属性 ? 存储器属性 > 存储器属性设置了setter函数 ? true
var obj = {
set name(val) {
console.log('set value: ', val);
// throw new Error('error')
}
};
obj.name = 1;
表达式执行的结果值
1或抛出异常
副作用
- 取决于setter函数带来的副作用
6. obj是原始值或复合值 ? 复合值 >>> 对象自身或者原型链中的对象hasOwnProperty('name') ? true >>> 属性是存储器属性或值属性 ? 值属性 >>> 对象自身或原型链对象中的该属性是可写的 ? false >>> 原有属性是自身属性或是原型链中原型对象的 ?自身属性
// 'use strict';
var obj = Object.defineProperty({}, 'name', {
writable: false,
})
obj.name = 1;
表达式执行的结果值
- 严格模式下
抛出异常 - 非严格模式下为
1
副作用
- obj不会被添加属性
7. obj是原始值或复合值 ? 复合值 >>> 对象自身或者原型链中的对象hasOwnProperty('name') ? true >>> 属性是存储器属性或值属性 ? 值属性 >>> 对象自身或原型链对象中的该属性是可写的 ? false >>> 原有属性是自身属性或是原型链中原型对象的 ? 原型链对象对象中的属性
// 'use strict';
var objPrototype = Object.defineProperty({}, 'name', {
writable: false,
})
var obj = Object.create(objPrototype);
obj.name = 1;
表达式执行的结果值
- 严格模式下
抛出异常 - 非严格模式下为
1
副作用
- obj不会被添加属性
8. obj是原始值或复合值 ? 复合值 >>> 对象自身或者原型链中的对象hasOwnProperty('name') ? true >>> 属性是存储器属性或值属性 ? 值属性 >>> 对象自身或原型链对象中的该属性是可写的 ? true >>> 原有属性是自身属性或是原型链中原型对象的 ?自身属性
var obj = Object.defineProperty({}, 'name', {
writable: true,
value:10,
})
obj.name = 1;
表达式执行的结果值
1
副作用
- 修改obj对象key值为name的属性的属性描述的value值为1
9. obj是原始值或复合值 ? 复合值 >>> 对象自身或者原型链中的对象hasOwnProperty('name') ? true >>> 属性是存储器属性或值属性 ? 值属性 >>> 对象自身或原型链对象中的该属性是可写的 ? true >>> 原有属性是自身的或来自原型链中的原型对象 ?原型链中的原型对象
var objPrototype = Object.defineProperty({}, 'name', {
writable: true,
})
var obj = Object.create(objPrototype);
obj.name = 1;
表达式执行的结果值
1
副作用
- obj被添加了一个key值为name的值属性,属性描述为 {"value":1,"writable":true,"enumerable":true,"configurable":true}
对原始值的操作
- JavaScript中的原始值的类型有
string,number,boolean,bigint,symbol
假设obj是一个原始值,那么obj.name=1表达式执行的结果值的可能性。
返回1
var obj = 100;
obj.name = 1;
抛出异常
'use strict';
var obj = 100;
Object.defineProperty(Number.prototype, 'name', {
writable: false,
});
obj.name = 1;
表达式的副作用的可能性
无副作用
var obj = 100;
obj.name = 1;
来自setter函数的副作用
var obj = 1;
var nameCounter = 0;
Object.defineProperty(Number.prototype,'name',{
set(val){
console.log('set val: ',val);
nameCounter += 1;
}
});
obj.name = 1;
其他可能性参照上述obj是复合值的情况
其他情况
上述所表述的场景基本能涵盖大多数的应用场景,还有一种特殊情况是顶层对象拥有一个key值为obj的存储器属性
var rawObj = { _name:'rawObj' };
Object.defineProperty(window, 'obj', {
get() {
console.log('get rawObj');
return rawObj;
},
set(val) {
console.log('set value: ', val)
},
enumerable: true,
configurable: true,
});
obj.name = 1;
obj.name = 1的副作用是会令rawObj添加一个key值为name的值属性,属性描述为 {"value":1,"writable":true,"enumerable":true,"configurable":true}
obj是proxy的情况
var obj = new Proxy({}, {
get: function (target, propKey, receiver) {
console.log(`getting ${propKey}!`);
return Reflect.get(target, propKey, receiver);
},
set: function (target, propKey, value, receiver) {
console.log(`setting ${propKey}!`);
return Reflect.set(target, propKey, value, receiver);
}
});
obj.name = 1;