JS的数据类型

178 阅读6分钟

(一)数据类型

1.JS的数据类型都有哪些⭐⭐⭐⭐⭐

包括:6种基本类型和引用类型

  • 基本类型:Number、String、Boolean、Null、Undefined、symbol(es6的新数据类型)
  • 引用类型:统称为Object(包括Object、Array、Function(堆)、Date、RegExp())

2. 基本类型和引用类型的区别

区别基本类型引用类型
存放位置基本类型是存放在引用类型值保存在
是否可添加属性和方法不可以可以
  • 在栈中保存数据的引用地址,这个引用地址指向的是对应的数据,以便快速查找到堆内存中的对象。
  • 栈内存是自动分配内存的。而堆内存是动态分配内存的,不会自动释放。(所以每次使用完对象的时候都要把它设置为null,从而减少无用内存的消耗)

[ 延伸问题 ]

(1)为什么0.1+0.2>0.3 ⭐⭐⭐⭐

因为在JS底层中,每个变量是以二进制表示,固定长度为64位,其中第1位是符号位,再往后11位是指数位,最后52表示的是尾数位,而0.1和0.2转为二进制的时候是无限循环小数,所以JS就会进行截取截取以后0.1和0.2就不是他们本身了,要比原来大 那么一丢丢,所以0.1+0.2就>0.3了

0.1 -> 0.0001100110011001...(无限循环)
0.2 -> 0.0011001100110011...(无限循环)
// 尾数位数限制,需要将后面多余的位截掉,这样在进制之间的转换中精度已经损失。

(1-1)如何解决这个问题,使0.1+0.2等于0.3?⭐⭐⭐⭐⭐

A:先给他们放大倍数,随后再除以相应倍数

const a = 0.1;
const b = 0.2;

console.log(a + b === 0.3)   // false
console.log((a * 1000 + b * 1000) / 1000 === 0.3)  // true

(2)对象和数组的区别

区别数组对象
顺序数组是有序数据的集合对象是无序数据的集合
长度有长度对象没有长度
数据是否有key值数组的数据没有名称,只有下标对象的数据需要指定名称。
key值是否唯一数组可以重复对象键值唯一

(二)数据类型的判断方式⭐⭐⭐⭐⭐

方式描述
typeof① 对于基本数据类型来说,除了 null 都可以显示正确的类型
typeof null的值为Object,无法分辨是null还是Object);
② 对于对象来说,除了函数都会显示 object;
instanceof通过原型链来判断,只能判断某对象是否存在于目标对象得的原型链上
Object.prototype.toString.call()可以检测所有的数据类型,可以区分 null 、string、number、undefined、array、function、object、date、math 数据类型。
缺点:不能细分谁是谁的实例
constructorconstructor属性值指向当前原型所属的类(构造函数)

示例代码

 // ------------------------------------typeof-----------------------------------------
 
typeof 5; // 'number'
typeof NaN; // 'number' ★★★
typeof '5'; // 'string'
typeof false; // 'boolean'
typeof Symbol(); // 'symbol'
typeof undefined; // 'undefined'
typeof null; // object ★★★ // typeof 对于对象来说,除了函数都会显示 objec;★★★
typeof Function; // ‘function'
typeof []; // 'object'
typeof {}; // 'object'

// -----------------------------------instanceof-------------------------------------
// instanceof 通过原型链来判断数据类型的
function Foo() {}
var f1 = new Foo();
var d = new Number(1);
console.log(f1 instanceof Foo); // true
console.log(d instanceof Number); //true
console.log(123 instanceof Number); //false   -->不能判断字面量的基本数据类型

// --------------------------Object.prototype.toString.call()-------------------------
// Object.prototype.toString.call()可以检测所有的数据类型,算是一个比较完美的方法了。
const obj = {};
const arr = [];
const date = new Date();
const reg = /[hbc]at/gi;
function fn() {}
console.log(Object.prototype.toString.call(obj)); //[object Object]
console.log(Object.prototype.toString.call(arr)); //[object Array]
console.log(Object.prototype.toString.call(fn)); // "[object Function]"
console.log(Object.prototype.toString.call(date)); // "[object Date]"
console.log(Object.prototype.toString.call(reg)); // "[object RegExp]"
console.log(Object.prototype.toString.call(undefined)); // "[object Undefined]"
console.log(Object.prototype.toString.call(null)); // "[object Null]"
console.log(Object.prototype.toString.call(123)); // "[object Number]"
console.log(Object.prototype.toString.call('abc')); // "[object String]"
console.log(Object.prototype.toString.call(true)); // "[object Boolean]"

// -------------------------------------constructor------------------------------------
var d = new Number(1);
var e = 1;
function fn() {}
var date = new Date();
var arr = [1, 2, 3];
var reg = /[hbc]at/gi;

console.log(d.constructor); //ƒ Number() { [native code] }
console.log(e.constructor.name); //Number
console.log(fn.constructor.name); // Function
console.log(date.constructor.name); // Date
console.log(arr.constructor.name); // Array
console.log(reg.constructor.name); // RegExp

[ 延伸问题 ]

(1)为什么要用Object.prototype.toString.call(),而不用 Array.prototype.toString.call()?⭐⭐

  • 每一个继承 Object 的对象都有 toString 方法,如果 toString 方法没有重写的话,会返回 [Object type],其中 type 为对象的类型。
  • 但当除了 Object 类型的对象外,其他类型直接使用 toString 方法时,会直接返回都是内容的字符串,所以我们需要使用call或者apply方法来改变toString方法的执行上下文。

因为只有Object.prototype.toString.call()返回的是统一格式,
而且 Array.prototype.toString.call()的部分类型(如undefined、null)无法检验。

    function fn() {}
    var date = new Date();
    var arr = [1, 2, 3];
    var reg = /[hbc]at/gi;

    console.log(Array.prototype.toString.call(undefined)); // 报错
    console.log(Array.prototype.toString.call(null)); // 报错
    console.log(Array.prototype.toString.call(123)); // "[object Number]" 
    console.log(Array.prototype.toString.call("abc")); // "[object String]" 
    console.log(Array.prototype.toString.call(true)); // "[object Boolean]" 
    console.log(Array.prototype.toString.call(fn)); // "[object Function]" 
    console.log(Array.prototype.toString.call(date)); // "[object Date]" 
    console.log(Array.prototype.toString.call(arr)); // "1,2,3"
    console.log(Array.prototype.toString.call(reg));// "[object RegExp]"

(2)instanceof作用与原理⭐⭐⭐⭐⭐

  • 作用:instanceof是用来判断一个实例是否属于某个类型
  • 原理:instanceof原理实际上就是查找目标对象的原型链,查找构造函数的原型对象是否在实例对象的原型链上,如果在返回true,如果不在返回false
  • instanceof不能用来判断基本数据类型
let Dog = function(){}
let tidy = new Dog()
tidy instanceof Dog //true
  • 手写原理:
function myInstance(L, R) {
    // 1. L代表instanceof实例,R代表原型
    let LP = L.__proto__; //实例对象的原型链上
    let RP = R.prototype; // 构造函数的原型对象
    while (true) {
        // 2.如果找到最后一层为null都没找到
        if (LP == null) {
            return false;
        }
        // 3. 判断构造函数的原型对象是否在实例对象的原型链上
        if (LP == RP) {
            return true;
        }
        // 4. 逐层向上查找
        LP = LP.__proto__; 
    }
}
console.log(myInstance({},Object)); 

(4)为什么typeof null 是Object?⭐⭐⭐⭐⭐

因为在JavaScript中,不同的对象都是使用二进制存储的,如果二进制前三位都是0的话,系统会判断为是Object类型,而null的二进制全是0,自然也就判断为Object,这个bug是初版本的JavaScript中留下的
扩展一下其他五种标识位:

标识位类型
000对象
1整型
010双精度类型
100字符串
110布尔类型

(5)==和===区别是什么?⭐⭐⭐⭐⭐

  • ===是严格意义上的相等,会比较两边的数据类型和值大小
    只要数据类型不一样,就返回false;

  • ==是非严格意义上的相等,两边类型相同,比较大小;
    如果是不同类型的数据进行比较,会默认进行数据类型之间的转换;
    两边类型不同,根据下方表格,再进一步进行比较。

1. 两边类型相同比较大小
对象 == 对象对象数据类型的比较,比较的是空间地址
2. 两边类型不同结果
Null == Undefinedtrue
String == Number先将String转为Number,再比较大小
Boolean == Number现将Boolean转为Number,再进行比较
Object == String/Number/SymbolObject 转化为原始类型,再进行比较

(6)(面试题)NaN == NaN 的结果是什么?为什么?⭐⭐⭐⭐⭐

  • NaN == NaN的执行结果是 false。因为JavaScript规定,NaN表示的是非数字,但是这个非数字也是不同的,因此 NaN 不等于 NaN,两个NaN永远不可能相等。
  • 判断是否为NaN用一个函数 isNaN来判断;
    • isNaN传入的如果是其他数据类型,那么现将它使用Number()转为数字类型再进行判断

(7)typeof 和 instanceof 检测数据类型有什么区别?

  • 相同点: 都常用来判断一个变量是否为空,或者是什么类型的。
  • 不同点:
    • typeof 返回值是一个字符串,用来说明变量的数据类型
    • instanceof 用于判断一个变量是否属于某个对象的实例.

(8)如何判断一个变量是对象还是数组?

可以用Object.prototype.toString.call()

(8-1)为什么该方法可以

  • toString为Object的原型方法,而Array 、Function等类型作为Object的实例,都重写了toString方法。
  • 由于Object.prototype.toString()本身允许被修改,像Array、Boolean、Number的toString就被重写过,所以需要调用Object.prototype.toString.call(arg)来判断arg的类型,call将arg的上下文指向Object,所以arg执行了Object的toString方法。