JavaScript数据类型的分类、判断和转换

2022-06-01  本文已影响0人  刷题刷到手抽筋

简介

编程语言会有不同的数据类型,这是因为数据是对不同场景的实体的量化抽象,不同实体之间会有区别,另外,不同类型的数据的应用场景和操作也是不一样的。

例如提示的话术就应该用字符串类型,可以拼接你好,我是${name}。而例如游戏得分应该用数值类型,可以进行加减等运算。

数据类型

JavaScript类型介绍

数据类型分类

ECMSScript有5种简单数据类型(也称为基本数据类型):Undefined、Null、Boolean、Number、String。还有一种复杂的数据类型——Object。
—— 《JavaScript高级程序设计》

根据《JavaScript高级程序设计》中说明,JavaScript有6种数据类型,Undefined、Null、Boolean、Number、String、Object。但实际上typeof null的值是"object",另外typeof function() {}的值是"function"。因此我们认为null并不是一个独立的类型,null是object类型是一个值,而function也是一个独立的类型。

**js数据类型有6种:

undefined类型的值只有一个,就是undefined。

数值类型有两个特殊的值,NaN(not a number)和Infinity(无穷大)

object类型又可以分为

其中number、string、boolean、undefined是值类型,function和object是引用类型。

值类型和引用类型

值类型和引用类型的区别是,值类型赋的变量直接存储数据,引用类型的变量存储数据的引用。

let a = 1;
let b = a;
b = 2;

console.log(a, b); // 1, 2

let c = {attr: 'yes'};
let d = c;
d.attr = 'no';

console.log(c.attr, d.attr); // no no
function test(arg) {
  arg = 2;
}

let a = 1;
// 相当于将a的值赋给test中的参数变量,参数改变并不会影响到a
test(a);

console.log(a); // 1

function update(arg) {
  arg.attr = 2;
}
let b = {attr: 1};
// 将b的引用赋给update的参数变量,参数变量改变引用指向的数据,也会影响到b
update(b);

console.log(b.attr); // 2

包装类型

基础类型的数据在使用时候,js引擎会先将之包装为对象,语句执行完对象被销毁。这个过程也被称为“装箱拆箱”。例如

const arr = '1,2,3'.split(',');

字符串先包装为String对象,然后对象执行相应方法,语句执行完后,包装对象就被销毁。

再如(1).toString()将返回数据类型的包装对象转换成的字符串。

注意:1.toString()会将"."解析为小数点,因此会报语法错误

包装类型机制扩展了基本数据类型的能力,方便了日常开发。

因为基础类型也有包装类型转为对象,因此除了Symbol都有构造函数。

"1".constructor                 // 返回函数 String()  { [native code] }
(1).constructor                 // 返回函数 Number()  { [native code] }
false.constructor                  // 返回函数 Boolean() { [native code] }
[1,2,3].constructor              // 返回函数 Array()   { [native code] }
{}.constructor  // 返回函数 Object()  { [native code] }
new Date().constructor             // 返回函数 Date()    { [native code] }
function () {}.constructor         // 返回函数 Function(){ [native code] }

null和undefined的区别

本身都表示“没有”,但null表示引用类型的对象为空,undefined则表示变量未定义。

在相等判断时候,null和undefined是相等的。

但null和undefined在很多方面有区别。

含义不同

null表示对象空指针,undefined表示变量未定义。

类型不同

typeof null // 'object'
typeof undefined // 'undefined'
Number(null) // 0
Number(undefined) // NaN

应用场景不同

null

作为对象原型链的终点。

undefined

定义了变量,没有初始化,默认是undefined。

函数不return,或者return后面没有值,则函数默认返回undefined。

函数参数如果不传,默认是undefined。

类型判断

判断类型的方法

typeof

typeof用来查看字面量或者变量的数据类型

typeof 1            // 'number'
typeof '1'          // 'string'
typeof false            // 'boolean'
typeof {}           // 'object'
typeof []           // 'object'
typeof new Date()       // 'object'
typeof (() => {})       // 'function'
typeof undefined        // 'undefined'
typeof Symbol(1)        // 'symbol'

由结果可知typeof可以测试出numberstringbooleanSymbolundefinedfunction,而对于null数组对象,typeof均检测出为object,不能进一步判断它们的类型。

instanceof

instanceof可以判断一个对象的构造函数是否等于给定的值

({}) instanceof Object // true
[] instanceof Array // true
new Date() instanceof Date // true
/123/g instanceof RegExp // true

instanceof方法一般用于判断自定义构造函数实例。

function Person() {}
const p = new Person();
p instanceof Person // true
p instanceof Object // true

The instanceof operator tests to see if the prototype property of a constructor appears anywhere in the prototype chain of an object. The return value is a boolean value.

—— MDN

instanceof原理是判断构造函数的原型prototype属性是否出现在对象的原型链上。

需要注意的是,这里提到instanceof是判断对象的构造函数,不适用与非对象类型的变量,看MDN的例子:

let literalString = 'This is a literal string';
let stringObject  = new String('String created with constructor');

literalString instanceof String;  // false, string literal is not a String
stringObject  instanceof String;  // true

constructor

console.log(false.constructor === Boolean);// true

console.log((1).constructor === Number);// true

console.log(''.constructor === String);// true

console.log([].constructor === Array);// true

console.log(({}).constructor === Object);// true

console.log((function test() {}).constructor === Function);// true

console.log(Symbol('1').constructor === Symbol);// true

注意:undefined和null没有contructor属性

这里可以看到虽然数字1的构造函数是Number,但1是对象字面量,不是通过new创建的,因此使用instanceof判断为false。

Object.prototype.toString

Object是js中所有其他数据类型的父类。意思是所有的数据类型都继承了Object。但是无论是string还是array都是会重写这个tostring方法的。所以'1'.toString()Object.prototype.toString.call('1')的结果不同。

Object.prototype.toString.call可以用来区分数组、null等引用类型。

function Test(){};
const t = new Test();

Object.prototype.toString.call(1);  '[object Number]'

Object.prototype.toString.call(NaN); '[object Number]'

Object.prototype.toString.call('1'); '[object String]'

Object.prototype.toString.call(true); '[object Boolean]'

Object.prototype.toString.call(undefined); '[object Undefined]'

Object.prototype.toString.call(null); '[object Null]'

Object.prototype.toString.call(Symbol());'[object Symbol]'

Object.prototype.toString.call(foo);  '[object Function]'

Object.prototype.toString.call([1,2,3]); '[object Array]'

Object.prototype.toString.call({});'[object Object]'

Object.prototype.toString.call(t);'[object Object]'

注意自定义对象的判断只能得到"[object Object]"的结果。

常见变量的类型判断

判断一个变量是否是对象

Object.prototype.toString.call(obj) ==='[object Object]'

判断JavaScript对象是否为空对象

// 方法1  注意该方法性能较差
function isEmptyObject(obj) {
    return JSON.stringify(obj) === '{}';
}

// 方法2  因为for in只能枚举对象自身的属性,不能枚举原型属性,因此可以用来判断空对象
function isEmptyObject(obj) {
  for (var key in obj) {
    return false;
  }
    return true;
}

// 方法3 Object.keys也是只能获取自身属性,不能获取原型属性
function isEmptyObject(obj) {
    return Object.keys(obj).length === 0;
}

如何判断一个对象是否数组

// ES6中增加的数组方法
Array.isArray()

// 使用constructor判断
function isArray(arr) {
    return arr.constructor.toString().indexOf("Array") > -1;
}

function isArray(arr) {
  return arr.constructor === Array;
}

// 用instanceof判断
function isArray(arr) { 
  return arr instanceof Array; 
}

判断NaN

isNaN()用来判断一个变量是否为NaN

isNaN(NaN); // true

或者利用NaN和自己不相等的特性

typeof num === 'number' && num !== num

类型转换

为什么要做类型转换

js是弱类型的语言,声明变量时候未指定变量类型,因此在很多场景下需要做类型转换。

js和其他端交互(如服务端、native、DOM(如input的value是字符串,需要转换为数字))时候,其他端对数据类型可能有要求

不同类型数据之间可能要进行运算

某些场景支持的数据类型固定(如if的condition需要是bool),这时候需要进行类型转换。

类型转换分为显式转换(包装类型函数、parseInt )和自动转换(隐式转换)。

转换为字符串类型

使用toString方法或者String()效果相同

(1).toSting();  // '1'
String(1);  // '1'

null和undefined没有toString方法,其他的类型都有。null 和undefined转换字符串可以用String(null)或者'' + null

转换为数值类型

parseInt和parseFloat对字符串解析会将字符串前面符合数字规则的部分解析成数字,如果开头就不是数字则返回NaN

parseInt(123);      // 123
parseInt('123');    // 123
parseInt('123a');   // 123
parseInt('a123');   // NaN
parseInt('123.123');    // 123
parseFloat('123.123');  // 123.123

解析数组,解析第一个元素。其他情况都返回NaN。

parseInt([]);       // NaN
parseInt([1]);      // 1 
parseInt([1, 2]); // 1
parseInt(['1']);    // 1
parseInt(['a']);    // NaN

类型转换规则

常见变量转换表

原始值 转为数字 转为字符串 转为布尔
false 0 "false" false
true 1 "true" true
0 0 "0" false
1 1 "1" true
"0" 0 "0" true
"000" 0 "000" true
"1" 1 "1" true
NaN NaN "NaN" false
Infinity Infinity "Infinity" true
-Infinity -Infinity "-Infinity" true
"" 0 "" false
"20" 20 "20" true
"a" NaN "a" true
[] 0 "" true
[10,20] NaN "10,20" true
function(){} NaN "function(){}" true
{ } NaN "[object Object]" true
null 0 "null" false
undefined NaN "undefined" false

对象转原始类型

// Symbol.toPrimitive
var obj = {
  [Symbol.toPrimitive] () {
    return 3;
  },
  valueOf () {
    return 2;
  },
  toString () {
    return 1;
  }
}
console.log(obj) // 3

// valueOf
var obj = {
  valueOf () {
    return 2;
  },
  toString () {
    return 1;
  }
}
console.log(obj) // 2

// toString
var obj = {
  toString () {
    return 1;
  }
}
console.log(obj) // 1

// 默认
var obj = {
}
console.log(!!{}); // true
console.log(obj + '') // "[object Object]"
console.log(+obj); // NaN

数组转为原始类型

另一个例子:

如何让if (a == 1 && a == 2)返回true

var a = {
value: 0,
  valueOf: function() {
    this.value++;
    return this.value;
  }
};
console.log(a == 1 && a == 2);//true

隐式转换

在一些场景中,不同类型的变量会放在一起处理,这时候js引擎会做隐式转换转,转换为相同的类型后再处理。还有些情况下对变量的类型有要求,而变量如果不符合要求就会进行隐式转换(如if语句要求是bool值,如果是非bool值,会先转换为bool再处理)。\

隐式转换场景

  1. 算术运算
  2. 单目运算符+
  3. if条件表达式转换为布尔
  4. !运算符转为布尔
  5. ==比较
  6. 比较运算符>、<、≥、≤

转换规则

-   如果是类型相同,直接进行===比较
-   如果类型不同,要进行转换再比较

练习题

1 + '1'         // '11'
1 + + '1'       // 2
1 + 1 + '1'     // '21'
1 + '1' + 1     // '111'
1 + 'a'         // '1a'      
1 + +'a'        // NaN
1 - '1'         // 0

!![]    // true
!!''    // false
!!{}    // true

if ([]) {console.log('bingo')}      // 'bingo'
if ('') {console.log('bingo')}      //
if ('0') {console.log('bingo')}     // 'bingo'
if ('{}') {console.log('bingo')}    // 'bingo'

NaN == ''           // false
NaN == 0            // false
NaN == 'NaN'    // false

1 == '1'    // true
0 == '0'    // true
0 == ''     // true

true == '1' // true
true == 'true'  // false
true == '0' // false

[] == true  // false
[] == ![]       // true (首先这个表达式等同于[] == false,然后布尔转为数字:[] == 0,然后对象要转为字符串再比较,即:'' == 0,这样是一个字符串和一个数值比较,要先将字符串转为数字,即:0 == 0)
[] == '0'   // false
[] == ''    // true
({}) == '[object Object]'    // true
({}) == 0    // false
({}) == NaN      // false
true > '0'      // true
'1.2.3' < '1.2.4'   // true
[2] > 1         // true
[2, 1] > 1      // false

参考文章

灵题库
前端知识点汇总

上一篇下一篇

猜你喜欢

热点阅读