变量和类型
JavaScript
规定了几种语言类型
Undefined
Null
Boolean
String
Number
Symbol
Object
为什么有的编程规范要求用 void 0 代替 undefined?
undefined
是全局对象的一个属性,也就是说,它是全局作用域中的一个变量,undefined的最初值就是原始数据类型undefined
。ES5之后的标准中,规定了全局变量下的undefined
值为只读,不可改写的,但是局部变量中依然可以对之进行改写。而void 0
无论什么时候都是返回undefined
,这样来看,使用void 0
来代替undefined
就比较稳妥,不会出错
1 | console.log(window.undefined == void 0); // true |
JavaScript
对象的底层数据结构是什么
js基本类型数据都是直接按值存储在栈中的(Undefined、Null、不是new出来的布尔、数字和字符串),每种类型的数据占用的内存空间的大小是确定的,并由系统自动分配和自动释放。这样带来的好处就是,内存可以及时得到回收,相对于堆来说,更加容易管理内存空间。
js引用类型数据被存储于堆中 (如对象、数组、函数等,它们是通过拷贝和new出来的)。其实,说存储于堆中,也不太准确,因为,引用类型的数据的地址指针是存储于栈中的,当我们想要访问引用类型的值的时候,需要先从栈中获得对象的地址指针,然后,在通过地址指针找到堆中的所需要的数据
参考资料:再谈js对象数据结构底层实现原理
Symbol
类型在实际开发中的应用、可手动实现一个简单的Symbol
ES6
引入了一种新的原始数据类型 Symbol
,表示独一无二的值。
symbol
类型的 key
不能被 Object.keys
和 for..of
循环枚举。因此可当作私有变量使用。
1 | let mySymbol = Symbol('key'); |
完整实现:
1 | (function() { |
参考资料: ES6 系列之模拟实现 Symbol 类型
JavaScript
中的变量在内存中的具体存储形式
JavaScript 中的变量分为基本类型和引用类型:
基本类型: 保存在栈内存中的简单数据段,它们的值都有固定的大小,保存在栈空间,通过按值访问
引用类型: 保存在堆内存中的对象,值大小不固定,栈内存中存放的该对象的访问地址指向堆内存中的对象,JavaScript 不允许直接访问堆内存中的位置,因此操作对象时,实际操作对象的引用
基本类型对应的内置对象,以及他们之间的装箱拆箱操作
String()
, Number()
, Boolean()
装箱:就是把基本类型转变为对应的对象。装箱分为隐式和显示
1 | // 隐式装箱: 每当读取一个基本类型的值时,后台会创建一个该基本类型所对应的对象。 |
拆箱: 拆箱与装箱相反,把对象转变为基本类型的值。
1 | Number([1]); //1 |
null
和undefined
的区别
Number
转换的值不同,Number(null)
输出为 0
, Number(undefined)
输出为 NaN
null
表示一个值被定义了,但是这个值是空值undefined
表示缺少值,即此处应该有值,但是还没有定义
typeof 结果不同
1 | typeof undefined // "undefined" |
至少可以说出三种判断JavaScript数据类型的方式,以及他们的优缺点,如何准确的判断数组类型
1.typeof
—— 返回给定变量的数据类型,可能返回如下字符串:
1 | 'undefined'——Undefined |
2.instanceof
检测 constructor.prototype
是否存在于参数 object
的原型链上,是则返回 true
,不是则返回 false
。
1 | alert([1,2,3] instanceof Array) // true |
3.constructor
—— 返回对象对应的构造函数。
1 | alert({}.constructor === Object); => true |
4.Object.prototype.toString()
默认返回当前对象的 [[Class]]
。这是一个内部属性,其格式为 [object Xxx]
,是一个字符串,其中 Xxx
就是对象的类型。
1 | Object.prototype.toString.call(new Date);//[object Date] |
优缺点 | typeof | instanceof | constructor | Object.prototype.toString.call |
---|---|---|---|---|
优点 | 使用简单 | 能检测出引用类型 | 基本能检测所有的类型(除了null和undefined) | 检测出所有的类型 |
缺点 | 只能检测出基本类型(除了null) | 不能检测出基本类型,且不能跨iframe | constructor易被修改,也不能跨iframe | IE6下,undefined和null均为Object |
可能发生隐式类型转换的场景以及转换原则,应如何避免或巧妙应用
一、数字运算符
做+
操作时,数字被隐式转换成字符串,实际上做的是字符串连接操作。
做除了加法以外的运算操作时,字符串被隐式转换成数字,实际上做的是数值计算。
二、.
点号操作符
数字、字符串等直接量在做.操作调用方法时,隐式地将类型转换成对象。
三、if
语句
if()括号里的表达式部分会被隐式转化为布尔类型进行判别。null
,""
,undefinded
, 0
, false
都会被转化为 false
四、==
等号-object array map set
参数 | 结果 |
---|---|
undefined | “undefined” |
null | “null” |
boolean | “true” 或者 “false” |
number | 数字作为字符串。比如,”1.765” |
string | 无需转换 |
[] | “” |
[5,2] | “5,2” |
{} | “[object Object]” |
Symbol() | “Symbol()” |
出现小数精度丢失的原因,JavaScript
可以存储的最大数字、最大安全数字,JavaScript
处理大数字的方法、避免精度丢失的方法
1.精度丢失原因,说是 JavaScript
使用了 IEEE 754
规范,二进制储存十进制的小数时不能完整的表示小数
2.能够表示的最大数字 Number.MAX_VALUE
等于 1.7976931348623157e+308
,最大安全数字 Number.MAX_SAFE_INTEGER
等于 9007199254740991
3.处理大数字: BigNumber
4.避免精度丢失: 把小数放到位整数(乘倍数),再缩小回原来倍数(除倍数)
参考资料:js数字位数太大导致参数精度丢失问题