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' );