《大前端三问》 - JS中的数据类型、变量、函数

我们说程序=数据结构+算法,这表明了数据结构在一门语言中的重要性,他将是你所写的程序的主要构成。而变量是数据结构的载体,数据结构常常是一块特定结构的内存空间,而要引用这段内存空间,我们就需要操作变量。因为JS是一门弱类型的语言,因此它的变量的概念有点像C中的指针或Java中的引用,表示其内容就是其指向的这段内存结构。

本章我们将先了解JavaScript中的数据类型,不同数据类型代表不同的意义、也占用不同的内存空间。再看看变量,他如上面说的代表一份内存的载体,也代表着一个作用域。最后我们看下算法,js中的控制流程与函数。

JavaScript 是一种多范式的动态语言,它包含类型、运算符、标准内置( built-in)对象和方法。它的语法来源于 Java 和 C,所以这两种语言的许多语法特性同样适用于 JavaScript。

JavaScript通过原型链而不是类来支持面向对象编程。但是在ES6中,JS的概念得到了完整的定义,这个后面会详细学习之。

1 JavaScript中的类型

JavaScript中的类型包括:

  • Number(数字)
  • String(字符串)
  • Boolean(布尔)true/false
  • Function(函数)
  • Object(对象)
    • Function(函数 - 也因此JS支持函数式编程)
    • Array(数组)
    • Date(日期)
    • RegExp(正则)
  • 特殊
    • undefine (未定义)
    • null (空)
    • NaN
  • Symbol(ES2015 新增)

1.1 算术运算

JavaScript 支持标准的算术运算符,内置对象 Math(数学对象),用以处理更多的高级数学函数和常数:

javascript中的高级数学函数示例
1
2
Math.sin(3.5);
var circumference = 2 * Math.PI * r;

1.2 特殊值

  • NaN表示Not a Number,表示任何数字运算的错误,任何其它值与之计算也是NaN
isNaN函数
1
isNaN(value); // 用于判断一个值是不是NaN
  • 与其他类型不同,JavaScript 中的 null 表示一个空值(non-value),必须使用 null 关键字才能访问,undefined 是一个“undefined(未定义)”类型的对象,表示一个未初始化的值.

体会一个这之间的不同与相同:一方面他们的本质相同,都是空;但是他们表示的意义不同,undefined是变量未定义,而null表示对象是空值。

示例
1
console.log(undefined == null); // true

1.3 字符串

JavaScript中使用的字符串都是Unicode字符串。更准确地说,它们是一串UTF-16编码单元的序列,每一个编码单元由一个 16 位二进制数表示。每一个Unicode字符由一个或两个编码单元来表示。

1.4 数组

JavaScript 中的数组是一种特殊的对象。它的工作原理与普通对象类似(以数字为属性名,但只能通过[] 来访问),但数组还有一个特殊的属性——length(长度)属性。这个属性的值通常比数组最大索引大 1。

创建一个数据可以使用new语句,也可以直接使用数组字面量语法:let arr = ['a', 'b', 'c']

关于数组元素可以使用访问时扩展这样的”骚操作”,如下面的示例:

数组的基本操作
1
2
3
4
5
6
7
8
var a = new Array();
a[0] = "dog";
a[1] = "cat";
a[2] = "hen";
a.length; // 3

// 数组字面量语法
let arr = ['a', 'b', 'c'];

可以对数据用for-in来遍历,或是用forEachmap等函数式的方法。

数组基本方法
1
2
3
4
5
6
7
8
9
10
11
12
arr.toString()	 // 返回一个包含数组中所有元素的字符串,每个元素通过逗号分隔。
arr.toLocaleString() // 根据宿主环境的区域设置,返回一个包含数组中所有元素的字符串,每个元素通过逗号分隔。
arr.concat(item1[, item2[, ...[, itemN]]]) // 返回一个数组,这个数组包含原先 a 和 item1、item2、……、itemN 中的所有元素。
arr.join(sep) // 返回一个包含数组中所有元素的字符串,每个元素通过指定的 sep 分隔。
arr.pop() // 删除并返回数组中的最后一个元素。
arr.push(item1, ..., itemN) // 将 item1、item2、……、itemN 追加至数组 a。
arr.reverse() // 数组逆序(会更改原数组 a)。
arr.shift() // 删除并返回数组中第一个元素。
arr.slice(start, end) // 返回子数组,以 a[start] 开头,以 a[end] 前一个元素结尾。
arr.sort([cmpfn]) // 依据可选的比较函数 cmpfn 进行排序,如果未指定比较函数,则按字符顺序比较(即使被比较元素是数字)。
arr.splice(start, delcount[, item1[, ...[, itemN]]]) // 从 start 开始,删除 delcount 个元素,然后插入所有的 item。
arr.unshift(item1[, item2[, ...[, itemN]]]) // 将 item 插入数组头部,返回数组新长度(考虑 undefined)。

2 变量

在 JavaScript 中声明一个新变量的方法是使用关键字 let 、const 和 var。

其中:

  • var表示声明一个全局作用域的变量;
  • const表示声明一个不可变的常量;
  • let表示声明一个块级作用域的本地变量(local variable);

下面的例子可以很好地解释varlet的作用范围:

解释作用域
1
2
3
4
5
6
7
8
9
10
11
12
13

const Pi = 3.14; // 设置 Pi 的值
Pi = 1; // 将会抛出一个错误因为你改变了一个常量的值。


var a = 10;
let b = 10;
{
var a = 5;
let b = 5;
}
console.log(a); // 5
console.log(b); // 10(local变量没有改变化)

3 流程控制

搞懂变量之后,对之对简单的应用就是流程控制了。JS的流程控制与C语法基本上差不多,这里就不作过多介绍了。无非就是

1
2
3
4
5
6
if - else
while
do-while
for
for-in
switch(js的switch支付字符串)

3.1 短路逻辑

js中的短路逻辑还是挺好用的,就是对于含&&||的逻辑表达式,是否会执行第二个语句(操作数)取决于第一个操作数的结果。也就是会在结果已定的情况下直接返回结果值。

比如:

短路逻辑示例
1
2
3
let receiveData = 'ok';
let responseData = receiveData || 'failed'; // 如果receiveData为空,则返回第二个字符串。非空则返回第一个字符串

4 函数

字义一个函数
1
2
3
function add(a , b) {
return a + b;
}

4.1 参数变量

函数中有一个特殊变量 – arguments!表示传进来的参数!!!如下面的方法,可以传入一个数组,则arguments就代表这个传入的数组

参数变量
1
2
3
4
5
6
7
function add() {
var sum = 0;
for (var i = 0, j = arguments.length; i < j; i++) {
sum += arguments[i];
}
return sum;
}

4.2 默认参数

默认参数
1
2
3
4
// 参数可以设置默认值,如下:
function add(a , b = 1) {
return a + b;
}

4.3 可变参数

可变参数...args,表示传入的参数数量是可变的,js会自动将之组织成一个数组。

可变参数
1
2
3
4
5
6
7
8
9
function avg(...args) {
var sum = 0;
for (let value of args) {
sum += value;
}
return sum / args.length;
}

avg(2, 3, 4, 5);

又比如我们熟悉的log方法:

log方法
1
log(message?: any, ...optionalParams: any[])

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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
parseInt('111',2);  // 输出7, 后面一位表示“进制”
parseFloat('10.3')

// -- 特殊值 --
isNaN(value)
console.log(undefined == null); // true

// -- 字符串 --
'hello'.length; // 5
// 索引
"hello".charAt(0); // "h"
'hello'[1]; // e
// 定位
"hello, world".replace("world", "mars"); // "hello, mars"
// 变换
"hello".toUpperCase(); // "HELLO"
'Hello'.toLowerCase();

// -- 数组的基本操作 --
var arr = new Array();
arr[0] = "dog";
arr[1] = "cat";
arr[2] = "hen";
arr.length; // 3
// 数组字面量语法
let arr = ['a', 'b', 'c'];
// 转字符串
arr.toString() // 返回一个包含数组中所有元素的字符串,每个元素通过逗号分隔。
arr.toLocaleString() // 根据宿主环境的区域设置,返回一个包含数组中所有元素的字符串,每个元素通过逗号分隔。
arr.join(sep) // 返回一个包含数组中所有元素的字符串,每个元素通过指定的 sep 分隔。
// 元素操作
arr.pop() // 删除并返回数组中的最后一个元素。
arr.push(item1, ..., itemN) // 将 item1、item2、……、itemN 追加至数组 a。
arr.shift() // 出队列(删除并返回数组中第一个元素)。
arr.unshift(item1[, item2[, ...[, itemN]]]) // 将 item 插入数组头部,返回数组新长度(考虑 undefined)。
arr.splice(start, delcount[, item1[, ...[, itemN]]]) // 从 start 开始,删除 delcount 个元素,然后插入所有的 item。
// 排序
arr.reverse() // 数组逆序(会更改原数组 a)。
arr.sort([cmpfn]) // 依据可选的比较函数 cmpfn 进行排序,如果未指定比较函数,则按字符顺序比较(即使被比较元素是数字)。
// 子串
arr.concat(item1[, item2[, ...[, itemN]]]) // 返回一个数组,这个数组包含原先 a 和 item1、item2、……、itemN 中的所有元素。
arr.slice(start, end) // 返回子数组,以 a[start] 开头,以 a[end] 前一个元素结尾。


// -- 短路逻辑示例 --
let receiveData = 'ok';
let responseData = receiveData || 'failed'; // 如果receiveData为空,则返回第二个字符串。非空则返回第一个字符串

// -- 函数 --
// 参数变量 arguments
function add() {
var sum = 0;
for (var i = 0, j = arguments.length; i < j; i++) {
sum += arguments[i];
}
return sum;
}

// 默认参数
function add(a , b = 1) {
return a + b;
}

// 可变参数
function avg(...args) {
var sum = 0;
for (let value of args) {
sum += value;
}
return sum / args.length;
}
avg(2, 3, 4, 5); // 调用使用可变参数的方法


6 引用

  1. 《重新介绍JavaScript》- 介绍JS很好的入门材料