tutorial
变量 1 2 let message; message = 'hello' ;
变量
数据类型
number — 可以是浮点数,也可以是整数,
bigint — 用于任意长度的整数,
string — 字符串类型,
boolean — 逻辑值:true/false,
null — 具有单个值 null 的类型,表示“空”或“不存在”,
undefined — 具有单个值 undefined 的类型,表示“未分配(未定义)”,
object 和 symbol — 对于复杂的数据结构和唯一标识符,我们目前还没学习这个类型。
值比较 === 表示比较时,不做任何的类型转换
控制 if 1 2 3 4 5 6 7 8 9 et year = prompt ('In which year was ECMAScript-2015 specification published?' , '' ); if (year < 2015 ) { alert ( 'Too early...' ); } else if (year > 2015 ) { alert ( 'Too late' ); } else { alert ( 'Exactly!' ); }
三目运算符:
1 let result = condtion ? value1 : value2;
控制合并运算符 1 2 3 result = a ?? b; result = (a != null && a != undefined ) ? a : b;
如果a是已定义的,则结果为a; 否则结果为 b
循环 1 2 3 while(condition){ // loop body }
1 2 3 do{ // loop body }while(condition);
1 2 3 for(begin; condtion; step){ // loop body }
跳出循环: break , continue
break/continue 标签 1 2 3 4 5 6 7 8 9 10 outer : for (let i = 0 ; i < 3 ; i++) { for (let j = 0 ; j < 3 ; j++) { let input = prompt (`Value at coords (${i} ,${j} )` , '' ); if (!input) { break outer; } } }
单使用break和continue,只能跳出当前循环, 但如果使用标签,就可以跳出到标签的那层
switch 1 2 3 4 5 6 7 8 9 10 11 12 switch(x){ case 'value1': ... break; case 'value2': ... break; ... default: ... break; }
函数 1 2 3 function showMessage ( ) { alert ('Hello a!' ); }
形式:
1 2 3 function name(param1, param2, ... parmN) { ... body ... }
函数表达式 1 2 3 4 5 6 let sayHi = function ( ){ alert ('Hello function expression!' ); }; sayHi ();
箭头函数 形式:
1 let func = (arg1, arg2, ..., argN) => expression;
可以认为是如下形式的缩写:
1 2 3 let func = function(arg1, arg2, ..., argN){ return expression; };
示例:
1 2 3 let sum = (a, b ) => a+b;alert (sum (1 ,2 ));
对象 基础语法 1 2 let user = new Object (); let user = {};
1 2 3 4 5 6 7 8 9 10 let user = { name : "John" , age : 30 } user['like birds' ] = true ; user['age' ] = 40 ; delete user['like birds' ];
”in“操作符:
1 2 3 4 let user = {name :'John' , age :30 };alert ("age" in user); alert ("blabla" in user);
for…in :
1 2 3 4 5 6 7 8 9 10 11 let user = { name : "John" , age : 30 , isAdmin : true }; for (let key in user) { alert ( key ); alert ( user[key] ); }
对于对象中的各个属性的顺序 : 整数属性会被进行排序,其他属性则按照创建的顺序显示。
对象引用和复制 1 2 3 4 5 let user = {name :'John' };let admin = user; alert (user === admin); admin.name = 'Pete' ; alert (user.name );
1 2 3 4 5 6 7 8 9 10 let user = {name :'John' , age :30 };let clone = {};for (let key in user){ clone[key] = user[key]; } clone.name = "Pete" ; alert (user.name );
以上的流程,可以通过assign方法来达到,语法:
1 Object.assign(dst, [src1, src2, src3...])
1 2 3 4 5 6 let user = {name :'John' };let permission1 = {canView : true };let permission2 = {canEdit : true };Object .assign (user, permission1, permission2);
1 2 3 4 5 let user = {name :'John' };Object .assign (user, {name, "Pete" }); alert (user.name ) let clone = Object .assign ({}, user);
深层克隆 : 原始类型,上边的复制方式可以完成,但如果属性是对其他对象的引用,则需要使用其他方式进行深层克隆。
1 2 3 4 5 6 7 8 9 let user = { name : "John" , sizes : { height : 182 , width : 50 } }; let clone = Object .assign ({}, user);alert (user.sizes === clone.sizes );
深层克隆,需要考虑使用其他实现,例如: lodash 库的 _.cloneDeep(obj) 。
对象方法 this 1 2 3 4 5 6 7 8 9 10 let user = { name : "John" , age : 30 , sayHi ( ) { alert (this .name ); } }; user.sayHi ();
构造 _构造函数_:
1 2 3 4 5 6 7 8 9 10 function User (name ) { this .name = name; this .isAdmin = false ; } let user = new User ('Jack' );
在一个函数内部,我们可以使用 new.target 属性来检查它是否被使用 new 进行调用了。
可选链 可选链 ?. 语法有三种形式:
obj?.prop —— 如果 obj 存在则返回 obj.prop,否则返回 undefined。
obj?.[prop] —— 如果 obj 存在则返回 obj[prop],否则返回 undefined。
obj.method?.() —— 如果 obj.method 存在则调用 obj.method(),否则返回 undefined。
1 2 3 let user = null ;alert (user?.address ); alert (user?.address .street );
symbol类型 根据规范,只有两种原始类型可以用作对象属性键:
symbol 有两个主要的使用场景:
“隐藏” 对象属性。 如果我们想要向“属于”另一个脚本或者库的对象添加一个属性,我们可以创建一个 symbol 并使用它作为属性的键。symbol 属性不会出现在 for..in 中,因此它不会意外地被与其他属性一起处理。并且,它不会被直接访问,因为另一个脚本没有我们的 symbol。因此,该属性将受到保护,防止被意外使用或重写。
因此我们可以使用 symbol 属性“秘密地”将一些东西隐藏到我们需要的对象中,但其他地方看不到它。
JavaScript 使用了许多系统 symbol,这些 symbol 可以作为 Symbol.* 访问。我们可以使用它们来改变一些内建行为。例如,在本教程的后面部分,我们将使用 Symbol.iterator 来进行 迭代 操作,使用 Symbol.toPrimitive 来设置 对象原始值的转换 等等。
属性的getter和setter 访问器属性由 “getter” 和 “setter” 方法表示。在对象字面量中,它们用 get 和 set 表示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 let user = { name : "John" , surname : "Smith" , get fullName () { return `${this .name} ${this .surname} ` ; } set fullName (value ) { [this .name , this .surname ] = value.split (" " ); } }; user.fullName = "Alice Cooper" ; alert (user.name ); alert (user.surname );
数据类型 数组 1 2 3 let arr = new Array ();let arr = [];
1 2 3 4 5 6 7 8 9 10 11 12 let fruits = ["Apple" , "Orange" , "Plum" ];alert (fruits[0 ]); alert (fruits[1 ]); alert (fruits[2 ]); fruits[2 ] = "Pear" ; fruits[3 ] = "Lemon" ; alert (fruits.pop ()); fruits.push ("Plum" ); alert (fruits.shift ()); fruits.unshift ("Apple" );
遍历:
1 2 3 4 5 6 7 8 9 10 let fruits = ["Apple" , "Orange" , "Plum" ];for (let i=0 ; i<arr.length ; i++){ alert (arr[i]); } for (let fruit of fruits){ alert (fruit); } for (let key in fruits){ alert (fruits[key]); }
Map和Set Map
new Map() —— 创建 map。
map.set(key, value) —— 根据键存储值。
map.get(key) —— 根据键来返回值,如果 map 中不存在对应的 key,则返回 undefined。
map.has(key) —— 如果 key 存在则返回 true,否则返回 false。
map.delete(key) —— 删除指定键的值。
map.clear() —— 清空 map。
map.size —— 返回当前元素个数。
map.keys() —— 遍历并返回一个包含所有键的可迭代对象,
map.values() —— 遍历并返回一个包含所有值的可迭代对象,
map.entries() —— 遍历并返回一个包含所有实体 [key, value] 的可迭代对象,for..of 在默认情况下使用的就是这个。1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 let recipeMap = new Map ([ ['cucumber' , 500 ], ['tomatoes' , 350 ], ['onion' , 50 ] ]); for (let vegetable of recipeMap.keys ()) { alert (vegetable); } for (let amount of recipeMap.values ()) { alert (amount); } for (let entry of recipeMap) { alert (entry); }
从一个已有普通对象创建一个map:
1 2 3 4 5 6 7 let obj = { name : "John" , age : 30 }; let map = new Map (Object .entries (obj));alert ( map.get ('name' ) );
从Map创建对象:
1 2 3 4 5 6 7 8 9 let prices = Object .fromEntries ([ ['banana' , 1 ], ['orange' , 2 ], ['meat' , 4 ] ]); alert (prices.orange );
Set
new Set(iterable) —— 创建一个 set,如果提供了一个 iterable 对象(通常是数组),将会从数组里面复制值到 set 中。
set.add(value) —— 添加一个值,返回 set 本身
set.delete(value) —— 删除值,如果 value 在这个方法调用的时候存在则返回 true ,否则返回 false。
set.has(value) —— 如果 value 在 set 中,返回 true,否则返回 false。
set.clear() —— 清空 set。
set.size —— 返回元素个数。
set.keys() —— 遍历并返回一个包含所有值的可迭代对象,
set.values() —— 与 set.keys() 作用相同,这是为了兼容 Map,
set.entries() —— 遍历并返回一个包含所有的实体 [value, value] 的可迭代对象,它的存在也是为了兼容 Map。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 let set = new Set ();let john = { name : "John" };let pete = { name : "Pete" };let mary = { name : "Mary" };set.add (john); set.add (pete); set.add (mary); set.add (john); set.add (mary); alert ( set.size ); for (let user of set) { alert (user.name ); }
日期和时间 1 2 3 4 5 6 7 8 9 10 11 let Jan01 _1970 = new Date (0 );alert ( Jan01 _1970 );let Jan02 _1970 = new Date (24 * 3600 * 1000 );alert ( Jan02 _1970 );let Dec31 _1969 = new Date (-24 * 3600 * 1000 );alert (Dec31 _1969);let date = new Date ("2017-04-25" );
从 Date 对象中访问年、月等信息有多种方式:getFullYear() 获取年份(4 位数)getMonth() 获取月份,从 0 到 11 。getDate() 获取当月的具体日期,从 1 到 31,这个方法名称可能看起来有些令人疑惑。getHours() ,getMinutes() ,getSeconds() ,getMilliseconds() 获取相应的时间组件。
getTime() 返回日期的时间戳 —— 从 1970-1-1 00:00:00 UTC+0 开始到现在所经过的毫秒数。getTimezoneOffset() 返回 UTC 与本地时区之间的时差,以分钟为单位:getDay() 获取一周中的第几天,从 0(星期日)到 6(星期六)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 function diffSubtract (date1, date2 ) { return date2 - date1; } function diffGetTime (date1, date2 ) { return date2.getTime () - date1.getTime (); } function bench (f ) { let date1 = new Date (0 ); let date2 = new Date (); let start = Date .now (); for (let i = 0 ; i < 100000 ; i++) f (date1, date2); return Date .now () - start; } alert ( 'Time of diffSubtract: ' + bench (diffSubtract) + 'ms' );alert ( 'Time of diffGetTime: ' + bench (diffGetTime) + 'ms' );
Json方法 JSON.stringfy:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 let student = { name : 'John' , age : 30 , isAdmin : false , courses : ['html' , 'css' , 'js' ], spouse : null }; let json = JSON .stringify (student);alert (typeof json); alert (json);
函数进阶 类 基本语法 1 2 3 4 5 6 class MyClass{ constructor(){...} method1(){...} method2(){...} ... }
1 2 3 4 5 6 7 8 9 10 11 12 class User { constructor (name ){ this .name = name; } sayHi ( ){ alert (this .name ) } } let user = new User ("John" );user.sayHi ();
类继承 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 class Animal { constructor (name ){ this .name =name; this .speed =0 ; } run (speed ){ this .speed = speed; alert (`${this .name} runs with speed ${this .speed} .` ); } stop ( ){ this .speed = 0 ; alert (`${this .name} stands still.` ); } } class Rabbit extends Animal { hide ( ) { alert (`${this .name} hides!` ); } } let rabbit = new Rabbit ("little white" );rabbit.run (5 ); rabbit.hide ();
Promise、async/await 模块 什么是模块? 一个模块(module)就是一个文件。一个脚本就是一个模块。
export 关键字标记了可以从当前模块外部访问的变量和函数。
import 关键字允许从其他模块导入功能。
1 2 3 4 export function sayHi (user ){ alert (`Hello, ${user} !` ); }
1 2 3 4 5 import {sayHi} from './sayHi.js' ;alert (sayHi); sayHi ('John' );