js-类型

244 阅读11分钟

类型分类

一、JS中数据类型

引自:《了不起的Nodejs》

其实我个人觉得下面的内容更加准确

  • 基本数据类型:(Undefined、Null、Boolean、Number、String、Symbol【es6新增】,BigInt【es6新增】)

  • 复杂数据类型: (Object)

  • Function一种特别的对象:可以执行

  • Array一种特别的对象:下标就是属性值,内部数据是有序的。

  • Object

二、定义类型的两种方式

  • 字面量

  • 构造函数方式

    var a = 'woot'; var b= new String('woot');

    a+b; // woot woot

    typeof a; // 'string' typeof b; // 'object'

    a instanceof String; // false b instanceof String; // true

    a == b; // true a === b; // false

注:实际开发中不建议使用new的方式定义,据说性能不好。

IF假值

If假值,||也是的,其实就是在执行前会调用Boolearn()方法

相当于:if(Boolean(XXX))

false、undefined、null、0、 "" 、NaN 都是被认为是“假值”。

注意:空数组**[]空对象****{}**不是假值哦

// 这五种都会被条件判断当做false
if(!0){
    console.log("df---在条件判断中,0会被自动当成false")
}
if(!""){
    console.log("df---在条件判断中,空字符串“”会被自动当成false")
}
if(!undefined){
    console.log("df---在条件判断中,undefined会被自动当成false")
}
if(!null){
    console.log("df---在条件判断中,null会被自动当成false")
}
if(!NaN){
    console.log("df---在条件判断中,NaN会被自动当成false")
}

什么情况下会发生布尔值的隐式强制类型转换?

1) if (..) 语句中的条件判断表达式。
(2) for ( .. ; .. ; .. ) 语句中的条件判断表达式(第二个)。
(3) while (..) 和 do..while(..) 循环中的条件判断表达式。
(4) ? : 三元表达式中的条件判断表达式。
(5) ||(逻辑或)和 &&(逻辑与)逻辑运算符左边的操作数(作为条件判断表达式)。

假值对象

浏览器在某些特定情况下,在常规 JavaScript 语法基础上自己创建了一些外来值,这些就是“假值对象”。
假值对象看起来和普通对象并无二致(都有属性,等等),但将它们强制类型转换为布尔值时结果为 false ;
最常见的例子是 document.all,它是一个类数组对象,包含了页面上的所有元素,
由 DOM(而不是 JavaScript 引擎)提供给 JavaScript 程序使用。

null、undefined、NaN、""的区别

null

null表示空值,即该处的值现在为空。

常用来表示对象类型的默认值。

undefined

表示“未定义”,下面是返回undefined的典型场景。

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

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

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

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

null转为数字时,自动变成0。

undefined转为数值时,为NaN。

undefined == null
// true

undefined === null
// false

// null在转换成强制类型时会变成0
let a = Number(null) // 0
let b = 5 + null // 5
console.log(a+","+b); // 0,5

对象的toString和valueOf

一般来说,对象到字符串的转换经过了如下步骤:

1.如果对象具有toString()方法,则调用这个方法。如果它返回一个原始值,js将这个值转换成字符串,并返还这个字符串结果。

2.如果对象没有toString()方法,或者这个方法并不返回一个原始值,那么js将调用valueOf()方法。

3.否则,js无法从toString()或者valueOf()获得一个原始值,因此这时它将抛出一个类型错误异常。

一般来说,对象到数字的转换过程中,js做了同样类似的事情,但这里它会首先尝试使用valueOf()方法:

1.如果对象具有valueOf()方法,后者返回一个原始值,则js将这个原始值转换成数字,并返回这个数字。

2.否则,如果对象具有toString()方法,后者返回一个原始值,则js将转换并返回。

(首先js转换成相应的字符串原始值,再继续将这个原始值转换成相应的数字类型,再返回数字)

3.否则,js抛出一个类型错误异常。

转换成原始值

对象通过toString或valueOf方法转换为原始值,JS语言核心的内置类首先尝试使用valueOf(),再尝试使用toString()

eg:

“1” == true;

将返回true,转换形式是:true首先转换为1,然后再执行比较。接下来字符串“1”也转换成了数字1,相等,所以返回true

  • 对于所有非日期对象来说,对象到原始值的转换基本上是对象到数字的转换

到底什么时候调用转换

好好看看上诉链接上的列子,非常不错;

  • alert(aa);
  • alert(+aa);
  • alert(''+aa);
  • alert(String(aa));
  • alert(Number(aa));
  • alert(aa == '10');

总结起来就是 如果只重写了toString,对象转换时会无视valueOf的存在来进行转换。

但是,如果只重写了valueOf方法,在要转换为字符串的时候会优先考虑valueOf方法。

在不能调用toString的情况下,只能让valueOf上阵了

单独判断null,undefined,NaN的方法:

判断NaN: isNaN()

var tmp = 0/0; //0做除数是算法错误,所以结果是NaN
 if(isNaN(tmp)){ 
    alert("NaN"); 
}

console.log(typeof NaN);    // number 

????NaN是一种特殊的number,NaN与任何值都不相等,与自己也不相等。
console.log(NaN === NaN); //false

isNaN 和 Number.isNaN 函数的区别?

函数 isNaN 接收参数后,会尝试将这个参数转换为数值,任何不能被转换为数值的的值都会返回 true因此非数字值传入也会返回 true ,会影响 NaN 的判断。

函数 Number.isNaN 会首先判断传入参数是否为数字,如果是数字再继续判断是否为 NaN ,这种方法对于 NaN 的判断更为准确。

判断undefined:

var tmp = undefined; 

if (typeof(tmp) == "undefined"){ 
     alert("undefined"); 
}
或则

if(tmp === undefined){}

判断null:

var tmp = null; 
if ( !tmp && typeof(tmp) ! ="undefined" && tmp!=0 && tmp!='' && !isNaN(tmp)){ 
     alert("null"); 
}

// 上面有点傻
if(tmp === null){}

判断undefined或null:

var tmp = undefined; 
 if (tmp== undefined) { 
     alert("null or undefined"); 
 }

 var tmp = undefined; 
 if (tmp == null) { 
     alert("null or undefined"); 
 }

其实就是利用【==】的自动转换,注意【==】和【===】的区别

/* null 、undefined、NaN和“”的区别,
 * 关键是null和undefined的区别
 * 
 */

// 来看一个typeof 输入的类型吧
console.log(typeof null);   // object
console.log(typeof undefined);  // undefined

类型判断(类型判断)

下面将对如下数据进行判断它们的类型

var bool = true
var num = 1
var str = 'abc'
var und = undefined
var nul = null
var arr = [1,2,3]
var obj = {name:'haoxl',age:18}
var fun = function(){console.log('I am a function')}

注意Array.isArray(arr) 是ES6新增的,不兼容ie6-ie8

1.使用typeof

console.log(typeof bool); //boolean
console.log(typeof num);//number
console.log(typeof str);//string
console.log(typeof und);//undefined
console.log(typeof fun);//function
console.log(typeof nul);//object
console.log(typeof arr);//object
console.log(typeof obj);//object
  • typeof 对于原始类型来说,除了 null 都可以显示正确的类型
  • typeof 对于对象来说,除了函数function都会显示 object

typeof 检测变量的类型范围包括: “string" | "number" | "bigint" | "boolean" | "symbol" bigInt | "undefined" | "object" | "function" 数据类型。

2.使用instanceof

console.log(bool instanceof Boolean);// false
console.log(num instanceof Number);// false
console.log(str instanceof String);// false
console.log(und instanceof Object);// false
console.log(arr instanceof Array);// true
console.log(nul instanceof Object);// false
console.log(obj instanceof Object);// true
console.log(fun instanceof Function);// true

var bool2 = new Boolean()
console.log(bool2 instanceof Boolean);// true

var num2 = new Number()
console.log(num2 instanceof Number);// true

var str2 = new String()
console.log(str2 instanceof String);//  true

function Person(){}

var per = new Person()
console.log(per instanceof Person);// true

function Student(){}
Student.prototype = new Person()
var haoxl = new Student()
console.log(haoxl instanceof Student);// true
console.log(haoxl instanceof Person);// true

instanceof不能区别undefined和null并且对于基本类型如果不是用new声明的则也测试不出来,对于是使用new声明的类型,它还可以检测出多层继承关系。

原理:

a instanceof B

判断实例对象a的隐式原型链上 是否有 B的显示原型

3.使用constructor

undefined和null没有contructor属性

console.log(bool.constructor === Boolean);// true
console.log(num.constructor === Number);// true
console.log(str.constructor === String);// true
console.log(arr.constructor === Array);// true
console.log(obj.constructor === Object);// true
console.log(fun.constructor === Function);// true
console.log(haoxl.constructor === Student);// false
console.log(haoxl.constructor === Person);// true

constructor不能判断undefined和null,并且使用它是不安全的,因为contructor的指向是可以改变的,开发中尽量不要使用

注意:对使用instanceof方法和constructor属性貌似都可以来判断是否为数组了,但是也有列外情况,比如在跨框架iframe的时候使用页面中的数组时,会失败,因为在不同的框架iframe中,创建的数组是不会相互共享其prototype属性的;如下代码测试即可得到验证。

var iframe = document.createElement('iframe');
document.body.appendChild(iframe);
xArray = window.frames[window.frames.length-1].Array;       
var arr = new xArray("1","2","3","4","5");
//这个写法IE下是不支持的,标准浏览器firefox,chrome下有

console.log(arr);  // 打印出 ["1", "2", "3", "4", "5"]
console.log(arr instanceof Array); // false 
console.log(arr.constructor === Array); // false

4.使用Object.prototype.toString.call

console.log(Object.prototype.toString.call(bool));//[object Boolean]
console.log(Object.prototype.toString.call(num));//[object Number]
console.log(Object.prototype.toString.call(str));//[object String]
console.log(Object.prototype.toString.call(und));//[object Undefined]
console.log(Object.prototype.toString.call(nul));//[object Null]
console.log(Object.prototype.toString.call(arr));//[object Array]
console.log(Object.prototype.toString.call(obj));//[object Object]
console.log(Object.prototype.toString.call(fun));//[object Function]
console.log(Object.prototype.toString.call(Symbol);//[object Symbol]

function Person(){}
function Student(){}
Student.prototype = new Person()
var s = new Student()
console.log(Object.prototype.toString.call(s));//[object Object]

原理(摘自高级程序设计3):在任何值上调用 Object 原生的 toString() 方法,都会返回一个 [object NativeConstructorName] 格式的字符串。每个类在内部都有一个 [[Class]] 属性,这个属性中就指定了上述字符串中的构造函数名。

但是它不能检测非原生构造函数的构造函数名

例子

let a = "string";
let b = 111;
let c = {};
let d = [1, 2, 3];
let e = function () {
    console.log("eee");
}
let f = undefined;
let g = null;
let h = new Date();
let i = /test/;
let j = true;

console.log(Object.prototype.toString.call(a) === '[object String]');//true
console.log(Object.prototype.toString.call(b) === '[object Number]');//true
console.log(Object.prototype.toString.call(c) === '[object Object]');//true
console.log(Object.prototype.toString.call(d) === '[object Array]');//true
console.log(Object.prototype.toString.call(e) === '[object Function]');//true
console.log(Object.prototype.toString.call(f) === '[object Undefined]');//true
console.log(Object.prototype.toString.call(g) === '[object Null]');//true
console.log(Object.prototype.toString.call(h) === '[object Date]');//true
console.log(Object.prototype.toString.call(i) === '[object RegExp]');//true

console.log(Object.prototype.toString.call(c) === '[object Object]');//true
console.log(Object.prototype.toString.call(d) === '[object Object]');//false
console.log(Object.prototype.toString.call(e) === '[object Object]');//false

5.使用jquery中的$.type

console.log($.type(bool));//boolean
console.log($.type(num));//number
console.log($.type(str));//string
console.log($.type(und));//undefined
console.log($.type(nul));//null
console.log($.type(arr));//array
console.log($.type(obj));//object
console.log($.type(fun));//function
function Person(){}
function Student(){}
Student.prototype = new Person()
var haoxl = new Student()
console.log($.type(haoxl));//object

$.type()内部原理就是用的Object.prototype.toString.call()

6.使用===

只能判断undefined和null,因为undefined和null只有唯一的值。

7.lodash

总结

判断类型

  • 基本(值)类型

  • Number ----- 任意数值 -------- typeof

  • String ----- 任意字符串 ------ typeof

  • Boolean ---- true/false ----- typeof

  • undefined --- undefined ----- typeof/===

  • null -------- null ---------- ===

  • 对象(引用)类型

  • Object(key,value) ---- Object.prototype.toString.call

  • Array ------ instanceof、Array.isArray()

  • Function ---- instanceof、typeof

  • 其他内置对象 ----- instanceof、Object.prototype.toString.call

  • 其他

  • NaN:Number.isNaN()

js中的类型守卫:

  • 类型判断:typeof

  • 属性或者方法或者函数判断:in

  • 实例判断:instanceof

  • 字面量相等判断:==,===,!=,!==

判断容器类是否为空

一.判断数组是否为空:length为0好了。

二.判断对象是否为空 {}:注意这里不是说null啊

1.将json对象转化为json字符串,再判断该字符串是否为"{}"
var data = {}; 
var b = (JSON.stringify(data) == "{}"); 
alert(b);//true

2.for in 循环判断
var obj = {};
var b = function() {
  for(var key in obj) {
  	return false;
  }
return true;
}
alert(b());//true

3.jquery的isEmptyObject方法
此方法是jquery将2方法(for in)进行封装,使用时需要依赖jquery
var data = {};
var b = $.isEmptyObject(data);
alert(b);//true

4.Object.getOwnPropertyNames()方法
获取到对象中的属性名
注意:此方法不兼容ie8,其余浏览器没有测试
var data = {};
var arr = Object.getOwnPropertyNames(data);
alert(arr.length == 0);//true

5.使用ES6的Object.keys()方法
与4方法类似,是ES6的新方法, 返回值也是对象中属性名组成的数组
var data = {};
var arr = Object.keys(data);
alert(arr.length == 0);//true

类型转换

其他值到字符串的转换规则

规范的 9.8 节中定义了抽象操作 ToString ,它负责处理非字符串到字符串的强制类型转换。

(1Null 和 Undefined 类型 ,null 转换为 "null",undefined 转换为 "undefined",

(2)Boolean 类型,true 转换为 "true"false 转换为 "false"。

(3)Number 类型的值直接转换,不过那些极小和极大的数字会使用指数形式。

(4)Symbol 类型的值直接转换,但是只允许显式强制类型转换,使用隐式强制类型转换会产生错误。

(5)对普通对象来说,除非自行定义 toString() 方法,否则会调用 toString()(Object.prototype.toString())
    来返回内部属性 [[Class]] 的值,如"[object Object]"。如果对象有自己的 toString() 方法,字符串化时就会
    调用该方法并使用其返回值。

其他值到数字值的转换规则

有时我们需要将非数字值当作数字来使用,比如数学运算。为此 ES5 规范在 9.3 节定义了抽象操作 ToNumber。

(1)Undefined 类型的值转换为 NaN。

(2)Null 类型的值转换为 0。

(3)Boolean 类型的值,true 转换为 1,false 转换为 0。

(4)String 类型的值转换如同使用 Number() 函数进行转换,如果包含非数字值则转换为 NaN,空字符串为 0。

(5)Symbol 类型的值不能转换为数字,会报错。

(6)对象(包括数组)会首先被转换为相应的基本类型值,如果返回的是非数字的基本类型值,则再遵循以上规则将其强制转换为数字。

为了将值转换为相应的基本类型值,抽象操作 ToPrimitive 会首先(通过内部操作 DefaultValue)检查
是否有valueOf() 方法。如果有并且返回基本类型值,就使用该值进行强制类型转换。
如果没有就使用 toString() 的返回值(如果存在)来进行强制类型转换。
如果 valueOf() 和 toString() 均不返回基本类型值,会产生 TypeError 错误。

其他值到布尔类型的值的转换规则

ES5 规范 9.2 节中定义了抽象操作 ToBoolean,列举了布尔强制类型转换所有可能出现的结果。

以下这些是假值:
• undefinednullfalse
• +0、-0NaN""

假值的布尔强制类型转换结果为 false。从逻辑上说,假值列表以外的都应该是真值。

parseInt() 与 Number()的区别

解析字符串中的数字和将字符串强制类型转换为数字的返回结果都是数字,它们之间的区别是什么?

解析允许字符串(如 parseInt() )中含有非数字字符,解析按从左到右的顺序,如果遇到非数字字符就停止。
而转换(如 Number ())不允许出现非数字字符,否则会失败并返回 NaN。

== 操作符的强制类型转换规则?

1)字符串和数字之间的相等比较,将字符串转换为数字之后再进行比较。
(2)其他类型和布尔类型之间的相等比较,先将布尔值转换为数字后,再应用其他规则进行比较。
(3nullundefined 之间的相等比较,结果为真。其他值和它们进行比较都返回假值。
(4)对象和非对象之间的相等比较,对象先调用 ToPrimitive 抽象操作后,再进行比较。
(5)如果一个操作值为 NaN ,则相等比较返回 falseNaN 本身也不等于 NaN )。
(6)如果两个操作值都是对象,则比较它们是不是指向同一个对象。如果两个操作数都指向同一个对象,则相等操作符返回 true,否则,返回 false