JS数据类型与判断方法

一、数据类型

五种简单数据类型(值类型)包括:String、Number、Boolean、undefined、Null
一种复杂数据类型(引用类型):Obeject(包括 function、Array、Date)

ES6 中新增了一种 Symbol 。这种类型的对象永不相等,即始创建的时候传入相同的值,可以解决属性名冲突的问题,做为标记

Symbol('key')===Symbol('key')  // false
Symbol('key')!==Symbol('key')  // true

1.undefined:在使用var声明变量但未对其加以初始化时,这个变量的值就是undefined

2.nullnull值表示一个空对象指针,而这也正是使用typeof操作符检测null时会返回object的原因

在 javascript 的最初版本中,使用的 32 位系统,为了性能考虑使用低位存储了变量的类型信息:

000:对象
1:整数
010:浮点数
100:字符串
110:布尔
有 2 个值比较特殊:

undefined:用 - (−2^30)表示。
null:对应机器码的 NULL 指针,一般是全零。

javascript 中的 null:既是对象,又不是对象,史称「薛定谔的对象」。

typeof null === 'object';
null instanceof Object === falsenull instanceof null
会抛出异常:

Uncaught TypeError: Right-hand side of 'instanceof' is not an object

3.Number:这种类型用来表示整数和浮点数值,还有一种特殊的数值,即NaN(非数值 Not a Number)。这个数值用于表示一个本来要返回数值的操作数未返回数值的情况(这样就不会抛出错误了)。例如,在其他编程语言中,任何数值除以0都会导致错误,从而停止代码执行。但在JavaScript中,任何数值除以0会返回NaN,因此不会影响其他代码的执行。

NaN本身有两个非同寻常的特点。首先,任何涉及NaN的操作(例如NaN/10)都会返回NaN,这个特点在多步计算中有可能导致问题。其次,NaN与任何值都不相等,包括NaN本身

二、类型判断

1.typeof

typeof ''; // string 有效
typeof 1; // number 有效
typeof NaN; // number
typeof Symbol(); // symbol 有效 typeof true; //boolean 有效 typeof undefined; //undefined 有效 typeof null; //object 无效 typeof [] ; //object 无效 typeof newFunction(); // function 有效 typeof newDate(); //object 无效 typeof newRegExp(); //object 无效 对于基本类型,除 null 以外,均可以返回正确的结果。 对于引用类型,除 function 以外,一律返回 object 类型。 对于 null ,返回 object 类型。 对于 function 返回 function 类型。 null 有属于自己的数据类型 Null , 引用类型中的 数组、日期、正则 也都有属于自己的具体类型
typeof 对于这些类型的处理,只返回了处于其原型链最顶端的 Object 类型

2.instanceof

instanceof 是用来判断 A 是否为 B 的实例,表达式为:A instanceof B,如果 A 是 B 的实例,则返回 true,否则返回 false。 在这里需要特别注意的是:instanceof 检测的是原型

[] instanceof Array; // true
[] instanceof Object; // true
instanceof 只能用来判断两个对象是否属于实例关系, 而不能判断一个对象实例具体属于哪种类型

3.constructor

当一个函数 F被定义时,JS引擎会为F添加 prototype 原型,然后再在 prototype上添加一个 constructor 属性,并让其指向 F 的引用。当执行 var f = new F() 时,F 被当成了构造函数,f 是F的实例对象,此时 F 原型上的 constructor 传递到了 f 上,因此 f.constructor == F

可以看出,F 利用原型对象上的 constructor 引用了自身,当 F 作为构造函数来创建对象时,原型上的 constructor 就被遗传到了新创建的对象上, 从原型链角度讲,构造函数 F 就是新对象的类型。这样做的意义是,让新对象在诞生以后,就具有可追溯的数据类型。

同样,JavaScript 中的内置对象在内部构建时也是这样做的

细节问题:

1. null 和 undefined 是无效的对象,因此是不会有 constructor 存在的,这两种类型的数据需要通过其他方式来判断。

2. 函数的 constructor 是不稳定的,这个主要体现在自定义对象上,当开发者重写 prototype 后,原有的 constructor 引用会丢失,constructor 会默认为 Object

为什么变成了 Object?

因为 prototype 被重新赋值的是一个 { }, { } 是 new Object() 的字面量,因此 new Object() 会将 Object 原型上的 constructor 传递给 { },也就是 Object 本身。

因此,为了规范开发,在重写对象原型时一般都需要重新给 constructor 赋值,以保证对象实例的类型不被篡改。

4.toString

toString() 是 Object 的原型方法,调用该方法,默认返回当前对象的 [[Class]] 。这是一个内部属性,其格式为 [object Xxx] ,其中 Xxx 就是对象的类型。

对于 Object 对象,直接调用 toString()  就能返回 [object Object] 。而对于其他对象,则需要通过 call / apply 来调用才能返回正确的类型信息。

Object.prototype.toString.call('') ;   // [object String]
Object.prototype.toString.call(1) ;    // [object Number]
Object.prototype.toString.call(true) ; // [object Boolean]
Object.prototype.toString.call(Symbol()); //[object Symbol]
Object.prototype.toString.call(undefined) ; // [object Undefined]
Object.prototype.toString.call(null) ; // [object Null]
Object.prototype.toString.call(newFunction()) ; // [object Function]
Object.prototype.toString.call(newDate()) ; // [object Date]
Object.prototype.toString.call([]) ; // [object Array]
Object.prototype.toString.call(newRegExp()) ; // [object RegExp]
Object.prototype.toString.call(newError()) ; // [object Error]
Object.prototype.toString.call(document) ; // [object HTMLDocument]
Object.prototype.toString.call(window) ; //[object global] window 是全局对象 global 的引用

拓展:

一个判断JS数据类型的函数
function judgeType(change) {
        if (arguments.length == 0) {
            return '0';//无参数传入
        }
        if (change === null) {
            return 'null'
        }
        if (change === undefined && arguments.length > 0) {
            return 'undefined'
        }
        if (change instanceof Function) {
            return 'function'
        }
        if (change instanceof Array) {
            return 'arry'
        }
        if (change instanceof Number || typeof change == 'number') {
            return 'number'
        }
        if (change instanceof String || typeof change == 'string') {
            return 'string'
        }
        if (change instanceof Boolean || typeof change == 'boolean') {
            return 'boolean'
        }
    }

三、数据比较

先按如下规则隐式转换,再进行比较。如对象和布尔比较的话,对象 => 字符串 => 数值;布尔值 => 数值。

特殊情况
[] == false;
![] == false;
null==null;
undefined == null //true undefined和null 比较返回true,二者和其他值比较返回false

四、判断类型是否为数组

1.通过instanceof判断

let a = [];
a instanceof Array; //true
let b = {};
b instanceof Array; //false
需要注意的是,prototype属性是可以修改的,所以并不是最初判断为true就一定永远为真。

其次,当我们的脚本拥有多个全局环境,例如html中拥有多个iframe对象,instanceof的验证结果可能不会符合预期,例如:
//为body创建并添加一个iframe对象
var iframe = document.createElement('iframe');
document.body.appendChild(iframe);
//取得iframe对象的构造数组方法
xArray = window.frames[0].Array;
//通过构造函数获取一个实例
var arr = new xArray(1,2,3); 
arr instanceof Array;//false

2.通过constructor判断

let a = [1,3,4];
a.constructor === Array;//true
同样,这种判断也会存在多个全局环境的问题,导致的问题与instanceof相同。

3.通过Object.prototype.toString.call()判断

// 检验是否是数组
  let a = [1,2,3]
  Object.prototype.toString.call(a) === '[object Array]';//true
  //检验是否是函数
  let b = function () {};
  Object.prototype.toString.call(b) === '[object Function]';//true
  //检验是否是数字
  let c = 1;
  Object.prototype.toString.call(c) === '[object Number]';//true

4.通过Array.isArray()判断

let a = [1,2,3]
Array.isArray(a);//true
// Array.isArray() 是在ES5中提出,也就是说在ES5之前可能会存在不支持此方法的情况。
if
(!Array.isArray) { Array.isArray = function(arg) { return Object.prototype.toString.call(arg) === '[object Array]'; }; }

五、Object.is

ES6提出“Same-value equality”(同值相等)算法,用来解决这个问题。Object.is就是部署这个算法的新方法。它用来比较两个值是否严格相等,与严格比较运算符(===)的行为基本一致

Object.is('foo', 'foo')
// true
Object.is({}, {})
// false

不同之处只有两个:一是 +0 不等于 -0 ,二是 NaN 等于自身。

+0 === -0 //true
NaN === NaN // false
Object.is(+0, -0) // false
Object.is(NaN, NaN) // true

ES5 可以通过下面的代码,部署Object.is

Object.defineProperty(Object, 'is', {
  value: function(x, y) {
    if (x === y) {
      // 针对+0 不等于 -0的情况
      return x !== 0 || 1 / x === 1 / y;
    }
    // 针对NaN的情况
    return x !== x && y !== y;
  },
  configurable: true,
  enumerable: false,
  writable: true
});

 

参考来源:https://www.cnblogs.com/onepixel/p/5126046.html

     https://www.cnblogs.com/chenmeijiao/p/12060845.html

posted @ 2020-12-11 14:11  盼星星盼太阳  阅读(218)  评论(0)    收藏  举报