跳转到内容
新建笔记

数据类型&变量

数据类型的使用与python类似。

数据类型说明代码示例
Number表示数字,包括整数和浮点数。支持科学计数法和十六进制表示。let age = 25;
let price = 19.99;
let count = 1.23e4;
123; // 整数123
0.456; // 浮点数0.456
1.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];
特性/关键字varletconst
作用域函数作用域或全局作用域块级作用域块级作用域
提升变量提升,可访问但未赋值时为 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及之后的代码,用于声明常量
特性/方法描述示例代码
字符串表示使用单引号'或双引号"括起来的字符序列。'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'
操作类型描述方法/属性示例代码
增加向数组末尾添加元素。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]
查询获取数组的长度。lengthconsole.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

JavaScript的对象是一种无序的集合数据类型,它由若干键值对组成。JavaScript用一个{...}表示一个对象,键值对以xxx: xxx形式申明,用,隔开。注意,最后一个键值对不需要在末尾加,,如果加了,有的浏览器(如低版本的IE)将报错。

操作类型描述方法/属性/关键字示例代码
创建创建一个新对象。{...}let xiaoming = {name: '小明', birth: 1990};
访问通过点操作符或方括号访问对象属性。. 或 ['property']xiaoming.name; // '小明' 或 xiaoming['name'];
修改直接赋值修改对象属性的值。赋值操作xiaoming.height = 1.75;
删除删除对象的属性。deletedelete xiaoming.school;
属性检测检测对象是否拥有某个属性。in'name' in xiaoming; // true
属性检测检测对象自身是否拥有属性,而不是继承自原型链。hasOwnProperty()xiaoming.hasOwnProperty('name'); // true
新增属性给对象添加新属性。赋值操作xiaoming.age = 18;
属性存在性访问不存在的属性不会报错,而是返回undefined。-console.log(xiaoming.age); // undefined

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(); // 空Map
m.set('Adam', 67); // 添加新的key-value
m.set('Bob', 59);
m.has('Adam'); // 是否存在key 'Adam': true
m.get('Adam'); // 67
m.delete('Adam'); // 删除key 'Adam'
m.get('Adam'); // undefined
let m = new Map();
m.set('Adam', 67);
m.set('Adam', 88);
m.get('Adam'); // 88

Set和Map类似,也是一组key的集合,但不存储value。由于key不能重复,所以,在Set中,没有重复的key。

let s1 = new Set(); // 空Set
let 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的element
let a = ['A', 'B', 'C'];
a.forEach(function (element) {
console.log(element);
});

作用域符合一般的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}) { ... }