1. 本章主要介绍Javascript的7种基本数据类型为和 2种引用数据类型。区分原始数据类型和引用数据类型的关键为:原始数据类型存储在栈内存中,引用数据类型的存储则需要开辟单独的堆内存。
  2. 除了数据类型的介绍,本章还会介绍数据类型之间的相互转化,包括显示转换和隐式转换,需要知道的是,js是弱类型语言,声明的变量可以根据环境直接转换类型,这里主要介绍的是string/number/boolean之间的相互转换。
  3. 介绍完数据转换,我们需要了解数据检测的相关技巧,再JS中,最常见的是用typeof vari进行数据类型检测,但是还有其他三种方式我们也需要了解,以便于再typeof无法检测时进行弥补。
  4. 最后需要了解不同的数据类型有哪些自带的API,其中会着重介绍数组和字符类型。

本章思维导图:

variable_type

数据类型

  1. Number,数字类型,其中有几点需要注意

    1
    var i = 1;
    1. NaN,即Not a Number,属于数字类型,typeof NaN == ‘number’ 且NaN === NaN 为 false
    2. Infinity 代表无穷大, Infinity === Infinity -1 为 true
    3. 以0X开头的会被检测为十六进制数,比如 x = 0XFF,实际输出x为255
    4. Number.MAX_SAFE_INTEGER 获取最大安全数
  2. String,字符类型,通常用单引号/双引号/反引号包裹

    1
    var s = "w";
  3. Boolean,布尔类型,只有true/false两种值

    1
    var b = false;
  4. Symbol,唯一值类型,Symbol不和任何类型相等,且不能转化为字符类型,不然会报错

    1
    var s = Symbol('unique')
    1. 给对象设置唯一值
    2. 在vuex/redux中做行为派发的时候,统一管理派发行为,标识的值可以是唯一值
  5. Bigint,大数,用于计算超大整形数据

    1
    var b = BigInt(1);
    1. 比如 9007199254740991+4 = 9007199254740996,实际上结果应该是9007199254740995,但因为超过了JS规定的最大安全数,所以出现差错。
    2. 我们可以用大数来搞定计算: BigInt(9007199254740991) + BigInt(4) = 9007199254740995n
    3. 或者直接在数字后面加n,9007199254740991n + 4n = 9007199254740995n
  6. null,空,表示此处不应该有变量或值,通常用于下面几个地方

    1. 作为对象原型链的终点
  7. undefined,未定义,表示此处应该有值,但是还有没定义,通常用于以下几个地方

    1. 函数调用时,没有提供参数
    2. 函数执行返回值
    3. 获取对象没有赋值的属性
    4. 变量声明但没有赋值
  8. Object,对象数据类型,又分为以下几个细类:

    1
    2
    3
    4
    var obj = {
    name: 'zen',
    age: 19
    }
    1. RegExp,正则类型,通常用模式包裹//
    2. Date,日期数据类型
    3. Array,数组数据类型
    4. Math,数学函数
  9. Function,函数类型

    1
    var fn = function(){}
    1. 函数类型会在之后的文章里继续介绍,这里主要介绍原始数据类型

类型转化

类型转化有四个方面:其他值转为数字类型、其他值转为字符串类型、其他值转为布尔类型、==比较

any -> number

将其他类型转化为数字类型,显示转换:Number() 和 parseInt()。

Number() 会把传入的value转为数字类型,一旦发现传入值不能转为数字类型,则返回NaN。

  • Number会把true/false转为1/0,把null转为0,undefined转为NaN,空字符串转为0
  • 不能把Symbol对象转为数字,会报错
  • 对象类型转为数字,要先转化为字符串,然后转为数字,对象类型转为字符串为 [object Object]
  • 数组类型转为字符串会将中括号替换为双引号,即String([1,2,3]) ==> “1,2,3” String([3]) => “3”
  • 函数转为数字结果都是NaN

parseInt() 会把传入的value先转为字符串类型,然后从第一项开始,一直遍历到非数字的那一项,返回所有数字项,如果没有则返回NaN

隐式转换

  • 数学运算:+号运算,在出现字符串的情况下,不是数学运算,而是字符串拼接
  • - * / % 都是数学运算,要把其他类型值基于Number()转为数字类型计算,如果转不了,就是NaN(字符串中只要出现非有效数字就是NaN,空字符串 = 0)
  • == 比较:有些值需要转为数字类型再比较,比如true/false 和数字比
  • isNaN(value), isNaN中value如果不是数字,会尝试用Number转化为数字
  • value++ / +value / ++value 都是转为数字之后再处理value

进制转换

1
2
3
4
5
6
var myNumber = 32;
myNumber.toString(10); // returns 32
myNumber.toString(32); // returns 10
myNumber.toString(16); // returns 20
myNumber.toString(8); // returns 40
myNumber.toString(2); // returns 100000

实例转为数字,调用的是valueOf方法,重写valueOf方法以验证

1
2
3
4
5
6
7
8
9
10
let num = new Number(100);
num.valueOf = function(){
console.log('invoke valueOf function')
return 100
}
console.log(num + 10);
/*
* invoke valueOf function
* 110
*/

[1] 例 转为数字

1
2
3
4
5
6
7
8
9
10
11
12
Number('12px') ==> NaN
Number('') ==> 0
Number(true) ==> 1
Number(false) ==> 0


parseInt() 会把传入的value先转为字符串类型,然后从第一项开始,一直遍历到非数字的那一项,返回所有数字项,如果没有则返回NaN
parseInt('12px') ==> 12
parseInt('') ==> NaN
parseInt([]) ==> NaN ,因为数组会先转为字符串''

console.log(isNaN([])); // false 表示[] 是一个数,isNaN采用Number进行隐式转换

[2] 例

1
2
3
let arr = [10.18,0,10,25,23];
arr = arr.map(parseInt);
console.log(arr);

解析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
arr = arr.map((item,idex) => {
// 循环遍历数组中的某一项就会触发回调函数
// 每一次还会传递当前项和当前索引
})

parseInt([value],[radix])
-> [radix] 这个值是一个进制,不写或者写0默认都按照10进制处理(特殊情况:如果value是以0x开头,则默认是16进制
-> 进制有取值范围 2~36 ,如果不在这之间,整个程序运行的结果一定是NaN
-> 把[value]看做[radix]进制,最后把[radix]进制转化为十进制

parseInt('10.18',0(10))
从字符串左侧第一个字符开始查找,找到符合[radix]进制的值,(遇到不合法的,则停止查找),把找到的值变为数字,再按照[radix]转换成十进制的规则处理
例如:
parseInt('25',3)
==> 3进制取值为 0 1 2 ,找value符合012的值,发现只有2符合
==> 2 当做3进制转为10
==> 2转为10进制
2*3^0 = 2
所以做的值是 2

[3] 例

1
2
3
4
5
6
7
8
9
10
console.1og([10] == '10'); //=>'10'=='10' true
console.1og({} == '{}'); //=>'[object Object]'=='{}' false
console.1og(1 == true); //=>1==1 true
console.log(2 == true); //=>2==1
console.1og(-1 == false); //=>-1==0 false
console.1og(0 == false); //=>0==0 true
console.1og(1 == '1'); //=>1==1 true
console.1og(true == '1'); //=>1==1 true
console.log(false == ''); //=>0==0 true
console.1og([] == 0); //=>0==0 true

[4] 例 a++和a+=1

1
2
3
4
var a = "1";
var b = "-1"
console.log(a++); // 2
console.log(b+=1); // -11

any -> string

把其他数据类型转为字符数据类型

  1. value.toString() / String(value)
  2. 隐式转换(一般是调用toString方法)
    1. 在 “+”号运算中,如果左右两边出现字符串(或者是部分对象值)则不是数学运算,会变为字符串拼接
    2. 基于alert/confirm/propmt/document.write 这些方式输出内容,需要先转为字符串,然后输出
    3. 模板字符串实现的是字符串拼接,对象会转换为字符串
    4. 其余的数学运算中,例如 “- / * %” 会把对象转为数字
    5. “==” 比较的时候,也会把对象转为字符串

[1] 例 如何把一个对象转为数字/字符串

  • 首先查找对象的 Symbol.toPrimitive 属性
  • 如果不存在,就调用 valueOf 方法获取对象的基本类型值
  • 如果找不到原始值,则调用 toSrring & Number 转换为字符串或者数字
  • 因为只有对象上toString方法是用于检测数据类型的,所以结果为 [ Object object ]

验证toPrimitive和自定义方法

1
2
3
4
5
obj[Symbol.toPrimitive] = function(hint){
console.log(hint) // 浏览器会根据上下文判断这个类型,默认default,当前上下文中为number
return 100;
}
console.log(10 + obj) // => 110

[2] 例

1
2
3
4
5
6
7
8
9
// 普通对象转为字符串都是[object Object],数组对象转为字符串都是 "第一项,第二项,..."
String(10)
console.log(10-null) // => 10
console.log(3*undefined) // => NaN

// 需要注意的是,加号两边都需要是数字,不然就会变成字符串拼接
console.log(1+'1') // => 11
console.log([10] + true); // => 10true
console.log(100 + true + 21.2 + null + undefined + "Tencent" + [] + null + 9 + false); // => NaNTencentnull9false

[3] 例 特殊情况

1
2
{} + 0 ? console.log("ok"):console.log("no"); // ==> no ,大括号被当作代码块,不参与运算
0 + {} ? console.log("ok"):console.log("no"); // ==> ok

any -> boolean

  1. !value 转为布尔值后取反
  2. !!value 转为布尔类型
  3. Boolean(value)
  4. 隐式转换:
    在循环或者条件判断中,条件处理的结果就是布尔类型值

规则:只有”NaN,0,null,undefined,空字符串“ 这5个值会变为布尔的false,其余都是true

== 比较的过程中,数据转换的规则:

  1. 类型一样的几个特殊点:
    {} == {} ==> false 对象比较的是堆内存的地址,即使对象相同,地址也不同
    [] == [] ==> false
    NaN == NaN ==> false

  2. 类型不一样的比较规则
    null == undefined ==> true,但是换成 === 结果就是false,剩下的null/undefined和其他任何数据类型都不相等
    字符串 == 对象 ,需要把对象转为字符串后,再进行比较
    剩下的如果 == 两边的数据类型不一致,都是需要转为数字再进行比较的

[1] 例

1
2
if(3 + '3px') {} // true
if(3 - '3px') {} // false => 3-NaN => NaN

[2] 例

1
2
3
4
5
6
7
console.log([] == false); // ===> true
/*
对象 == 布尔 都转为数字(隐式转换)
[] ==> '' --> 0
false --> 0
0 == 0 : true
*/

[3] 例

1
2
3
4
5
console.log(![] == false); // ===> true
/*
![] 把数组转为布尔类型后取反 false
false == false == true
*/

类型检测

分类

  • 基本数据类型: number string boolean null undefined symbol BigInt
  • 引用数据类型: object(普通对象,数组对象,正则对象,日期对象)、function

几种检测机制

  • typeof [value] 检测数据类型的运算符
  • [example] instanceof [class] 检测某一个实例是否属于这个类
  • [example].constructor === [class] 检测实例和类的关系,从而检测数据类型
  • Object.prototype.toString.call([value]) 检测数据类型

typeof

用法

1
typeof 1  ==> "number"
  • 返回结果是一个字符串,字符串中包含了对应的数据类型:number/string/boolean/undefined/symbol/bigint/object/function
  • NaN/Infinity 都是数字类型
  • 多个typeof检测,最后结果都是string
  • typeof null ==> "object" && typeof不能细分对象因为typeof是按照计算机底层存储的二进制结果来进行检测的,对象(不管是日期对象还是正则对象等)都是以000xxx存储的,null的二进制存储值为000000,所以typeof检测null的结果就是对象类型
  • typeof无法区分普通对象和数组对象,因为对象都是000开头的,typeof只检测前三位

instanceof

用法:

1
2
3
4
5
6
7
8
1 instanceof Number ==> false

var arr = [1,2,3];
arr instanceof Array ==> true
arr instanceof Object ==> true

var e = /^$/;
e instanceof RegExp ==> true
  • instanceof并不是用来检测数据类型的,只是用来检测当前实例是否属于这个类
  • 一般只用于普通对象/数组对象/正则对象/日期对象的具体细分
  • instanceof不能区分数组对象和普通对象
  • instanceof无法应用到原始类型(string/number….)检测上
  • 当原型链改变时,instanceof会失效

instanceof的原理:

实例 instanceof 类检测时,底层找的是Function.prototype[Symbol.hasInstance]这个方法,比如检测arr对象是否属于数组类型(arr instanceof Array),会将其转化为如下形式:

1
Array[Symbol.hasInstance](arr)

Symbol.hasInstance方法执行原理:

  1. 如果当前实例的原型链上是否存在这个类的原型,则结果为true

instanceof检测arr时,即是数组又是对象是因为:

  • arr.__proto__ === Array.prototype
  • arr.__proto__.__proto__===Object.prototype
instanceof array

constructor

用法:

1
2
arr.constructor === Array  ==>true
(1).constructor === Number ==>true

constructor检测原理:

constructor和instanceof类似,只不过instanceof查找的是原型链,而constructor查找的是变量的constructor属性。

constructor
  • arr.constructor === Object ==> false,arr的往下查找,在Array.prototype上就有constructor方法,找到直接返回,不再继续查找,所以arr调用constructor检测到类型不是Object
  • constructor可以检测字面量,即1,false这些值,浏览器会默认转化字面量为对象类型(Object(1))
  • 一旦原型重定向,constructor也会更改,所以检测不准确

Object.prototype.toString.call()

用法:

1
Object.prototype.toString.call(1) ==> "[object Number]"
  • 除了Object下面的toString方法不是用来转化字符串的,其他都是用来转化为字符串的,Object原型上的toString方法是用来检测数据类型的。
  • 返回结果为:"[object 对象[Symbol.toStringTag] || 对象构造函数(不受更改影响,对内置有效) || Object ]"
  • Object.prototype.toString.call(val),call是用来改变this的,或者写为:({}).toString.call(val)

Object如果检测class类型返回结果是:"[object Function]",如果想要加上自己的类型,根据返回结果公式,可以在对象上重写Symbol.toStringTag

1
2
3
4
5
6
7
8
9
10
11
class Person {
get[Symbol.toStringTag]() {
return "Person";
}
}

let p = new Person();

console.info(
({}).toString.call(p) //==> "[object Person]"
);

类型方法

Number

保留小数点后两位

1
(1.11111111).toFixed(2) 	// "1.11"

String

字符串常用方法:

  1. charAt/charCodeAt/String.fromCharCode/ 获取字符串中指定位置字符的办法
  2. substr/substring/slice 字符串查找和截取
  3. split 字符串转化为数组的方法
  4. indexOf/lastIndexOf 字符串查找是否包含某个字符
  5. replace 字符串替换
  6. toUpperCase/toLowerCase 字符串大小写转换
  7. trim 删除字符两边的空白
  8. localeCompare/match 其他

记忆时需要考虑的点:

  1. 方法的作用
  2. 方法参数
  3. 方法返回值

字符串中无需记忆原始字符串是否改变,因为它是基本类型,每一个操作都是直接操作值,对原始字符串不会产生任何影响;数组需要记住原数组是否改变,因为数组是对象类型,操作的是堆内存,方法执行可能会把原始堆内存信息改变

为了便于下面操作,我们先定义一个字符串:

1
2
3
4
var line = `She does not know 
her beauty,
she thinks her brown body
has no glory.`

获取字符串中指定位置字符

1
2
3
4
line[1] 				// "h",如果索引不存在,返回undefined
line.charAt(1) // "h",如果索引不存在,获取到的是空字符串
line.charCodeAt(1) // 104 获取指定字符的UNICODE编码(ASCII码表中的值)
String.fromCharCode(104) // "h"

字符串查找和截取

1
2
3
4
substr/substring/slice 
line.substr(4,8) // "does not" 从N开始,截取M个字符
line.substring(4,8) // "does" 从索引N开始,找到索引为M处,不包含M
line.slice(4,8) // "does" 和substring是一样的,两个都是索引,只不过slice支持以负数作为索引

字符串转化为数组的方法

1
2
line.split('\n') // 把字符串拆分为数组,默认以空格拆
 ["She does not know ", "her beauty,", "she thinks her brown body", "has no glory."]

字符串查找是否包含某个字符,如果不存在,则返回-1

1
2
line.indexOf('s')				// 7  查找字符第一次出现的位置
line.lastIndexOf('s') // 59 查找字符第二次出现的位置

字符串替换

1
2
line.replace('she','he') 	// 默认只替换一次
line.replace(/her/g,'his') // 替换全部需要用正则

Array

数组常用方法:

  1. Array.isArray() 判断是否为数组
  2. push/pop/shift/unshift 增删
  3. slice/concat/splice 截取
  4. toString/join 转字符串
  5. indexOf / lastIndexOf / includes / find/findIndex 是否包含
  6. reverse/sort 排序
  7. forEach/map/filter/some/some/reduce 迭代

ps:类数组如NodeList不能够使用数组方法,因为类数组的原型指向是Object,数组的原型指向是Array,所以类数组上没有数组方法,可以可以采用以下方法来解决

1
2
3
4
5
6
7
8
9
10
11
12
1. 解决方法1:改变this,实现方法借用(OBJ需要和数组结构一样)
Array.prototype.forEach.call(obj,item=>{
console.log(item)
})

2. 解决办法2:改变原型指向
obj.__proto__ = Array.prototype;
obj.forEach( item=>{ console.log(item) })

3. 解决办法3:把需要用到的方法作为obj的一个私有属性
obj.each = Array.prototype.forEach;
obj.each(item => { console.log(item) });

记忆角度

  1. 方法意义和作用

  2. 参数(执行时候传递的内容)

  3. 返回值

  4. 原始数组是否改变

选定初始数组

1
2
3
let lrry = ["She does not know ", "her beauty,", "she thinks her brown body", "has no glory."]
let arr_length = 4;
let res = -1;

判断是否为数组

1
Array.isArray(lrry) 	// true

增删

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
/*  @func:   push,向数组末尾添加新值
* @params: 添加的值 【 push into tail 】
* @return: [Number] 新增数组的长度 【 5 】
* 原始数组改变
*/
res = lrry.push('push into tail')

/* @func: pop,删除数组末尾元素
* @params: 无
* @return: 删除的那一项的值 【 push into tail 】
* 原始数组改变
*/
res = lrry.pop()

/* @func: unshift,向数组开头添加新值
* @params: 添加的值 【 shift into head 】
* @return: [Number] 新增数组的长度 【 5 】
* 原始数组改变
*/
res = lrry.unshift('shift into head')

/* @func: shift,删除数组开头元素
* @params: 无
* @return: 删除的那一项的值 【 shift into head 】
* 原始数组改变
*/
res = lrry.shift()
console.log(res)

截取

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
/*  @func:   splice,从数组索引 n 开始 删除 m 个元素,把新数组返回,原数组改变,同时支持把删除部分替换为指定值
* @params: 初始索引,截取个数,[newValue]
* @return: 截取到的新数组
* @res: ["her beauty,", "she thinks her brown body", "has no glory."]
* @lrry: ["She does not know ", "hi"]
* @special: res = lrry.splice(1,0,'hi'); 在index=1后面新增一项
*/
res = lrry.splice(1,3,'hi');

/* @func: slice,从数组索引n开始找到m,把查找内容以新数组的方式返回,原数组不变
* @params: 初始索引,结束索引
* @return: 截取到的新数组
* @special: res = lrry.slice() 截取所有
*/
res = lrry.slice();


/* @func: concat,数组拼接,多个数组作为参数,返回结果是拼接后的数组,原始数组不变
* @params: 字符串/数组
* @return: 截取到的新数组 一维数组
*/
res = lrry.concat('A User','C How',['D Quenue']);

数组转为字符串

1
2
3
4
5
6
7
8
9
10
11
/*  @func:   toString,数组转为字符串,用,连接每项
* @params:
* @return: 字符串
*/
res = lrry.toString()

/* @func: join 将数组转为字符串
* @params: 连接符,默认是,
* @return: 字符串
*/
res = lrry.join('\n')

验证释放包含某项

1
2
3
4
5
res = lrry.indexOf("her beauty,") // 返回该项第一次出现的下标,如果没有,则返回-1

res = lrry.lastIndexOf("her beauty,") // 返回该项最后一次出现的下标,如果没有,则返回-1

res = lrry.includes("her beauty,") // true, 判断是否包含,返回true/false

find 返回数组中满足提供的测试函数的第一个元素的值。否则返回undefined

1
2
3
4
5
6
7
8
9
10
11
var inventory = [
{name: 'apples', quantity: 2},
{name: 'bananas', quantity: 0},
{name: 'cherries', quantity: 5}
];

function findCherries(fruit) {
return fruit.name === 'cherries';
}

console.log(inventory.find(findCherries)); // { name: 'cherries', quantity: 5 }

排序

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
/*  @func:   reverse 将数组逆序,返回结果是逆序后的数组,原始数组改变
* @params:
* @return: 数组
*/
res = lrry.reverse()


/*
sort() 数组排序,默认不是按照每一项的数值大小排序,而是按照每一项的字符编码进行比较排序的,所以导致直接写sort不能处理两位及两位以上的内容排序
sort会先按照第一项的localeCompare排序,如果是多位数排序,会先按照高位比较排序,比如:
arr = [110,2,23,49,222,444,333]
排序结果是:
 [110, 2, 222, 23, 333, 444, 49]
原理: '110'.localeCompare('2') == -1 ===> '110' < '2' ,以此排序
sort() 想要按照数值排序,需要用到回调函数
*/

arr = [110,2,23,49,222,444,333]
arr.sort(function(a,b){
return a-b; // 升序
});

// 对象排序
var cars = [
{type:"Volvo", year:2016},
{type:"Saab", year:2001},
{type:"BMW", year:2010}
];
cars.sort(function(a, b){return a.year - b.year});

数组迭代

1
2
forEach // 循环遍历数组,不支持返回值 
map // 支持返回值,不改变原数组,返回结果是修改后的新数组

forEach

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
arr.forEach((item,index)=>{
// 此函数会被循环执行 arr.length 次
// item 当前遍历这一项的内容
// index 当前项的索引
})

// example
lrry.forEach((item,index)=>{
res = `[ ${index} ] ${item}`
console.log(res)
})
/* output:
* [ 0 ] She does not know
* [ 1 ] her beauty,
* [ 2 ] she thinks her brown body
*/

filter 过滤数组中的条目

1
2
3
4
5
6
7
8
9
10
res = lrry.filter((item,index,arr)=>{
// item 当前遍历项
// index 当前项索引
// arr 调用filter的数组,这里是lrry
return item.length > 15;
})
/*
@res  ["She does not know ", "she thinks her brown body"]
@lrry ["She does not know ", "her beauty,", "she thinks her brown body", "has no glory."]
*/

map支持返回值,但是不会改变原来的数组,执行完的返回结果是修改后的新数组

1
2
3
4
5
6
7
8
9
10
11
12
13
14
res = lrry.map((item,index,arr)=>{
// item 当前遍历项
// index 当前项索引
// arr 调用filter的数组,这里是lrry
return `${index}) ${item}`
})


/*
@res ["0) She does not know ", "1) her beauty,", "2) she thinks her brown body", "3) has no glory."]
@lrry ["She does not know ", "her beauty,", "she thinks her brown body", "has no glory."]
*/


every,返回值为true/false,只有所有item满足条件,才会返回true

1
2
3
4
res = lrry.every((item,index)=>{
return item.length > 15
})
console.log(res) // false

some,返回值为true/false,只要有一个满足条件,就会返回true

1
2
3
4
5
res = lrry.some((item,index)=>{
return item.length > 15
})

console.log(res) // true

reduce 对数组中的每个元素执行一个由您提供的reducer函数(升序执行),将其结果汇总为单个返回值。

reduce接收四个参数

  1. Accumulator (acc) (累计器)
  2. Current Value (cur) (当前值)
  3. Current Index (idx) (当前索引)
  4. Source Array (src) (源数组)
1
2
3
4
5
6
7
8
9
10
arr.reduce(callback(acc, cur, idx, src]),initialValue)
// 如果initialValue存在,则初始值为initialValue,从数组第0项开始计算,循环arr.length次
// 如果initialValue不存在,则初始值为arr[0],从数组第一项开始计算,循环arr.length-1次

// 数组求和
let arr = [11, 2, 24, 3, 5]
res = arr.reduce((acc, cur, idx) => {
return acc + cur
}, 0)

count/第几次 acc/累计值 cur/当前项 idx/下标 returnVal/返回值
1 0 11 0 11
2 0+11 = 11 2 1 13
3 11+2 = 13 24 2 37
4 13+24=37 3 3 40
5 37+3 = 40 5 4 45

Date

JS默认时间格式:Wed Mar 25 2015 08:00:00 GMT+0800 (中国标准时间)

需要注意的是,获取日期和返回日期的函数中,获取月份需要+1,比如现在是2020年9月29日,使用getMonth()获取到的数字为8。

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
var date = new Date();
// 获取时间日期
getFullYear() 获取年份,返回如2020数字值
getMonth() 获取月份,返回0-11
getDate() 获取日期,返回1-31
getHours() 获取小时,返0-23
getMinutes() 获取分钟,返回0-59
getSeconds() 获取秒钟,返回0-59
getTime() 获取自1970-01-01时,到现在的总秒数
getDay() 获取星期,返回0-6

// 剩下的还有获取UTC时间
getUTCDate
getUTCDay
getUTCFullYear
getUTCHours
getUTCMilliseconds
getUTCMinutes
getUTCMonth
getUTCSeconds

// 设置时间日期
setDate(1-31)
setFullYear()
setHours(0-23)
setMilliseconds(0-999)
setMinutes(0-59)
setMonth(0-11)
setSeconds(0-59)
setTime()

UTC、GMT、ISO、CST几种时间日期之间有什么区别?

GMT(Greenwich Mean Time)格林尼治时间

UTC(Coordinated Universal Time)世界统一时间

CST(China Standard Time)中国时间标准

UTC和GMT表示的是时间标准,而ISO 8601是时间和日期的表示法

UTC与GMT的含义相同,只不过UTC比GMT更加精准。

世界标准时间相比中国北京时间早8小时

1
2
3
4
5
6
var d = new Date();
d.toISOString() ==> "2020-09-29T14:30:54.109Z"
d.toGMTString() ==> "Tue, 29 Sep 2020 14:30:54 GMT"
d.toUTCString() ==> "Tue, 29 Sep 2020 14:30:54 GMT"
d.toLocaleDateString() ==> "2020/9/29"
d.toLocaleString() ==> "2020/9/29 下午10:30:54"

Math

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
typeof Math; // => 'object'
console.dir(Math);
Math.PI //=> 获取圆周率
Math.abs(-12) // 获取数字的绝对值,如果传入的不是数字,则先用Number转为数字,如果不能转为数字,则返回NaN
Math.ceil(12.3) // => 13 向上取整
Math.floor(12.3) // => 12 向下取整
Math.round(12.4) // => 12 四舍五入
Math.max(12,34,123,42) //=> 获取一堆值中的最大值,不能传入数组,数组为运算结果为NaN
Math.min(12,34,123,42) //=> 获取一堆值中的最小值
Math.pow(x,y) // 计算x^y
Math.sqrt(4) //=> 2 给数字开根方
Math.random() // 获取0~1之间的随机小数


// 获取[N,M] 之间的随机整数(包含,M)
Math.round(Math.random*(m-n)+n)
console.log(
Math.max([12,34,123,42]) //=> 获取一堆值中的% 13 + 33 最大值
)

for(let i = 0;i<10;i++){
// 获取 33~45 之间的随机整数
let ras = Math.round(Math.random() * 100 ) % 13 + 33
console.log(ras)
}