数据类型的使用与python类似。
| 数据类型 | 说明 | 代码示例 |
|---|---|---|
| Number | 表示数字,包括整数和浮点数。支持科学计数法和十六进制表示。 | let age = 25; let price = 19.99; let count = 1.23e4;123; // 整数1230.456; // 浮点数0.4561.2345e3; // 科学计数法表示1.2345x1000,等同于1234.5-99; // 负数NaN; // NaN表示Not a Number,当无法计算结果时用NaN表示Infinity; // Infinity表示无限大,当数值超过了JavaScript的Number所能表示的最大值时,就表示为Infinity |
| String | 和python类似,表示文本数据,使用单引号或双引号括起来。 但多行字符串用“来表示,格式化字符串输出和shell用法类似${变量名} | let name = 'Alice'; let greeting = "Hello, World!";`这是一个 多行 字符串`; |
| Boolean | 表示逻辑实体,只有两个值:true 和 false。 | let isApproved = true; let isReady = false; |
| Undefined | 表示变量已声明但未赋值。 | let x; // x 的值是 undefined |
| Null | 表示故意赋予变量的空值。 | let emptyValue = null; |
| Symbol | 表示一个唯一的、不可变的数据类型,通常用作对象属性的键。 | let mySymbol = Symbol('mySymbol'); |
| BigInt | 表示大于 2^53 - 1 的整数。 | let bigNumber = BigInt(1234567890123456789012345678901234567890n); |
| Object | 表示键值对的集合,可以包含任意类型的数据。 | let person = { name: 'Bob', age: 30 }; |
| Array | 特殊类型的对象,用于存储有序的数据集合。 | let numbers = [1, 2, 3, 4, 5]; |
(1)变量声明
跳转到“(1)变量声明”| 特性/关键字 | var | let | const |
|---|---|---|---|
| 作用域 | 函数作用域或全局作用域 | 块级作用域 | 块级作用域 |
| 提升 | 变量提升,可访问但未赋值时为 undefined | 暂时性死区,访问未声明变量会抛出错误 | 暂时性死区,访问未声明变量会抛出错误 |
| 可重复声明 | 是 | 否 | 否 |
| 示例代码 | var x = 5;if(true) { var x = 10; }console.log(x); // 输出 10 | let y = 5;if(true) { let y = 10; }console.log(y); // 输出 5 | const z = 5;if(true) { const z = 10; }console.log(z); // 输出 5 |
| 可修改性 | 可修改 | 可修改 | 不可修改(一旦声明,其值不能被重新赋值) |
| 使用场景 | 适用于ES5及之前的代码 | 推荐用于ES6及之后的代码,用于声明不需要重新赋值的变量 | 推荐用于ES6及之后的代码,用于声明常量 |
(2)字符串补充
跳转到“(2)字符串补充”| 特性/方法 | 描述 | 示例代码 |
|---|---|---|
| 字符串表示 | 使用单引号'或双引号"括起来的字符序列。 | 'I'm OK' 或 "I'm OK" |
| 转义字符 | 使用反斜杠\来转义特殊字符或表示特殊意义的字符。 | 'I\'m "OK"!' 表示 I'm "OK"! |
| ASCII字符表示 | 以十六进制形式表示ASCII字符。 | '\x41' 等同于 'A' |
| Unicode字符表示 | 使用\u后跟四位十六进制数来表示Unicode字符。 | '\u4e2d\u6587' 等同于 '中文' |
| 多行字符串 | 使用反引号 来表示,允许字符串跨越多行。 | “这是一个 |
| 多行 | ||
| 字符串“ | ||
| 模板字符串 | 使用反引号 ,并在${}中插入变量或表达式,自动替换为变量值。 | let name = '小明'; `你好, ${name}, 你今年${age}岁了!` |
| 字符串连接 | 使用+号连接多个字符串。 | '你好, ' + name + ', 你今年' + age + '岁了!' |
| 字符串长度 | 通过.length属性获取字符串的字符数。 | let s = 'Hello, world!'; s.length; // 13 |
| 索引访问 | 通过下标访问字符串中的字符,索引从0开始。 | let s = 'Hello, world!'; s[0]; // 'H' |
| 不可变性 | 字符串是不可变的,对索引赋值无效。 | let s = 'Test'; s[0] = 'X'; console.log(s); // 'Test' |
| toUpperCase | 将字符串转换为大写。 | let s = 'Hello'; s.toUpperCase(); // 'HELLO' |
| toLowerCase | 将字符串转换为小写。 | let s = 'Hello'; s.toLowerCase(); // 'hello' |
| indexOf | 返回子字符串在字符串中首次出现的位置。 | let s = 'hello, world'; s.indexOf('world'); // 7 |
| substring | 返回字符串中从指定索引开始到结束或指定索引的子串。 | let s = 'hello, world'; s.substring(0, 5); // 'hello' |
(3)数组补充
跳转到“(3)数组补充”| 操作类型 | 描述 | 方法/属性 | 示例代码 |
|---|---|---|---|
| 增加 | 向数组末尾添加元素。 | push() | let arr = [1, 2]; arr.push(3); // arr 变为 [1, 2, 3] |
| 增加 | 向数组开头添加元素。 | unshift() | arr.unshift(0); // arr 变为 [0, 1, 2, 3] |
| 增加 | 从指定索引开始插入元素,可以插入多个。 | splice(index, 0, elem1, ..., elemN) | arr.splice(2, 0, 'a', 'b'); // arr 变为 [0, 1, 'a', 'b', 2, 3] |
| 删除 | 删除数组末尾的元素。 | pop() | arr.pop(); // 移除 3,arr 变为 [0, 1, 2] |
| 删除 | 删除数组开头的元素。 | shift() | arr.shift(); // 移除 0,arr 变为 [1, 2] |
| 删除 | 从指定索引开始删除元素,可以删除多个。 | splice(index, count) | arr.splice(2, 2); // 删除索引2开始的2个元素,arr 变为 [0, 1] |
| 修改 | 直接通过索引赋值修改数组元素。 | 索引赋值 | arr[1] = 10; // 将索引1的元素修改为10,arr 变为 [0, 10] |
| 查询 | 获取数组的长度。 | length | console.log(arr.length); // 输出 2 |
| 查询 | 查找数组中元素的索引,不存在返回-1。 | indexOf(searchElement) | arr.indexOf(2); // 查找元素2的索引 |
| 查询 | 查找数组中最后一个元素的索引,不存在返回-1。 | lastIndexOf(searchElement) | arr.lastIndexOf(2); // 查找元素2最后一次出现的索引 |
| 查询 | 返回数组中满足提供的测试函数的第一个元素的值。 | find(predicate) | arr.find(x => x > 1); // 查找第一个大于1的元素 |
| 查询 | 返回数组中满足提供的测试函数的所有元素。 | filter(predicate) | arr.filter(x => x > 1); // 过滤所有大于1的元素 |
| 查询 | 返回数组中元素的位置索引。 | includes(searchElement) | arr.includes(2); // 检查数组是否包含元素2 |
| 特性/方法 | 描述 | 示例代码 |
|---|---|---|
| 长度属性 | 通过.length属性获取数组的元素数量。 | let arr = [1, 2, 3]; console.log(arr.length); // 3 |
| 调整大小 | 直接赋值给.length属性可以改变数组的大小。 | arr.length = 5; console.log(arr); // [1, 2, 3, undefined, undefined] |
| 索引赋值 | 通过索引修改数组元素的值。 | arr[1] = 'new value'; console.log(arr); // [1, 'new value', 3] |
| 超出索引赋值 | 赋值超出当前索引范围会自动扩展数组。 | arr[10] = 'x'; console.log(arr); // [1, 'new value', 3, ..., 'x'] |
| indexOf | 搜索指定元素的位置,不存在返回-1。 | arr.indexOf(2); // 1 |
| slice | 截取数组的一部分并返回新数组。 | arr.slice(2); // [3] |
| 复制数组 | 不改变原数组的情况下复制数组。 | let copy = arr.slice(); |
| push | 在数组末尾添加一个或多个元素,并返回新长度。 | arr.push(4); console.log(arr); // [1, 2, 3, 4] |
| pop | 删除数组的最后一个元素并返回该元素。 | arr.pop(); console.log(arr); // [1, 2, 3] |
| unshift | 在数组开头添加一个或多个元素,并返回新长度。 | arr.unshift(0); console.log(arr); // [0, 1, 2, 3] |
| shift | 删除数组的第一个元素并返回该元素。 | arr.shift(); console.log(arr); // [1, 2, 3] |
| sort | 对数组元素进行排序,直接调用按默认顺序排序。 | arr.sort(); console.log(arr); // ['1', '2', '3'] |
| reverse | 反转数组元素的顺序。 | arr.reverse(); console.log(arr); // [3, 2, 1] |
| splice | 从指定索引开始删除或添加元素。 | arr.splice(2, 1, 'new'); console.log(arr); // [1, 2, 'new', 3] |
| concat | 连接当前数组和另一个数组或多个元素,并返回新数组。 | arr.concat([4, 5], 6); // [1, 2, 3, 4, 5, 6] |
| join | 将数组元素连接成一个字符串,元素间用指定的分隔符。 | arr.join(', '); // '1, 2, 3' |
| 多维数组 | 数组的元素可以是另一个数组,形成多维数组。 | let multiArr = [[1, 2], [3, 4]]; |
| 访问多维数组元素 | 通过连续索引访问多维数组中的元素。 | let x = arr[1][2]; console.log(x); // 500 |
(4)对象补充
跳转到“(4)对象补充”JavaScript的对象是一种无序的集合数据类型,它由若干键值对组成。JavaScript用一个{...}表示一个对象,键值对以xxx: xxx形式申明,用,隔开。注意,最后一个键值对不需要在末尾加,,如果加了,有的浏览器(如低版本的IE)将报错。
| 操作类型 | 描述 | 方法/属性/关键字 | 示例代码 |
|---|---|---|---|
| 创建 | 创建一个新对象。 | {...} | let xiaoming = {name: '小明', birth: 1990}; |
| 访问 | 通过点操作符或方括号访问对象属性。 | . 或 ['property'] | xiaoming.name; // '小明' 或 xiaoming['name']; |
| 修改 | 直接赋值修改对象属性的值。 | 赋值操作 | xiaoming.height = 1.75; |
| 删除 | 删除对象的属性。 | delete | delete xiaoming.school; |
| 属性检测 | 检测对象是否拥有某个属性。 | in | 'name' in xiaoming; // true |
| 属性检测 | 检测对象自身是否拥有属性,而不是继承自原型链。 | hasOwnProperty() | xiaoming.hasOwnProperty('name'); // true |
| 新增属性 | 给对象添加新属性。 | 赋值操作 | xiaoming.age = 18; |
| 属性存在性 | 访问不存在的属性不会报错,而是返回undefined。 | - | console.log(xiaoming.age); // undefined |
(5)Map&Set
跳转到“(5)Map&Set”Map是一组键值对的结构,具有极快的查找速度。不同于对象的是破除了Key仅能是字符串的限制。
let names = ['Michael', 'Bob', 'Tracy'];let scores = [95, 75, 85];
let m = new Map([['Michael', 95], ['Bob', 75], ['Tracy', 85]]);m.get('Michael'); // 95
let m = new Map(); // 空Mapm.set('Adam', 67); // 添加新的key-valuem.set('Bob', 59);m.has('Adam'); // 是否存在key 'Adam': truem.get('Adam'); // 67m.delete('Adam'); // 删除key 'Adam'm.get('Adam'); // undefined
let m = new Map();m.set('Adam', 67);m.set('Adam', 88);m.get('Adam'); // 88Set和Map类似,也是一组key的集合,但不存储value。由于key不能重复,所以,在Set中,没有重复的key。
let s1 = new Set(); // 空Setlet s2 = new Set([1, 2, 3]); // 含1, 2, 3
let s = new Set([1, 2, 3, 3, '3']);s; // Set {1, 2, 3, "3"}
s.add(4);s; // Set {1, 2, 3, 4}s.add(4);s; // 仍然是 Set {1, 2, 3, 4}
let s = new Set([1, 2, 3]);s; // Set {1, 2, 3}s.delete(3);s; // Set {1, 2}(6)iterable(类似python,容器等)
跳转到“(6)iterable(类似python,容器等)”遍历Array可以采用下标循环,遍历Map和Set就无法使用下标。为了统一集合类型,ES6标准引入了新的iterable类型,Array、Map和Set都属于iterable类型。具有iterable类型的集合可以通过新的for ... of循环来遍历。
let a = ['A', 'B', 'C'];let s = new Set(['A', 'B', 'C']);let m = new Map([[1, 'x'], [2, 'y'], [3, 'z']]);for (let x of a) { // 遍历Array console.log(x);}for (let x of s) { // 遍历Set console.log(x);}for (let x of m) { // 遍历Map console.log(x[0] + '=' + x[1]);}
for ... of循环和for ... in循环有何区别?
for ... in循环由于历史遗留问题,它遍历的实际上是对象的属性名称。一个Array数组实际上也是一个对象,它的每个元素的索引被视为一个属性。当我们手动给
Array对象添加了额外的属性后,for ... in循环将带来意想不到的意外效果:let a = ['A', 'B', 'C'];a.name = 'Hello';for (let x in a) {console.log(x); // '0', '1', '2', 'name'}
for ... in循环将把name包括在内,但Array的length属性却不包括在内。for ... of循环则完全修复了这些问题,它只循环集合本身的元素:let a = ['A', 'B', 'C'];a.name = 'Hello';for (let x of a) {console.log(x); // 'A', 'B', 'C'}然而,更好的方式是直接使用
iterable内置的forEach方法,它接收一个函数,每次迭代就自动回调该函数。以Array为例:let a = ['A', 'B', 'C'];a.forEach(function (element, index, array) {// element: 指向当前元素的值// index: 指向当前索引// array: 指向Array对象本身console.log(`${element}, index = ${index}`);});let m = new Map([[1, 'x'], [2, 'y'], [3, 'z']]);m.forEach(function (value, key, map) {console.log(value);});// 如果对某些参数不感兴趣,由于JavaScript的函数调用不要求参数必须一致,因此可以忽略它们。例如,只需要获得Array的elementlet a = ['A', 'B', 'C'];a.forEach(function (element) {console.log(element);});
(7)变量作用域
跳转到“(7)变量作用域”作用域符合一般的C/C++,python等规则。
| 概念/用法 | 说明 | 代码示例 |
|---|---|---|
| 变量作用域 | 变量的作用域取决于其声明的位置,var声明的变量作用域为整个函数体。 | function foo() { var x = 1; } |
| 变量提升 | var声明的变量会被提升到函数或全局作用域的顶部,但赋值不会提升。 | function foo() { console.log(x); var x = 1; } |
| 同名变量屏蔽 | 内部函数声明的同名变量会屏蔽外部函数的变量。 | function foo() { var x = 1; function bar() { var x = 'A'; } } |
| 全局作用域 | 不在任何函数内声明的变量具有全局作用域,绑定到window对象。 | var course = 'Learn JavaScript'; console.log(window.course); |
| 函数作为全局变量 | 以变量方式声明的函数也是全局变量,绑定到window对象。 | var foo = function() { alert('foo'); }; window.foo(); |
| 名字空间 | 将所有变量和函数绑定到一个全局变量中,减少命名冲突。 | let MYAPP = {}; MYAPP.name = 'myapp'; |
| 局部作用域 | for循环等语句块中不能定义局部作用域变量。 | function foo() { for (var i=0; i<100; i++) {} console.log(i); } |
| 块级作用域 | let声明的变量具有块级作用域。 | function foo() { let x = 1; if (true) { let x = 2; } console.log(x); } |
| 常量 | const声明的变量是常量,不能重新赋值。 | const PI = 3.14; PI = 3; // 无效果 |
| 解构赋值 | 允许从数组或对象中快速提取数据并赋值给变量。 | let [x, y, z] = ['hello', 'JavaScript', 'ES6']; |
| 解构赋值忽略元素 | 解构赋值时可以忽略数组中的某些元素。 | let [, , z] = ['hello', 'JavaScript', 'ES6']; |
| 对象属性解构 | 从对象中提取属性并赋值给变量。 | let {name, age} = person; |
| 嵌套对象解构 | 对象属性解构时可以提取嵌套对象的属性。 | let {address: {city, zipcode}} = person; |
| 解构赋值默认值 | 解构赋值时可以为变量提供默认值,避免undefined。 | let {name, single = true} = person; |
| 已声明变量解构 | 如果变量已经被声明,需要用小括号括起来进行解构赋值。 | ({x, y} = {x: 100, y: 200}); |
| 交换变量值 | 使用解构赋值交换两个变量的值。 | let x = 1, y = 2; [x, y] = [y, x]; |
| 函数参数解构 | 函数参数可以通过解构赋值快速获取对象属性。 | function buildDate({year, month, day}) { ... } |