Xiaoshier Blog

JavaScript 基础知识之数据类型

最近花了近半个月的时间, 初步读了一遍 underscore.js 源码, 通过读源码, 对 javascript 系统的学习了一遍.
之前也有通过看书或者是工作中用到 javascript 对其进行学习, 但是效果都不是很好.
一般看书, 都是这边看过去, 理解了, 过两天就忘了; 工作中的实战, 只是为了解决当时的问题而学习,
对 javascript 没有一个很好的认识,学习及 研究.

之前也有过读 之前也有过读 underscore 源码的计划, 但都是读了几行,
一时半会看不懂, 或是其他事给搁置了, 这次痛下决心, 即使第一遍读不懂,
也要把它看完, 就采用了, 把它敲下来的方法, 还别说一行行的往下敲, 还真让我坚持了下来.
读完之后, 也相当于又把 javascript 基础给了解了一遍, 收益颇多,
现在总结记录一下, 好记性不如烂笔头嘛, 说的太好了.

一. 数据类型

数据类型分为基本类型和引用类型

1. 基本类型: Undefined, Null, String, Number, Boolean, Symbol

  • 基本类型, 是简单的数据段, 值本身无法被改变;
  • 可以通过 typeof 来确定是哪种基本类型, 返回值有
    undefined, object, string, number, boolean, function
  • 存储在变量获得内存中, 即有限存储空间的栈内存中;
  • 数值的复制, 是按值传递, 复制者和被复制者的值相同, 复制结束后再没何联系;
  • 传递参数, 是按值传递, 使用时也是按值使用;

2. 引用类型: Object, Array, Function, Date, Regexp

  • 引用类型有自己的属性和方法; 引用类型是一种数据结构, 被称为类; 引用类型的对象是引用类型的实例
  • 可以使用 Object.prototype.toString.call(context) 的方法来获得是哪种类型的引用类型
    [object Object],[object Array], [object Function], [object String],
    [object Error], [object RegExp], [object Date], [object Arguments], [object Boolean]
  • 存储在堆内存中, 变量只是指向内存的指针
  • 复制引用类型, 是按引用传递, 复制者和被复制者是指向同一内存的指针,
    一个修改内容, 另一个相应的值也会跟着发生变化
  • 传递参数, 是按值传递, 但是按引用来访问

二. 基本类型(原始类型)

1. Undefined 类型

  • Undefined类型只有一个值 undefined;
  • 以下情况值为 undefined: 一个变量为初始化; 一个函数未传入实参的形参;
    一个函数未返回值, 默认返回值为 undefined

2. Null 类型

  • Null 类型只有一个值 null;
  • null 值表示指向一个空对象的指针, 使用 typeof null 返回的值为 object;
  • 一般声明对象时, 若无具体初始值, 给该对象初始化为 null;

    null == undefined => true;
    null === undefined => false; 
    

3. String 类型

  • String 可以由 “ 或 ‘ 表示;
  • 其他类型可以通过 toString()String() 的方法转为字符串;

4. Number 类型

Number(), parseInt(), parseFloat() 函数, 可将其他类型转为数字类型;
parseInt(param, n) (n: 转换为多少进制), 转为整数类型, parseFloat(param)转为浮点型;

Number(true) => 1;
Number(false) => 0;
Number(null) => 0;
Number('string') => NaN;
Number(undefined) => NaN;

5. Boolean 类型

  • 有两个值 falsetrue;
  • Boolean() 函数, 可将其他类型转为布尔类型;

    Boolean(undefined) => false;
    Boolean(NaN) => false;
    Boolean(0) => false;
    Boolean('') => false;
    Boolean(null) => false;
    

6. Symbol 类型

ECMA 6 新增类型

三. 引用类型

引用类型是一种数据结构, 将数据和功能组织在一起, 被称为类; 引用类型的值即对象, 就是类的实例;
使用 new 操作符加上一个构造函数来创建对象

1. Object 类型

  • 创建对象:

    var obj = {
        name: 'Jeo',
        age: 20
    }
    
    var obj = {} 或 obj = new Object();
    obj.name = 'Jeo';
    obj.age = 20;
    
  • 访问对象:

    obj.name;
    obj['name'];
    

2. Array 类型

  • 创建数组:

    var arr = [1, 2, 3];
    
    var arr = new Array(length);//length 为数组长度, 创建一个包含 length 项数组
    var arr = Array(length);//同上
    
    var name = Array('Joe');//创建包含一个项的数组 
    
  • 访问数组:

    arr[index]; //index 是数组索引值;
    
  • 获得数组长度:

    var arr = [1, 2, 3, 4];
    arr.length; =>4;
    arr['length']: =>4;
    
  • 方法:
    toString, toLocaleString, valueOf =>转换方法, 将数组转换为字符串, 返回字符串, 以逗号隔开
    push, pop, unshift, shift =>在原数组的基础上最后/最前添加项或删除最后/第一项,
    slice, splice, =>操作方法, slice(m, n):获得数组第 m 项到第 n - 1的项. 返回新的数组, 原数组值不变; splice(m, n[, string]):删除, 插入, 替换. 返回删除项, 原数组发生相应变化
    sort, reverse =>重新排序, 返回经过排序的数组
    indexOf, lastIndexOf =>位置方法,indexOf(m[, n]), lastIndexOf(m[, n]) 获得传入项在数组中的索引值[或第 n 个之后项的索引值], 存在返回索引值, 不存在返回 -1;
    every, filter, forEach, map, some =>迭代方法, 传入参数一般为函数, 每一项经过函数, 返回新的值

  • 类数组:
    拥有length属性,其它属性(索引)为非负整数(对象中的索引会被当做字符串来处理,这里你可以当做是个非负整数串来理解)
    不具有数组所具有的方法.

    DOM方法 document.getElementsByClassName() 的返回结果(实际上许多DOM方法的返回值都是类数组) 和 函数中的 arguments 对象就是类数组对象

    var obj = {
        1: 'string',
        2: 'string',
        3: 'string',
        length: 3
    }
    

3. Date 类型

时间是以 1970 年 1 月 1 日凌晨为基数, 来保存日期

  • 创建日期:

    var now = new Date();//创建日期对象, 并获得当前时间, 毫秒值
    var someday = new Date(Date.parse('May 25, 2004'));//创建日期对象, 并赋值
    var someday = new Date(2004, 5, 25);
    
    //尽量少用, 有些方法, 对这种方式创建的时间对象, 不适用
    var now = Date();//创建日期对象, 无论传参数与否,都只获得当前时间, 毫秒值
    var now = Date(anything);
    
  • 方法:
    Date.parse, Date.UTC, valueOf, getTime把时间对象, 转为毫秒值;

    toDateString, toTimeString,toUTCString
    toLocaleDateString, toLocaleTimeString以特定的时间显示年月日时间等;

    getFullYear, getMouth, getDate, getDay, getHours, getMinutes,
    getSeconds, getMilliseconds =>获得年月日星期时分秒毫秒

    setFullYear, setMouth, setDate, setHours, setMinutes,
    setSeconds, setMilliseconds =>设置年月日时分秒毫秒;

4. Function 类型

  • 任何函数都是 Function 类型的实例, 函数名则是指向函数的指针;

  • 定义函数
    函数可由函数声明函数表达式来定义函数; 函数声明的函数, 在执行任何代码之前可用;
    函数表达式必须等到解析器执行到它所在的代码行, 才会被解释执行. 原因如下:

    javascript引擎在执行 javascript 时分为 预编译阶段执行阶段 .
    预编译阶段 :

    1. 声明变量 var a = 2; 首先编译器会在当前作用域的集合中声明该变量, 然后为引擎生成运行时所需的代码, 这些代码被用来处理 a = 2 这个赋值操作,
      引擎在执行阶段时, 先询问作用域是否有变量 a, 如果有则对 a 进行赋值操作, 如果没有继续向上一层级查找, 直到没有抛出异常错误.
    2. 变量的赋值会执行两个动作, 编译器在当前作用域声明变量; 执行时引擎在作用域中查找该变量, 找到就对其进行赋值操作.
    3. 预编译阶段, 确认变量是在哪里以及如何声明的, 方便在执行过程中如何对他们进行查找.
    4. 在内存中开辟一块空间 , 存放用 var 关键字声明的变量和 function 关键字声明函数 .
    5. 预编译不会对变量进行赋值 , 但是会对函数初始化 ;
      在函数声明之前可调用函数, 而在变量初始化之前变量的值为 undefined.
      函数声明提升时,函数名相同的函数, 后面声明的函数会覆盖前面声明的函数例子.
    6. 将变量声明和函数声明提升 , 变量声明优先于函数声明 .
      也就是说, 如果函数声明的函数名称和变量名称一样时, 函数名称会覆盖变量名称;
    7. 函数内部也存在变量提升, 函数声明提升, 将变量名, 提升至作用域链顶部, 原理同上;
    8. 函数声明提升, 也就是将整个函数提升, 在执行阶段, 不再解析函数声明, 如果有变量和函数重名时, 再解析到变量时, 该函数名被重新定义. 如下
    foo(); => ok
    var foo = 10; 
    function foo() {
        console.log('ok');
    }
    console.log(foo) => 10
    
  • 函数没有重载, 也就是一个函数名定义多次, 最后一个声明的函数, 会覆盖之前声明的函数;

  • 函数内部有两个特殊的对象 argumentsthis
    arguments 是类数组对象, 具有数组的 length 属性, 但不具有数组的其他方法,
    可通过 Array.prototype.slice.call(arguments) 将其转为数组;
    this 对象是函数据以执行的环境对象, 全局环境下是指 windows 对象, 局部环境下, 是指引用该函数的对象;

  • 函数有两个属性 lengthprototype
    length 是指函数接收的命名参数的个数
    prototype 是包含函数类型所有实例共享的属性和方法, 如 indexOf(), toString()等方法, 都保存在 prototype 对象中

  • 函数的方法 apply()call()
    他们的作用是设置函数体内 this 对象的值和传入函数的参数
    使用方法: func.apply(thisArg[, argsArray)func.call(thisArg[, arg1[, arg2[, ...]]])

5. Regexp 类型

6. 基本包装类型

为了便于操作基本类型, ECMAScript 提供了 3 种特殊的引用类型: Number, String, Boolean;
这三种类型依旧是引用类型, 使用 typeof 的结果都是 object . 直接调用包装类型的函数, 相当于是调用转型函数, 将其他类型数据, 转为调用的包装类型

每当读取一个基本类型时, 后台就会创建一个对应的基本包装类型的对象, 让我们可以调用基本包装类型的方法和属性 .
有如下步骤:

  • 创建基本包装类型的实例 ;
  • 在实例上调用指定方法 ;
  • 销毁这个实例

如下操作:

var str = 'some text';
var str2 = str.substring(2);

后台建立如下代码:

var str = new String('some text');
var str2 = str.substring(2);
str = null;

7. 单体内置对象