共9种分为简单数据类型(6种)和复杂数据类型(3种)
1. 简单数据类型(值类型)
- 简单类型又叫基本数据类型或者值类型
- 值类型: 在存储时变量中存储的是值本身,因此叫做值类型。
- 例如:字符串(String)、数字(Number)、布尔(Boolean)、空(Null)、未定义(Undefined)、Symbol
- 值类型变量的数据存放在变量(栈空间)中,里面直接开辟空间,存放的是值
- 简单类型传参:函数的形参也可以看做是一个变量,当我们把一个值类型变量作为参数传递给函数形参时,其实是把变量在栈空间里的值复制了一份给形参,那么在方法内部对形参做任何修改,都不会影响到外部变量
2. 引用类型: 复杂数据类型,
- 在存储变量中存储的仅仅是地址(引用),因此叫做引用数据类型
- 通过new关键字创建的对象(系统对象,自定义对象)
- 例如:对象(Object)、数组(Array)、函数(Function)
- 复杂数据类型:首先先栈里面存放地址,用十六进制表示,然后这个地址指向堆里面的数据
- 复杂数据类型传参:函数的形参也可以看做是一个变量,当我们应用类型变量传递给形参时,其实是把变量在栈空间里保存的堆地址复制给了形参,形参和实参其实保存了同一个堆地址,所以操作的是同一个对象
//复杂数据类型传参
function Person(name) { this.name = name; }
function f1(x) { //x=p
console.log(x.name); //刘德华
x.name = '张学友';//改变了堆里面name的值
console.log(x.name); //张学友
}
var p = new Person('刘德华');
console.log(p.name); //刘德华
f1(p); //给x赋值为p x和p指向相同的地址
console.log(p.name); //张学友
3. 堆和栈
- 堆栈空间分配区别:
- 栈(操作系统):由操作系统自动分配释放函数的参数值、局部变量的值等。其操作方式类似于数据结构中的栈;简单数据类型存放到栈里面;
- 堆(操作系统):存储复杂类型(对象),一般由程序员分配释放,若程序员不释放,由垃圾回收机制回收;复杂数据类型存放到堆里面。
- 注意:JS里面没有栈和堆的概念,通过栈和堆更容易理解执行方式
4. 详细介绍6种简单数据类型
-
String字符串:用于表示由零或多个16位的Unicode字符组成的字符序列
- 在JS中字符串需要使用引号引起来
- 使用双引号或单引号都行,但是不要混着用,可用length看长度
- 引号不能嵌套,双引号不能放双引号,单引号不能放单引号
- 转译符:无法输出的字符,先输出,在输出字符,如: \n表示换行、\t制表符(空格)等
- 字符串不可变:在内存中不会立刻消失,只能二次赋值,原有的字符串在一定时间内被垃圾回收器回收
- 字符串拼接:果两个变量都是字符串,无论是否包含数字,只要是拼接,那么在前一个后面添加后一个字符串(+和-情况不同,详情参考数据转换)
-
Number数值
- 在JS中所有的数值都是Number类型,包括整数和浮点数(小数)
- 进制转换:进制包括2进制、8进制(011)、10进制、16进制(0xA)、制等
- 值 = 位值进制的(位置-1)次方+位值进制的(位置-1)次方+位值*进制的(位置-1)次方+...........
- 浮点数:因为精度丢失问题,所以不判断计算后的两个浮点数是否相等
- Js中可以表示数字的最大值console.log(Number.MAX_VALUE)//1.7976931348623157e+308
- 数字的最小值console.log(Number.MIN_VALUE) // 5e-324
- 如果使用Number表示的数值超过了最大值,则会返回一个
- Infinity(无穷大)// 表示一个正无穷
- -Infinity // 表示一个负无穷
- 使用typeof检查Infinity也会返回一个number
- NaN表示一个特殊的数字,表示Not A Number
- console.log(“abc”/18); //结果是NaN
- Undefined和任何数值计算为NaN;
- NaN 与任何值都不相等,包括 NaN 本身
- 使用typeof检查NaN也会返回一个number
- isNaN() :任何不能被转换为数值的值都会导致这个函数返回 true
- 不是一个数字的标准,如果符合了那么就不是一个数字,不符合就是一个数字
- isNaN(NaN);// true
- isNaN(“blue”); // true -Boolean isNaN(123); // false
-
Boolean
- 布尔值只有两个,主要用来逻辑判断
- true:表示真 false:表示假
- 使用typeof检验一个布尔值时,会返回一个boolean
- true: true、除0数字、'something'、Object(任何对象)为true
- false: false、0、undefined、null为false
- if判断时会把()内的值强行转换成boolean类型进行判断
-
undefined
- Undefined类型的值只有一个,就是Undefined(未定义)
- 当声明一个变量,但不给这个变量赋值时,它的值就是Undefined
- 使用typeof检查Undefined值时,也会返回一个Undefined
-
Null 空值
- Null的值只有一个,就是null(空值)
- null的这个值专门用来表示一个为空的对象
- 使用typeof检测一个null值时,会返回一个object(对象)
-
Symbol类型: 符号类型是唯一的并且是不可修改的
var s = Symbol()- Symbol 函数前不能使用 new 命令,否则会报错。这是因为生成的 Symbol 是一个原始类型的值,不是对象
- 一个字符串作为参数,表示对 Symbol 实例的描述,主要是为了在控制台显示,或者转为字符串时,比较容易区分
let s1 = Symbol('foo') // Symbol(foo)
- 一个对象为参数,就会调用该对象的toString方法,将其转为字符转,然后才生成一个Symbol值
const obj = { toString() { return 'abc'; } }; const sym = Symbol(obj); sym // Symbol(abc) - Symbol值不能与其他类型的值进行运算
let sym = Symbol('My symbol'); "your symbol is " + sym // TypeError: can't convert symbol to string
- Symbol值可以显示转为字符串
let sym = Symbol('My symbol'); String(sym) // 'Symbol(My symbol)'; sym.toString() // 'Symbol(My symbol)'
- Symbol值可以转为布尔值,但不能转为数值
-
let sym = Symbol(); Boolean(sym) // true; !sym // false; Number(sym) // TypeError; sym + 2 // TypeError
- 作为属性名的Symbol:由于每一个Symbol值都是不相等的,可以作为标识符
let mySymbol = Symbol(); // 第一种写法 let a = {}; a[mySymbol] = 'Hello!'; // 第二种写法 let a = { [mySymbol]: 'Hello!' }; // 第三种写法 let a = {}; Object.defineProperty(a, mySymbol, { value: 'Hello!' }); // 以上写法都得到同样结果 a[mySymbol] // "Hello!" - Symbol.for(): 重新使用同一个Symbol值
- Symbol.for()为 Symbol 值登记的名字,是全局环境的,不管有没有在全局环境运行
- 它接受一个字符串作为参数,然后搜索有没有以该参数作为名称的 Symbol 值。如果有,就返回这个 Symbol 值,否则就新建一个以该字符串为名称的 Symbol 值,并将其注册到全局
let s1 = Symbol.for('foo'); let s2 = Symbol.for('foo'); s1 === s2 // true- Symbol.for()与Symbol()这两种写法,都会生成新的 Symbol。它们的区别是,前者会被登记在全局环境中供搜索,后者不会
- Symbol.for()不会每次调用就返回一个新的 Symbol 类型的值,而是会先检查给定的key是否已经存在,如果不存在才会新建一个值
- Symbol()写法没有登记机制,所以每次调用都会返回一个不同的值
- Symbol.keyFor()方法返回一个已登记的 Symbol 类型值的key
let s1 = Symbol.for("foo"); Symbol.keyFor(s1) // "foo"; let s2 = Symbol("foo"); Symbol.keyFor(s2) // undefined
5. 详细介绍3种复杂数据类型
- Object:Object数据类型,称为对象,是一组数据和功能(函数)的集合。可以用new操作符后跟要创建的对象类型的名称来创建。也可以用字面量表示法创建。在其中添加不同名(包含空字符串在内的任意字符串)的属性。
- Array:JavaScript 数组用方括号书写。数组的项目由逗号分隔
- Function:ECMAScript中的函数是对象,与其他引用类型一样具有属性和方法。因此,函数名实际是一个指向函数对象的指针。
- 函数声明
function sum(num1,num2){ return num1+num2; } // 函数声明 var sum = function(num1,num2){ return num1+num2; }; // 函数表达式 这里的分号很重要- 没有重载: 创建第二个函数时覆盖了引用第一个函数的变量addSomeNumber。
function addSomeNumber(num){ return num + 100; } function addSomeNumber(num){ return num + 200; } var result = addSomeNumber(100); //300- 函数声明与函数表达式
- 代码开始执行前,解析器会率先读取函数声明并将其添加到执行环境中,对代码求值前,JS引擎在第一遍会声明函数并将它们放到源代码树的顶部。但改为函数表达式就会出错
alert (sum(10,10)); function sum(num1,num2){ return num1+num2; }- 作为值的函数
function callSomeFunction(someFunction,someArgument){ return someFunction(someArgument); } function add10(num){ return num+10; } var result1 = callSomeFunction(add10,10); alert(result1); //20 // callSomeFunction是通用的,函数作为第一个参数传递进去,返回执行第一个参数后的结果