前言
最近打算有空闲时间慢慢整理一些JS相关文章,先从变量、常量及数据类型入手。本文将重点围绕以下几点进行介绍:
- 变量var和let、变量在内存中的具体存储形式
- 常量const
- 数据类型、typeof详解
- 数据类型的显隐示转换
- null和undefined的区别
- js判断数据类型的方法
变量
JS中的变量是松散类型的,可以存储任何类型的数据。因此JS也称为弱类语言。JS变量松散类型的本质,决定了变量只是在特定时间用于保存特定值的一个名字而已。由于不存在定义某个变量必须要保存何种数据类型值的规则,变量的值及其数据类型可以在脚本的生命周期内改变。过多基础概念不在赘述。
变量命名规则
- 变量名必须以英文字母、_、$开头
- 变量名可以包括英文字母、_、$、数字
- 不可以使用系统的关键字、保留字作为变量名
var变量
var定义的变量没有块级作用域,只有函数级作用域(作用域问题改天会更新详解)。当我们在JS中写下:
var a = 100;
这样的语句执行时实际上发生了两个步骤:第一步,申请一块内存空间叫做a,第二步,向此内存空间里赋值。因此,我们就能很清晰的理解以下两种情况:
- 如果只是声明变量没有赋值相当于只申请了一块内存空间,此时内存空间里没有实际值故系统显示为undefined。
- 如果未经声明的变量直接赋值是不安全的,尽管在非严格情况下可以运行,是因为js解释器帮你做了第一步申请,并且它会将这种未经声明的变量视为全局变量。而在严格模式下,系统会报Reference(非法或不能识别的引用类型)的错误。
let变量
let变量是es6中引进的,用let定义的变量会生成一个作用域,外部不能访问。因此对于变量的私有化要求更加严格。let定义的变量有以下几个特点:
- let定义的变量拥有块级作用域
- let在块级作用域中不存在变量提升
- 不能在同一作用域中(函数作用域和块级作用域)用let声明相同的变量
变量在内存中的具体存储形式
基本类型是保存在栈内存中的,它们的值都有固定的大小,保存在栈空间,按值访问。 引用类型保存在堆内存中,值大小不固定。栈内存中存放改变量的访问地址,地址指向堆内存中的对象。js不允许直接访问堆内存中的位置。
当基本类型变量发生复制行为时,系统会自动为新的变量分配一个新值,最后这些变量时独立互不影响的。而引用类型变量复制时,系统也会为新变量分配一个新值,不同的是,这个值也只是一个地址,指向的是堆内存中的同一个对象。因此a.x发生变化时b.x也会发生变化。如图
基本类型 引用类型
常量
const定义的是常量,不可以修改并且必须初始化。使用const定义数组时,数组名不能改变,但数组的内容可以通过push改变。因为数组内容的改变不会改变数组的引用地址。
数据类型
JS中的数据分为七种内置类型,这七种内置类型又分为两大类型,一种是原始值,一种是引用值。
原始值
- Number 数字类型
- String 字符串类型
- Boolean 布尔类型
- undefined 未定义
- null 空(占位值)
- symbol
五个原始值这里不在赘述。有一点需要注意的是原始值是栈数据。操作的是数据。
引用值
引用值有很多种,例如array,object,function,date...等,引用值是堆数据,操作的是存数据的内存地址。
typeof详解
typeof操作符返回的是一个字符串,字符串,字符串(重要的事情说三遍)用来指示未经计算的操作数类型。typeof是唯一一个使用未声明对象不会报错(会返回undefined)的操作符。它总共有六个返回值,需要牢记,分别是:
- Number
- Boolean
- String
- undefined
- object
- function
其中object为所有引用值的返回值。需要强调的一点是object同时也是null的返回值。这是由于最初null这个占位值用做空对象,浏览器一直把它当做对象看待。
数据类型的显隐示转换
显示类型转换(显示装箱)
- Number(需转换的数据)
Number(null);//0
Number(undefined);//NaN
- parseInt(需转换的数据,基底)
将数据根据基底要求的进制转换成十进制整型,基底的范围为2~36,只取小数点之前的数,不会进行四舍五入。
- parseFloat(String)
识别到第一个小数点后的所有数字类型并返回,遇到非数字类型就砍断。
-
String(需转换的数据)
-
Boolean(需转换的数据)
在js中
undefined
,null
,false
,NaN
,''
,0
,-0
这些值都为false
- 需转换的数据.toString(基底);
需要注意undefined和null不能用此方法。这个里面的基底与上面不同,这里的基底是将调用它的数据转换成基底要求的进制数。
隐示类型转换(隐式装箱)
- isNaN();
隐示调用Number();然后将结果与NaN比较.所以:
isNaN(null);//false
isNaN(undefined);//ture
- ++、--、正负运算
隐示调用Number();然后再进行运算
- 加号
当加号两边有一个字符串的话,就会隐示调用String()将两边全部转换为字符串
- -、*、/、%
隐示调用Number()
- &&、||、!
判断之前,先用Boolean()转换成布尔值。再进行判断。
- <、>、<=、>=
有数字进行比较的会先转换成数字。纯字符串比较会比较ASCII码值。true比较时转化成1,false比较时会转化成0
- ==、!=
需要注意有三个特殊的值:
NaN == NaN; // false,NaN谁都不等于
undefined == null;//true
undefined和null即不等于true,也不等于false。
不发生类型转换的
- ===
类型也要相同才为true.但是NaN依然不等于NaN
- !==
null和undefined的区别
在if语句中,它们都会被自动转为false,相等运算符(==)甚至直接报告两者相等。
null是一个表示“空”的对象,转为数值时为0;undefined是一个表示"此处无定义"的原始值,转为数值时为NaN。
js判断数据类型的方法
typeof | instanceof | constructor | Object.prototype.toString.call | |
---|---|---|---|---|
优点 | 使用简单 | 能检测出引用类型 | 基本能检测出所有类型(除null和undefined) | 可检测出所有类型 |
缺点 | 只能检测出基本类型,除null,typeof(nulll)=object | 不能检测出基本类型,且不能跨iframe | constructor容易被修改,且不能跨iframe | ie6下,undefined和null均为object |