javascript 知识点整理 02 数据类型

这部分内容的整理都来自于《js高级程序设计》

变量声明

数据类型(原始类型、引用类型、类型转换、函数)

函数(arguments对象、参数传递)

引用类型拷贝(深拷贝、浅拷贝)

变量声明


  • var可以声明局部变量,不用的话是声明全局变量。

    严格模式要求必须要先声明,不然会导致错误

  • 局部变量在函数体退出后就会被销毁。内存管理会定期把除了当前执行环境中使用的变量和引用的外部变量的变量都回收掉。

  • 声明一个变量但是未经初始化,其类型为undefined;

  • 输出一个没有声明的变量的类型,也会返回undefined

    且对于没有声明的变量只能使用typeof查看其类型

    我的理解是,没有声明和声明了没有初始化,这俩变量其实都没法拿来干活儿,都是没有真正定义的,所以类型都返回undefined逻辑上说得通。


数据类型


这个地方说法很多样,一般来说就是基本数据类型(undefined null string number boolean)和引用类型(object)。

基本数据类型也叫值类型,简单数据类型

类型识别

  • typeof

    • 只能识别基本数据类型
    • 对null会返回object
    • function类型返回function
  • instanceof

    • 检测引用类型(包括自定义对象)
    • obj instanceof Object 始终都会返回true
  • constructor

    • 指向构造器,可以识别标准类型,内置对象,自定义对象
    • 不能识别undefined, null
  • Object.prototype.toString.call()

    • 识别标准类型和内置对象


基本数据类型

undefined null string number boolean

  • 使用typeof操作符能识别基本数据类型,返回的值是小写的英文字符串
  • 因为null是对空对象的一个引用,所以使用typeof返回其类型时会返回object
undefined null
  • undefined是从null派生出来的,所以undefined == null会返回true,但是undefined === null会返回false

  • null是对空对象的引用


Boolean

类型转换

数据类型 -> true -> false
Boolean true false
String 非空字符串 空串
Number 非0的数 0和NaN
Object 任何对象 null
Undefined n/a undefined


Number

提供了Number(), parseInt(), parseFloat()三个函数

在使用转型函数Number()或者需要隐式转化为数值类型的情况下,遵守以下规则

  1. boolean类型:true为1,false为0

  2. string类型:

  • 非空字符串:

    • 只包含数字的字符串,会转为数值,0开头的话直接抹掉0

    • 其他格式(不管数字开头的或者非数字开头还是别的格式),都会转换成NaN,和parseInt()不一样

  • 空串为0

  1. null: 0

  2. undefined:NaN

parseInt():

  • 允许传入两个值,第二个值可以是要转为哪种进制的基数
  • 传入字符串时,只要开头有数字,就会把连续的数字转为数值

parseFloat()只能转入一个值,且js里的浮点数计算精度会有问题


String
  • 调用toString即可以实现大部分的转换

  • toString允许传入一个基数,把数值类型的值转为指定进制的字符串

  • undefined和null没有toString方法,只能用String转型函数


引用类型

  • Object Array Date RegExp Function

  • 基本包装类型 String Number Boolean

  • 单体内置对象 Global Math


Object


说白了就是一组名值对,一个属性名对应一个属性

实例化方式
  • new

    1
    2
    var obj = new Object();
    var obj2 = new Object({name:"Conan"});
  • 对象字面量

    1
    2
    var obj = {};
    var obj2 = {name:"Conan"};

这种方式看起来简约大方于是用的很多:)

同时使用这种方式可以方便的进行参数传递:

1
2
3
4
5
6
7
8
9
10
11
function foo (name, age) {
var this.name = name;
var this.age = age;
}
foo("Conan",25);
function bar (args) {
var this.name = args.name;
var this.age = args.age;
}
bar({name:"Conan",age:25});

我觉得这种方式瞬间爆炸……因为有事没事写那么多变量名谁记得住啊……用这个的话,可以增加变量的可选性

属性访问方式

. []

Object实例属性和方法
  • constructor
  • hasOwnProperty
  • isPrototypeOf
  • propertyIsNumerable(能否枚举)


Array


实例化方式
1
2
3
var arr = new Array();
var arr = Array();
var arr = [];

使用Array()构造实例的时候允许传递一个值,如果是一个数值的话,则建立一个对应长度的数组,一个以上数值的话,每个数值都是数组的一项。如果是一个或多个字符串,与一个以上数值一样。

1
2
3
var arr = new Array(20); //arr.length为20
var arr = new Array(10, 20); //arr.length为2
var arr = new Array("red","blue","yellow") //arr.length为3


检测类型
  • instanceof value instanceof Array

  • Array.isArray Array的一个方法


实例方法
0. 转换方法 join


1. 栈方法 pop push


2. 队列方法 shift unshift


3. 排序方法 reverse sort

sort支持传入一个函数进行排序

1
2
3
4
5
6
7
8
9
function(a,b){
if( a > b ){
return 1;//前者排列在后者的后面,返回正数
}else if( a < b ){
return -1;//前者排列在后者的前面,返回负数
}else{
return 0;//两数相等返回0
}
}

sort对字符串排序或者数字排序,默认是按照字符编码顺序排列的


4. 操作方法 concat slice splice

concat 后面不传入值或者数组,则拷贝当前数组的副本

slice slice(start, end)

splice splice(start, length, (item1, item2, …))


5. 位置方法 ES5中定义了indexOf lastIndexOf


6. 迭代方法 ES5中定义了every some filter map forEach

其中前面四个都是要求执行函数然后返回一个结果的,对原始数组不影响,最后一个和for-in差不多,只是执行函数

这几个方法接受两个参数,要执行的函数和函数作用域对象(可选)。函数接受三个参数,数组项的值,数组项的位置,数组自身,也即item, index, array

  • every() 执行函数,如果每项返回true,则返回true
  • some() 执行函数,如果有一项返回true,则返回true
  • filter() 执行函数,返回每一项返回true构成的数组。其实就是筛选出满足条件的部分
  • map() 执行函数,返回每一次函数执行后结果构成的数组
  • forEach() 执行函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
var arr = [1, 5, 2, 6, 3, 0, 4, 1, 2, 3, 4];
var rst_every = arr.every(function(item,index,array){
return item > 3;
})
var rst_some = arr.some(function(item,index,array){
return item > 3;
})
var rst_filter = arr.filter(function(item,index,array){
return item > 3;
})
var rst_map = arr.map(function(item,index,array){
return item -= item;
})
var temp = [];
var rst_forEach = arr.forEach(function(item,index,array){
// 去重
if(temp.indexOf(item) == -1){
temp.push(item);
}
})
console.log(rst_every); //false
console.log(rst_some); //true
console.log(rst_filter); //[5, 6, 4, 4]
console.log(rst_map); //[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
console.log(temp); //[1, 5, 2, 6, 3, 0, 4]


7. 归并方法 ES5中定义了reduce reduceRight

reduce从左边开始归并,reduceRight从右边开始归并

这两个方法都要求传入一个执行函数,函数传入的参数包括上一项的值,当前项值,当前项的位置,数组,即prev cur index array

1
2
3
4
5
6
7
8
9
10
var arr = [1, 2, 3, 4, 5] ;
var sum;
sum = arr.reduce(function (prev, cur, index, array) {
return prev + cur;
})
var count = 0;
rst = arr.map(function (item, index, array){
count += item;
})

最后的计算结果,sum和count的值是一样的。

因为数组的第一项没有prev,所以归并是从第二项开始的


Date


简单记一下

实例化,new Date()

getTime
getYear()
getFullYear()
getMonth 0-11
getDate 一个月中的天数,1-31
getDay 一个礼拜中的天,0是周日,6是周六
getHour 0-23
getMinutes 0-59
getSeconds 0-59
getMilliSeconds

把get换成getUTC又是一条好汉
把get换成set又是一条好汉

getWeek !!!没有week


RegExp


构建实例
  • 字面量
  • 构造器RegExp
实例属性
  • global
  • ignoreCase
  • multiline
  • lastIndex 下一次要开始匹配的位置
  • source 模式自身
实例方法
  • exec()

    • 返回一个数组,匹配项,index(匹配项的起始位置), input(捕获组)
  • test()

    • 匹配成功返回ture,失败返回false
构造器属性
  • lastParen 上一个捕获组
  • lastMatch 上一个匹配项
  • leftContext
  • rightContext
  • input


Function


函数名是指针,函数体是对象

创建函数实例
1
2
3
4
5
6
7
8
9
10
//函数声明
function func () {
statement
}
//函数表达式
var func = function () {} ;
//构造函数
var func = new Function("name","age","return name + age") ;
  • 函数声明和表达式没有本质区别

  • 执行环境初始化时,函数声明会提前,函数表达式不会;同样提前的会有变量声明和形参;

  • 函数的参数传递是值传递

函数内部对象
arguments
  • arguments代表实参集合

    1
    2
    3
    4
    5
    6
    7
    8
    var color1 = "red",
    color2 = "blue",
    color3 = "yellow";
    function getColor (color1, color2, color3) {
    console.log(arguments[0]); //"red"
    console.log(arguments[1]);//"blue"
    console.log(arguments[2]);//"yellow"
    }
  • arguments.callee
    callee属性指向自身函数
    主要是消除函数名耦合带来的不便

this
  • 当前执行环境
  • 函数或者事件的调用对象
函数属性
  • caller指向该函数的调用者

  • length表示函数要接受的形参个数

  • prototype函数的原型
    ES5中规定prototype属性不可枚举,所以for-in对它没啥用

函数方法
  • apply call

    • 用来扩展函数的作用域,其实就是让别的函数或者对象也可以拥有该函数的特定方法

    • apply和call都接受两个参数,第一个是要指定的作用域,第二个数、是参数

    • 关于参数

      • apply要求必须是一个arguments参数组或者是Array实例,如果不是函数体内调用的话,无法使用arguments对象

      • call要求写明每个参数的具体是什么

      • 这个参数的值就是指定的作用域要调用该函数时,该函数需要的参数的值

  • bind 创建一个新的函数实例,并且把作用域绑定到传入bind()的值上

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
window.color = "yellow";
var obj = {color:"red"};
function sayColor (color) {
// this.color = color ;
console.log(this);
console.log(this.color);
console.log(color);
}
sayColor.call(obj, "cyan");
sayColor.apply(obj, ["cyan"]);
var sayColor2 = sayColor.bind(obj);
sayColor2("blue");
// console.log(sayColor2);


基本包装类型 String Number Boolean


不建议用基本包装类型String() Number() Boolean()构建实例来创建对象,因为他们创建的都是对象,不是数值类型

Number

方法

  • toFixed() 四舍五入到指定位数

  • toExponential() 科学技术到指定位数

  • toPrecision() 自动选择上面的一种


String

属性 length

方法

  1. 字符方法 charAt() charCodeAt()

  2. 位置方法 indexOf() lastIndexOf()

    • 传入两个参数,第二个为开始匹配字符的位置
  3. 操作方法

    • concat

    • slice (start,end) 接受负数

    • substring (start,end) 不接受负数,负数都装换成0

    • substr (start,length) 第一个参数接收负数,第二个参数会把负数转成0

  4. 大小写转换 toUpperCase() toLowerCase()

  5. 模式方法

    • match 传入RegExp实例或者一个正则表达式,返回匹配的模式

    • search 传入值同上;只返回第一个匹配的到的模式的位置

    • replace 第一个参数为字符串或者正则表达式,第二个参数可以是要替换的文本字符串或者是一个函数

      • function (match, postion, originalText) {}
    • split 分隔符可以是字符串也可以是正则表达式

  6. 字符串比较 lacaleCompare()

  7. trim方法

  8. 静态方法 fromCharCode()

    1
    2
    3
    4
    5
    6
    7
    //想知道字符数字对应的具体值是什么,随手写了一个
    var code = {};
    for(var i = 0; i < 900; i++) {
    code[i] = String.fromCharCode(i);
    }
    console.log(code);


单体内置对象 Math Global


  • Math

    • max min
    • floor
    • ceil
    • round
    • random
    • abs
    • 其他
  • Global

    • web浏览器中Global是指window对象
    • 全局方法
    • encodeURI encodeURIComponent
    • decodeURI decodeURIComponet
    • eval(),直接执行js代码,可以用于改变作用域。执行代码属于调用环境的一部分


值拷贝


  • 值类型的变量拷贝直接赋值即可,因为都是存在栈内存里的

  • 引用类型的变量拷贝要复杂一点,因为直接赋值,复制的只是一个引用指针,操作还是指向原有对象

    1
    2
    3
    4
    5
    var obj = {name:"lily", age:25};
    var obj2 = obj;
    obj2.age = 20;
    console.log(obj.age); //20
    console.log(obj2.age); //20
    • 针对数组类型的值,挨个遍历赋值就可以了

      1
      2
      3
      4
      5
      6
      var arr = [1, 2, 3];
      var arr2 = [];
      for(var i in arr) {
      arr2.push(arr[i]);
      }
      console.log(arr2);
    • 针对对象,因为对象本身就是一个名值对,每个值的value都有一个具体的数据类型,可能是基本类型可能是引用类型,所以要分情况

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      function deepClone (obj, cloneObj) {
      if(typeof obj != "object") return false;
      cloneObj = cloneObj || {};
      for(var i in obj) {
      if(typeof obj[i] === "object"){
      cloneObj[i] = (obj[i] instanceof Array) ? [] : {} ;
      arguments.caller(obj[i], cloneObj[i]) ;
      }else{
      cloneObj[i] = obj[i]
      }
      }
      return cloneObj;
      }