Javascript 面试题连等赋值 a.x = a = {n: 2}
var a = {n: 1}
var b = a;
a.n = a = {m: 2}
// 问a, b是什么?
这个题可能考察的知识点有以下几个
- Javascript中object属于哪种数据类型
- object类型数据的存储方式
- Javascript中运算符的优先级
- Javascript编译器关于赋值运算的知识
程序的运行过程核结果如下图
// a对象值{m:2}
// b对象值{n:{m:2}}
object类型属于数据类型中的引用类型
对象是 JavaScript 的基础。 在 JavaScript 中一共有六种主要类型(术语是“语言类型”) :
• string
• number
• boolean
• null
• undefined
• object
注意, 简单基本类型(string、 boolean、 number、 null 和 undefined) 本身并不是对象。
null 有时会被当作一种对象类型, 但是这其实只是语言本身的一个 bug, 即对 null 执行
typeof null 时会返回字符串 "object"。 1 实际上, null 本身是基本类型。
有一种常见的错误说法是“JavaScript 中万物皆是对象”, 这显然是错误的。
-- 《你不知道的JavaScript上卷》
我倾向于将数据类型理解成是对语言类型的分类,数据类型包括值类型和引用类型,Javascript中的语言类型string,number,boolean,undefined属于值类型,object属于引用类型。
object类型数据的存储方式
基于值类型的变量直接包含值。将一个值类型变量赋给另一个值类型变量时,将复制包含的值。这与引用类型变量的赋值不同,引用类型变量的赋值只复制对对象的引用,而不复制对象本身。上面这个问题中在执行var b = a之后,因为a和b都是引用类型的数据,Javascript引擎在执行代码时将在内存的堆区域创建对象,并在栈中创建a和b变量并指向此对象。所以对a或者b操作都将影响到彼此的值。Javascript中不同数据类型在内存中存储的介绍这里不再做过多介绍。有很多博客文章介绍这些概念。
Javascript中运算符的优先级
这个题目语句a.x = a = {m: 2}中出现了2个运算符,.和=,Javascript运算符的优先级.高于=,所以先计算a.x值为表达式a = {m: 2}的结果。
关于更多Javascript运算符的优先级,可以参考运算符优先级 中的表格
Javascript编译器关于赋值运算的知识
既然Javascript运算符的优先级.高于=,为什么a.x = a = {m: 2}中要先评估a = {m: 2}的值再赋值给a.x,而不是先执行a.x =a再执行a = {m:2}。
关于这一点,再次引用《你不知道的Javscript上卷中》关于编译器赋值部分的描述
因为Javascript编译器赋值运算中有查询RHS的存在,a.x必须要取到原值,而a并不是源值值,所以继续评估a = {m:2},此时编译器顺利取到了a = {m:2}的结果为{m:2},这是一个再堆中存在的源值。