JavaScript的数据类型及判断

banner

最近本身回归基础看了下javascript的相关知识点,想着看都看了,写出来记录下足迹也是一件好事,遂记录~javascript

javascript中有两种类型,一种是基本数据类型,一种是引用类型。java

基本类型

基本数据类型,也称为简单数据类型,在ES5中有如下五种:Undefined、Null、Boolean、Number和String,在ES6中新增了一种简单的数据类型Symbolgit

Undefined类型

Undefined类型只有一个值undefined。在进行相关变量定义的时候,未赋值的状况下,默认是赋值为undefined了。可是也是有些特殊的状况下会报错的。状况我大体罗列下:es6

# 状况1⃣️:变量声明了,可是没有赋值
var message;
console.log(message); // undefined

# 状况2⃣️:变量声明并赋值了,可是在console运行以后
console.log(message); // undefined
var message = 'find a frontend job in Canton!';

# 状况3⃣️:变量没声明,报引用报错
// var message;
console.log(message); // Uncaught ReferenceError: message is not defined

# 状况4⃣️:不经过var声明,直接写变量,报引用错误
message; // 不等价 var message;
console.log(message); // Uncaught ReferenceError: message is not defined

# 状况5⃣️:不经过var声明,直接写变量赋值
message = 'find a frontend job in Canton!'; // 默认在message前添加了var
console.log(message); // find a frontend job in Canton!

# 状况6⃣️:不经过var声明,直接写赋值,可是在console运行以后,报引用错误
console.log(message);
message = 'find a frontend job in Canton!'; // 至关于没message变量
复制代码

上面罗列的是ES5中经过var声明的状况。也许你会对状况2⃣️产生疑惑:我都给message赋值了啊,可是打印出undefined,这就有点尴尬了?github

由于在js中执行上下文分为两个阶段,第一个阶段是建立阶段,第二个阶段才是执行阶段api

上面状况2⃣️的执行状况以下:bash

1. 建立阶段:frontend

executionContextObj = {
	scopeChain: { ... },
	variableObject: {
		message: undefined
	},
	this: { ... }
}
复制代码

2. 执行阶段:函数

executionContextObj = {
	scopeChain: { ... },
	variableObject: {
		message: 'find a frontend job in Canton!'
	},
	this: { ... }
}
复制代码

详细的解析能够看下我以前翻译的一篇文章JS的执行上下文和环境栈是什么?ui

上面讲到的是var,咱们引入ES6let 和 const来演示下:

# 状况7⃣️:let声明变量赋值
let message;
console.log(message); // undefined

# 状况8⃣️:let声明变量可是不赋值,在console运行以后
console.log(message); // Uncaught ReferenceError: Cannot access 'message' before initialization
let message = 'find a frontend job in Canton!';

# 状况9⃣️:const声明变量可是不赋值,报语法错误
const message;
console.log(message); // Uncaught SyntaxError: Missing initializer in const declaration
复制代码

let和const改变了var命令会发生变量提高的现象,即变量能够在声明以前使用,值为undefined。它们改变了这种奇怪的现象,声明的变量必定要在声明以后使用,不然报错。

固然还有其余声明变量的方法,好比function命令等,这里不一一列举,只是探讨下undefined的值而已~

Null类型

Null类型的值是null。从逻辑角度来看,null值表示一个空对象指针。

若是定义的变量准备在未来用来保存对象,那么最好就是将变量初始化为null,而不是其余的数据值。这样,只要直接检查null值就能够知道相应的变量是否已经保存了一个对象的引用。以下面的例子:

if(car != null) {
	// 对car对象执行某些操做
}
复制代码

undefined值是派生自null值的。虽然二者在==比较时候是相等的,以下:

console.log(null == undefined); // true
复制代码

当变量不肯定类型的时候,能够不用为变量赋值,也就是默认赋值undefined了。可是若是你知道你的变量要保存对象可是尚未真正保存对象的时候就要赋值null了。

Boolean类型

Boolean类型在平常生活中使用频繁了,其值是truefalse,对应咱们口头的

将布尔值的truefalse转换为数值的话,能够用非00数字表示。

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

console.log( 0 == false); // true
复制代码

若是是恒等的比较方式===,那数字表示法是要凉凉的~

Number类型

Number类型有二进制表示法,八进制表示法,十六进制表示法和十进制表示法。这里只讨论十进制表示法,由于在日常的开发中,用到十进制的状况居多😂

这个类型用来表示整数值和浮点数值(即带小数点的值)。

整数值的基本操做非常简单,并且没啥bug好说,除非不在Number.MIN_VALUENumber.MAX_VALUE范围内。带小数点的仍是要留意下的,好比:

let a = 13.04;
let b = 2.5;
console.log(a + b); // 15.54
console.log(a * b); // 32.599999999999994
console.log(a - b); // 10.54
复制代码

咦咦,真是让人尴尬😅,怎么上面代码中两个浮点数相乘会出现那么多位的数字啊,不是等于32.6吗?

因此在进行浮点数的运算的时候仍是得慎重点,先转换成整数计算,以后再切换回去浮点数,好比上面的a * b能够考虑写成(a * 100 * (b * 10))/1000

当你要判断一个值是不是数值,可使用isNaN来表示,其返回一个布尔值,以下:

console.log(isNaN(NaN)); // true
console.log(isNaN(10)); // false
console.log(isNaN('10'); // false , '10'会被转化为10
console.log('blue'); // true , 不能转化为数值
console.log(true); // false, 可被转化为数值1
复制代码

还有将非数值转化为数值的三个方法:Number()、parseInt()和parseFloat()。见名思义:

**Number()是将传入的内容转换为数字(整数)或NaN。可是在转换字符串的时候比较复杂,通常用parseInt()**居多。**parseFloat()**就是转化成浮点数的方法啦。

String类型

String类型也就是字符串类型啦。

字符串类型包含一些特殊的字符字面量,也叫转义序列,用来表示非打印字符串。好比换行符\n啦。

在实际的开发中,咱们须要将数字类型或对象类型转换成字符串类型,那么咱们能够直接使用toString()方法进行操做啦。好吧,这api的东西你们都会用,就不说了😂

Symbol类型

Symbol类型是ES6引入的新类型,为了防止对象中属性名冲突的问题。

Symbol值经过Symbol函数生成。这就是说,对象的属性名如今能够有两种类型,一种是原来就有的字符串,另外一种就是新增的Symbol类型。凡是属性名属于Symbol类型,就都是独一无二的,能够保证不会与其余属性名产生冲突。

具体的看下阮一峰的es6入门中Symbol部分

上面说到的是6种基本的数据类型,还有一种是引用类型。

引用类型

引用类型:当复制保存对象的某个变量时,操做的是对象的引用,可是在为对象添加属性时,操做的是实际的对象。引用类型值指那些可能有多个值构成的对象。

引用类型有这几种:Object、Array、RegExp、Date、Function、特殊的基本包装类型(String、Number、Boolean)以及单体内置对象(Global、Math)。

基本包装类型这个有点好玩,咦?上面的基本数据类型都有String、Number和Boolean啦,怎么这里还有这些。是的,上面的基本类型是经过基本包装类型来建立的。以下:

var s1 = 'find a frontend job in Canton';
var s2 = s1.substring(2);
复制代码

上面的代码实际进行了下面的步骤:

(1)建立String类型的一个实例;

(2)在实例中调用指定的方法;

(3)销毁这个实例。

上面的三个步骤转化为代码以下:

var s1 = new String('find a frontend job in Canton');
var s2 = s1.substring(2);
s1 = null;
复制代码

(正规)的引用类型和基本包装类型的主要区别就是对象的生存期。使用new操做符建立的引用类型的实例,在执行流离开当前做用域以前都一直保存在内存中。而自动建立的基本包装类型的对象,则只存在于下一行代码的执行瞬间,而后当即被销毁。这意味着咱们不能在运行时为基本类型值添加属性和方法。来看下下面的例子:

var s1 = 'find a frontend job in Canton';
s1.name = 'jia ming';
console.log(s1.name); // undefined
复制代码

只能经过基本包装类的原型来添加了,好比改写toString方法:

var s1 = 'find a frontend job in Canton';
String.prototype.toString = function() {
    console.log('my name is jia ming');
}
console.log(s1.toString()); // my name is jia ming
复制代码

嗯~苦口婆心介绍了javascript的数据类型,那么下面才是重头戏。咱们在实际的开发中,如何识别不一样的数据类型呢?

数据类型判断

数据类型有上面的7种类型,其中基本类型是Undefined、Null、Boolean、Number、String和Symbol,还有一种引用类型。引用类型又包含比较多种的对象,好比ObjectArray等。

咱们首先想到的是经过typeof来判断,直接上代码来试下吧:

let symbol = Symbol('jia ming');
let str = 'find a frontend job in Canton!';
let flag = true;
let height = 99;
let job;
let obj = null;
console.log(typeof symbol); // symbol
console.log(typeof str); // string
console.log(typeof flag); // boolean
console.log(typeof height); // number
console.log(typeof job); // undefined
console.log(typeof obj); // object
复制代码

嗯~很ok啦,对基本的数据类型都能判断到啦,这个null获得的结果是object,你能够当成特殊状况来处理啦 -- 无中生有,一辈子万物嘛。

咱们再来看下引用类型打印出来的是什么东东😊

let person = {
    name: 'jia ming',
    info: 'find a frontend job in Canton!',
};
let arr = ['jia ming', 'find a frontend job in Canton!'];
let reg = new RegExp('jia ming', 'g');
let date = new Date();
let fn = () => {
    return 'find a frontend job in Canton!';
}
let math = Math.min(2, 4, 8);
console.log(typeof person); // object
console.log(typeof arr); // object
console.log(typeof reg); // object
console.log(typeof date); // object
console.log(typeof fn); // function
console.log(typeof math); // number
复制代码

咦咦~着实让人尴尬啊,这个为啥那么多object啊,个人当心脏😔。咱们只是简单经过typeof校验比较尴尬啊,咱们换个思路,咱们来结合call改变下上下文对象,改写一个方法进行判断,以下:

let person = {
    name: 'jia ming',
    info: 'find a frontend job in Canton!',
};
let arr = ['jia ming', 'find a frontend job in Canton!'];
let reg = new RegExp('jia ming', 'g');
let date = new Date();
function handleType(obj, type) {
    if(typeof obj === 'object') {
        return Object.prototype.toString.call(obj) === `[object ${type}]`;
    }
    return false;
}
console.log(handleType(person, 'Object')); // true
console.log(handleType(arr, 'Array')); // true
console.log(handleType(reg, 'RegExp')); // true
console.log(handleType(date, 'Date')); // true
复制代码

美滋滋,能够实现区别判断的哈。但是上面的基本类型中null也是object啊,而后是Math类型的typeof也是number啊,这个你能够本身作下处理啦。这里就不考虑了~

后话

文章首发:github.com/reng99/blog…

更多内容:github.com/reng99/blog…

参考

相关文章
相关标签/搜索