前端面试JS自检(一)数据类型 先看问题 自己自述一遍 不会再看答案 )

推荐大家的使用本篇文章的方式:
先看问题自己会不会,如果会的话,要自己说一遍,组织好语言。

一. 数据类型

1. JS数据类型的种类

总共7钟。

  • Undefined 未定义
    表示变量不含有任何值,是未定义的状态。

  • NULL 空

  • Boolean 布尔值

  • Number 数字

  • String 字符串

  • Object 对象
    分三个子类型 object、array、function

  • Symbol 符号 (es6新加)

类型
分为两种,基本数据类型(number boolean string symbol)和引用数据类型(object 比如:array、function、data)。

两种类型的区别在于存储位置的不同:
基本数据类型直接存储在(stack)中的简单数据段,占据空间小、大小固定,属于被频繁使用数据,所以放入栈中存储;
引用数据类型存储在(heap)中的对象,占据空间大、大小不固定。如果存储在栈中,将会影响程序运行的性能;引用数据类型在栈中存储了指针,该指针指向堆中该实体的起始地址。当解释器寻找引用值时,会首先检索其在栈中的地址,取得地址后从堆中获得实体。

2. undefined && null

null与undefined都可以表示“没有”,含义非常相似。将一个变量赋值为undefined或null,老实说,语法效果几乎没区别。

undefined == null //返回true
undefined === null //返回false
Number(null) //0
Number(undefined) //NaN 
console.log(typeof undefined)// undefined
console.log(typeof null)// object

undefined 代表的含义是未定义,null 代表的含义是空对象。一般变量声明了但还没有定义的时候会返回 undefined,null主要用于赋值给一些可能会返回对象的变量,作为初始化。

// 变量声明了,但没有赋值
var i;
i // undefined

// 调用函数时,应该提供的参数没有提供,该参数等于 undefined
function f(x) {
    
    
  return x;
}
f() // undefined

// 对象没有赋值的属性
var  o = new Object();
o.p // undefined

// 函数没有返回值时,默认返回 undefined
function f() {
    
    }
f() // undefined

3. 数据类型的检测方式

  • typeof

会把array和null都判断为object,其余都判断正确

console.log(typeof 2); // number
console.log(typeof true); // boolean
console.log(typeof 'str'); // string
console.log(typeof function(){
    
    }); // function
console.log(typeof {
    
    }); // object
console.log(typeof []); // object
console.log(typeof null); // object
console.log(typeof undefined); //undefined 
typeof NaN; // "number"

可以利用tyepeof undefined这一点就用来检查一个没有声明的变量而不报错。

typeof array返回object:
这表示在 JavaScript 内部,数组本质上只是一种特殊的对象

typeof null返回object:
这是由于历史原因造成的。1995年的 JavaScript 语言第一版,只设计了五种数据类型(对象、整数、浮点数、字符串和布尔值),没考虑null,只把它当作object的一种特殊值。后来null独立出来,作为一种单独的数据类型,为了兼容以前的代码,typeof null返回object就没法改变了。

  • instanceof
    返回一个布尔值,表示对象是否为某个构造函数的实例。左边是实例对象,右边是构造函数。可区分数组和对象只能判断引用数据类型,不能判断基本数据类型。运行机制是判断在其原型链中能否找到该类型的原型,所以还是会将数组判定成Object类型。
    console.log(2 instanceof Number); // false
    console.log(true instanceof Boolean); // false
    console.log('str' instanceof String); // false
    console.log([] instanceof Array); // true
    console.log([] instanceof Object); // true
    console.log(null instanceof Object); // false
    console.log(function(){
    
    } instanceof Function); // true
    console.log({
    
    } instanceof Object); //true

利用instanceof运算符,还可以巧妙地解决,调用构造函数时,忘了加new命令的问题

function Fubar (foo, bar) {
    
    
  if (this instanceof Fubar) {
    
    
    this._foo = foo;
    this._bar = bar;
  } else {
    
    
    return new Fubar(foo, bar);
  }
}

上面代码使用instanceof运算符,在函数体内部判断this关键字是否为构造函数Fubar的实例。如果不是,就表明忘了加new命令。

  • constructor
    有两个作用,一是判断数据的类型,二是对象实例通过constrcutor对象访问它的构造函数。需要注意,如果创建一个对象来改变它的原型,constructor 就不能来判断数据类型了。
    console.log((2).constructor === Number); // true
    console.log((true).constructor === Boolean); // true
    console.log(('str').constructor === String); // true
    console.log(([]).constructor === Array); // true
    console.log(([]).constructor === Object); // false
    console.log((function (){
    
    }).constructor === Function); // true
    console.log(({
    
    }).constructor === Object); //true
    
    function Fn(){
    
    };
    Fn.prototype = new Array();
    var f = new Fn();
    console.log(f.constructor===Fn);    // false
    console.log(f.constructor===Array); // true
  • Object.prototype.toString.call()
    Object.prototype.toString.call() 使用 Object 对象的原型方法 toString 来判断数据类型:
var a = Object.prototype.toString;
 
console.log(a.call(2));
console.log(a.call(true));
console.log(a.call('str'));
console.log(a.call([]));
console.log(a.call(function(){
    
    }));
console.log(a.call({
    
    }));
console.log(a.call(undefined));
console.log(a.call(null));

同样是检测对象obj调用toString方法,obj.toString()的结果和Object.prototype.toString.call(obj)的结果不一样,这是为什么?

这是因为toString是Object的原型方法,而Array、function等类型作为Object的实例,都重写了toString方法。不同的对象类型调用toString方法时,根据原型链的知识,调用的是对应的重写之后的toString方法(function类型返回内容为函数体的字符串,Array类型返回元素组成的字符串…),而不会去调用Object上原型toString方法(返回对象的具体类型),所以采用obj.toString()不能得到其对象类型,只能将obj转换为字符串类型;因此,在想要得到对象的具体类型时,应该调用Object原型上的toString方法。

4. 判断数组的方式

  • 原型链
obj.__proto__ === Array.prototype;
  • Object.prototype.toString.call()
Object.prototype.toString.call(obj).slice(8,-1) === 'Array';
  • Array.isArray()
Array.isArray(obj);
  • instance
obj instance of Array
  • Array.prototype.isPrototypeOf(obj)
Array.prototype.isPrototypeOf(obj)

5. 0.1+0.2 ! == 0.3

let n1 = 0.1, n2 = 0.2
console.log(n1 + n2)  // 0.30000000000000004
(n1 + n2).toFixed(2) // 注意,toFixed为四舍五入

toFixed(num) 方法可把 Number 四舍五入为指定小数位数的数字。那为什么会出现这样的结果呢?

计算机是通过二进制的方式存储数据的,所以计算机计算0.1+0.2的时候,实际上是计算的两个数的二进制的和。0.1的二进制是0.0001100110011001100…(1100循环),0.2的二进制是:0.00110011001100…(1100循环),这两个数的二进制都是无限循环的数。那JavaScript是如何处理无限循环的二进制小数呢?

一般我们认为数字包括整数和小数,但是在 JavaScript 中只有一种数字类型:Number,它的实现遵循IEEE 754标准,使用64位固定长度来表示,也就是标准的double双精度浮点数。在二进制科学表示法中,双精度浮点数的小数部分最多只能保留52位,再加上前面的1,其实就是保留53位有效数字,剩余的需要舍去,遵从“0舍1入”的原则。

根据这个原则,0.1和0.2的二进制数相加,再转化为十进制数就是:0.30000000000000004。

6. 如何获取安全的undefined值?

因为 undefined 是一个标识符,所以可以被当作变量来使用和赋值,但是这样会影响 undefined 的正常判断。表达式 void ___ 没有返回值,因此返回结果是 undefined。void 并不改变表达式的结果,只是让表达式不返回值。因此可以用 void 0 来获得 undefined。

7. NaN

NaN 指“不是一个数字”(not a number),NaN 是一个“警戒值”(sentinel value,有特殊用途的常规值),用于指出数字类型中的错误情况,即“执行数学运算没有成功,这是失败后返回的结果”.

typeof NaN; // "number"

NaN 是一个特殊值,它和自身不相等,是唯一一个非自反(自反,reflexive,即 x === x 不成立)的值。而 NaN !== NaN 为 true。

判断NaN
● 函数 isNaN 接收参数后,会尝试将这个参数转换为数值,任何不能被转换为数值的的值都会返回 true,因此非数字值传入也会返回 true ,会影响 NaN 的判断。
● 函数 Number.isNaN 会首先判断传入参数是否为数字,如果是数字再继续判断是否为 NaN ,不会进行数据类型的转换,这种方法对于 NaN 的判断更为准确。

8. 类型转换

8.1 ==操作符的强制类型转换规则
对于 == 来说,如果对比双方的类型不一样,就会进行类型转换。假如对比 x 和 y 是否相同,就会进行如下判断流程:

  1. 首先会判断两者类型是否相同,相同的话就比较两者的大小;
  2. 类型不相同的话,就会进行类型转换;
  3. 会先判断是否在对比 null 和 undefined,是的话就会返回 true
  4. 判断两者类型是否为 string 和 number,是的话就会将字符串转换为 number
  5. 判断其中一方是否为 boolean,是的话就会把 boolean 转为 number 再进行判断
  6. 判断其中一方是否为 object 且另一方为 string、number 或者 symbol,是的话就会把 object 转为原始类型再进行判断
    在这里插入图片描述
    8.2 其他值到字符串的转换
    ● Null 和 Undefined 类型 ,null 转换为 “null”,undefined 转换为 “undefined”,
    ● Boolean 类型,true 转换为 “true”,false 转换为 “false”。
    ● Number 类型的值直接转换,不过那些极小和极大的数字会使用指数形式。
    ● Symbol 类型的值直接转换,但是只允许显式强制类型转换,使用隐式强制类型转换会产生错误。
    ● 对普通对象来说,除非自行定义 toString() 方法,否则会调用 toString()(Object.prototype.toString())来返回内部属性 [[Class]] 的值,如"[object Object]"。如果对象有自己的 toString() 方法,字符串化时就会调用该方法并使用其返回值。

8.3 其他值到数字值的转换规则
● Undefined 类型的值转换为 NaN。
● Null 类型的值转换为 0。
● Boolean 类型的值,true 转换为 1,false 转换为 0。
● String 类型的值转换如同使用 Number() 函数进行转换,如果包含非数字值则转换为 NaN,空字符串为 0。
● Symbol 类型的值不能转换为数字,会报错。
● 对象(包括数组)会首先被转换为相应的基本类型值,如果返回的是非数字的基本类型值,则再遵循以上规则将其强制转换为数字。

9. Object.is() 与比较操作符 三等号、双等号 的区别?

● 使用双等号进行相等判断时,如果两边的类型不一致,则会进行强制类型转化后再进行比较。
● 使用三等号进行相等判断时,如果两边的类型不一致时,不会做强制类型准换,直接返回 false。
● 使用 Object.is 来进行相等判断时,一般情况下和三等号的判断相同,它处理了一些特殊的情况,比如 -0 和 +0 不再相等,两个 NaN 是相等的。

10. 如何判断一个对象是空对象

●使用JSON自带的.stringify方法来判断:

if(Json.stringify(Obj) == '{}' ){
    
    
    console.log('空对象');
}

●使用ES6新增的方法Object.keys()来判断:

if(Object.keys(Obj).length < 0){
    console.log('空对象');
}

猜你喜欢

转载自blog.csdn.net/qq_41867900/article/details/125209873