面试的时候,一开始第一二个问题都比较深入浅出,一般会有JS数据类型有哪些从而引出一系列的问题...... 举例如下(后续遇到相关的会相应补充)
- null和undefined有什么区别,判空时需要注意哪些?
- typeof null为什么是Object?用什么检测null值类型?
- ES6为什么要提出Symbol(符号)?
- ES6为什么要提出BigInt?
- 如何检测数据类型?有什么区别?优点和缺点是什么?
- 比较操作符有什么?==,===,Object.is()有什么区别
- 如何判断一个对象是空对象?
- const对象属性可以修改吗?
- 0.1+0.2!==0.3?如何解决?
1、null和undefined有什么区别,判空时需要注意哪些?
两者都是基础数据类型:undefined代表含义是未定义,null代表含义是空对象
undefined == null // true
undefined === null //false
null是一个表示”无”的对象,转为数值时为0;undefined是一个表示”无”的原始值,转为数值时为NaN。 当声明的变量还未被初始化时,变量的默认值为undefined。 null用来表示尚未存在的对象,常用来表示函数企图返回一个不存在的对象。
undefined表示”缺少值”,就是此处应该有一个值,但是还没有定义。典型用法是:
- 变量被声明了,但没有赋值时,就等于undefined。
- 调用函数时,应该提供的参数没有提供,该参数等于undefined。
- 对象没有赋值的属性,该属性的值为undefined。
- 函数没有返回值时,默认返回undefined。
null表示”没有对象”,即该处不应该有值。典型用法是:
- 作为函数的参数,表示该函数的参数不是对象。
- 作为对象原型链的终点。
2、typeof null为什么是Object?用什么检测null值类型?
- JS红宝书:因为特殊值null被认为是一个对空对象的引用
- 在JS最初版本中 用
32
位表示一个变量,其中前3
位用于表示值的类型。000
表示对象,010
表示浮点数,100
表示字符串,110
表示布尔值。其他都被认为是指针。在这种表示发下,null
的机器码标识为全0
,被解释为全0
指针,前3
位都是0
所以被认为是空对象引用.
使用复合条件来检测 null 值的类型:
var a = null;
(!a && typeof a === "object"); // true
3、ES6为什么要提出Symbol(符号)?
- Symbol是原始数据类型 实例是唯一的不可变的
- 作用:确保对象属性使用唯一标识符 不会发生属性冲突的危险
var sym1 = Symbol('qwer')
var sym2 = Symbol('qwer')
sym1 == sym2 // false
4、ES6为什么要提出BigInt?
BigInt是新的原始数据类型,用于表示更发的整数,也可以在整数后面添加后缀 n 来将其转换为 BigInt。
const big1 = BigInt(12345678901234567890);
const big2 = 9876543210987654321n;
为什么要BigInt? JavaScript 中Number.MAX_SAFE_INTEGER 表示最⼤安全数字,计算结果是 9007199254740991,即在这个数范围内不会出现精度丢失(⼩数除外)。但是⼀旦超过这个范围,js 就会出现计算不准确的情况,这在⼤数计算的时候不得不依靠⼀些第三⽅库进⾏解决,因此官⽅提出了 BigInt 来解决此问题
5、如何检测数据类型?有什么区别?优点和缺点是什么?
方法 | 原理区别 |
---|---|
typeof | 可以准确检测原始数据类型 但是判断不了复杂数据类型【Array Function】 |
instanceof | 可以转缺判断复杂数据类型 但不能判断原始数据类型 |
constructor | 无法检测null和undefined 【实例对象通过constructor访问其构造函数】 |
Object.prototype.toString.call() | 都可以检测到 【Object对象原型方法toString()判断数据类型】 |
/**
* typeof
* 对于对象,数组,null都被认为object 其他判断都正确
*/
typeof 1 //'number'
typeof true //'boolean'
typeof 'ddd' //'string'
sym1 = Symbol('jkj')
typeof sym1 //'symbol'
typeof [] //'object'
typeof {} //'object'
typeof function(){} //'function'
typeof undefined //'undefined'
typeof null //'object'
/**
* instanceof 判别不了基础数据类型 能判断对象数据类型
*/
2 instanceof Number //false
true instanceof Boolean //false
'ertt' instanceof String //false
[] instanceof Array //true
{} instanceof Object // Uncaught SyntaxError: Unexpected token 'instanceof'
({}) instanceof Object //true
function(){} instanceof Function //Uncaught SyntaxError: Function statements require a function name
(function(){}) instanceof Function //true
null instanceof null //Uncaught TypeError: Right-hand side of 'instanceof' is not an object
undefined instanceof undefined //Uncaught TypeError: Right-hand side of 'instanceof' is not an object
/**
* constructor
* 有两个作用:
* (1)判断数据的类型
* (2)对象实例通过constructor对象访问它的构造函数
* 如果创建一个新对象来改变它的原型 则不生效
*/
(2).constructor === Number //true
('abc').constructor === String //true
(true).constructor === Boolean //true
([]).constructor === Array //true
({}).constructor === Object //true
(function(){}).constructor === Function //true
// 如果创建一个新对象来改变它的原型 则不生效
function Fn(){}
Fn.prototype = new Array()
var f = new Fn()
console.log(f.constructor == Function); // false
console.log(f.constructor == Array); // true
/**
* Object.prototype.toString.call() 【最理想】
* 调用Object 原型上的toString 方法。
* 使用Object 对象的原型方法toString 来判断数据类型:
*/
Object.prototype.toString.call(2) //'[object Number]'
Object.prototype.toString.call('www') //'[object String]'
Object.prototype.toString.call(false) //'[object Boolean]'
Object.prototype.toString.call({}) //'[object Object]'
Object.prototype.toString.call([]) //'[object Array]'
Object.prototype.toString.call(function(){}) //'[object Function]'
Object.prototype.toString.call(null) //'[object Null]'
Object.prototype.toString.call(undefined) //'[object Undefined]'
Object.prototype.toString.call(123456789012345678901234567890n) //'[object BigInt]'
Object.prototype.toString.call(Symbol('id')) //'[object Symbol]'
6、比较操作符有什么?==,===,Object.is()有什么区别
比较操作符 | 作用 |
---|---|
== | 值不相同会强制类型转换再比较 |
=== | 不会强制类型转换比较 |
Object.is() | 和===大致一样 但他能解决特殊问题 -0和+0 NaN和NaN的特殊比较 |
-0 == +0 //true
-0 === +0 //true
Object.is(-0,+0) //false
NaN == NaN //false
NaN === NaN //false
Object.is(NaN,NaN) //true
7、如何判断一个对象是空对象?
function isObj(params){
if(JSON.stringify(params) == '{}') return true
return false
}
function isObj(params){
// es6新增方法 Object.keys
// 遍历对象 返回对象中的每一项key的数组
if(Object.keys(params).length <=0) return true
return false
}
8、const对象属性可以修改吗?
- const保证的并不是变量的值不能动,而是变量指向的那个内存地址不能动。
- 对于基本类型的数据(数值,字符串,布尔值),它们的值都保存在变量指向的那个指针地址,因此等同于常量。
- 但对于引用类型的数据(对象,数组),变量指向数据的内存地址,保存的只是一个指针,const只能保证这个指针固定不变,至于它指向的数据结构是不是可变,就完全不能控制
PS: 想将对象冻结,应该使用Object.freeze
方法
const user = {
age:15,
name:'小明'
}
user.age = 16
//此时 age已经更改为16 user为 {age: 16, name: '小明'}
Object.freeze(user) // 冻结
user.age = 12 // 更改不了,user依然为 {age: 16, name: '小明'}
9、0.1+0.2!==0.3?如何解决?
0.1 + 0.2 === 0.3; // false
从数学角度来说,上面的条件判断应该为 true,可结果为什么是 false 呢? 简单来说,二进制浮点数中的 0.1 和 0.2 并不是十分精确,它们相加的结果并非刚好等于 0.3,而是一个比较接近的数字 0.30000000000000004,所以条件判断结果为 false。
那么应该怎样来判断 0.1 + 0.2 和 0.3 是否相等呢?
(1)最常见的方法是设置一个误差范围值,通常称为“机器精度”(machine epsilon),对 JavaScript 的数字来说,这个值通常是 2^-52 (2.220446049250313e-16)。
从 ES6 开始,该值定义在 Number.EPSILON 中,我们可以直接拿来用,也可以为 ES6 之前 的版本写 polyfill:
if (!Number.EPSILON) {
Number.EPSILON = Math.pow(2,-52);
}
可以使用 Number.EPSILON 来比较两个数字是否相等(在指定的误差范围内):
function numbersCloseEnoughToEqual(n1,n2) {
return Math.abs( n1 - n2 ) < Number.EPSILON;
}
var a = 0.1 + 0.2;
var b = 0.3;
numbersCloseEnoughToEqual( a, b ); // true
numbersCloseEnoughToEqual( 0.0000001, 0.0000002 ); // false
能够呈现的最大浮点数大约是 1.798e+308(这是一个相当大的数字),它定义在 Number. MAX_VALUE 中。最小浮点数定义在 Number.MIN_VALUE 中,大约是 5e-324,它不是负数,但 无限接近于 0 !
参考博客和书籍:
《你不知道的JavaScript中卷》 《JavaScript红宝书第四版》