标准应该称为JavaScript的LHS和RHS,含义是“赋值操作的左侧和右侧”,并不意味着就是“=赋值操作符的左侧和右侧”。例如console.log(a),对a进行的是RHS。
变量的LHS
严格模式下
示例1
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<title>变量的左查询</title>
</head>
<body>
属性的查询测试
</body>
<script>
'use strict'
var x = 'windowx'
function hello() {
x = 'hellox'; // 修改的是window里面的x属性,需要查询作用域链,最终找到windows下有x变量
function hi() {
console.log(x); // 需要查询作用域链,找不到报异常。
}
hi()
}
hello()
</script>
</html>
示例2
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<title>变量的左查询</title>
</head>
<body>
属性的查询测试
</body>
<script>
'use strict'
function hello() {
x = 'hellox'; // 从作用域链中查找属性,左查询严格模式下找不到报异常。
}
hello()
</script>
</html>
示例3
var x = 'hellox'
// 等价于
var x
x = 'hellox'
小结
在严格模式下,LHS沿着作用域链查询变量。如果查询不到将会抛出错误。其中var x = 'hellox'即进行了声明,也进行了左查询。
非严格模式下
示例1
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<title>变量的左查询</title>
</head>
<body>
属性的查询测试
</body>
<script>
var x = 'windowx'
function hello() {
x = 'hellox'; // hellox 在window下
var y = 'helloy'; // helloy 在hello下
function hi() {
// 非严格模式下左查询查不到,在作用域链最后一个作用域处添加该属性。
z = 'hiz' // hiz 在window下
}
hi()
}
hello()
</script>
</html>
小结
非严格模式下左查询查不到,在作用域链最后一个作用域处添加该属性。
变量的RHS
无论在严格模式还是非严格模式下都是沿着作用域链查找,找不到都抛出异常Uncaught ReferenceError。
属性的LHS
示例1
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<title>属性的设置</title>
</head>
<body>
属性的设置
</body>
<script>
// 'use strict' // 这里无论是否注释,输出的都是'调用了set'
function hello() {
}
Object.defineProperty(hello.prototype, 'x', {
get: function () {
return 'getx';
},
set: function (value) {
console.log('调用了set');
}
});
var hi = new hello();
/**
* 下面代码是属性的设置
*/
hi.x = 'hix'; // 调用了set 无论是否使用严格模式,在原型链上存在该属性,都将会调用setter。
</script>
</html>
示例2
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<title>属性的设置</title>
</head>
<body>
属性的设置
</body>
<script>
'use strict' // 这段代码目前运行在严格模式下,控制台报错。如果注释掉'use strict',控制台不会报错,js引擎自动忽略 hi.y = 'hiy'
function hello() {
}
Object.defineProperty(hello.prototype, 'x', {
value: 'x',
writable: true,
});
Object.defineProperty(hello.prototype, 'y', {
value: 'y',
writable: false
});
var hi = new hello();
/**
* 属性的设置,向上查询原型链
*/
hi.x = 'hix'; // 如果是可写的,那么赋值过程无任何异样
hi.y = 'hiy'; // Cannot assign to read only property 'y' of object '#<hello>' 如果该段代码运行在非严格模式下将会被忽略
</script>
</html>
小结
严格模式下当前作用域链不存在该属性,原型链上的同名属性且该属性writable:false,则为objct.x赋值,会抛出错误。
非严格模式下当前作用域链不存在该属性,原型链上的同名属性且该属性writable:false,则为objct.x赋值,不会抛出错误,js引擎自动忽略该赋值操作。
无论在严格模式或者非严格模式下,当前作用域不存在该属性,原型链上存在同名属性,调用同名属性的setter。
属性的RHS
无论在严格模式还是非严格模式下都是沿着原型链查找,找不到都抛出异常。
总结
| 变量的查询 | ||
|---|---|---|
| 严格模式 | 非严格模式 | |
| 声明 var x; | 在当前作用域中添加该属性 | 同严格模式 |
| LHS x = value | 作用域链中查找:找不到,报异常 | 找不到,在查找作用域链的顶层作用域添加该属性 |
| RHS x | 作用域链中查找:找不到报异常 | 同严格模式 |
| 属性的查询 | ||
|---|---|---|
| 严格模式 | 非严格模式 | |
LHS:objct.x = value,object是使用变量LHS查询,x是属性查找,后面如果仍然有’.’仍然是按照属性去找 | 当前作用域不存在该属性,原型链上的同名属性writable:false,则为objct.x赋值,将抛出错误。 | 当前作用域不存在该属性,原型链上的同名属性writable:false。Js引擎忽略这条赋值语句。 |
| 当前作用域不存在该属性,原型链上存在同名属性,调用同名属性的setter | 同严格模式 | |
RHS:object.x,object是变量RHS,x是属性查找,后面如果仍然有’.’仍然是按照属性去找 | 原型链查找,找不到,报异常 | 同严格模式 |