JS数据类型

160 阅读8分钟

共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是通用的,函数作为第一个参数传递进去,返回执行第一个参数后的结果