导图社区 javascript基础语法
javascript基础语法知识总结,包括proxy和reflect、模块、<script>元素、现代模式、变量、常量的相关内容。
编辑于2021-12-21 09:13:45javascript基础语法
Proxy 和 Reflect
proxy
语法
let proxy = new Proxy(target, handler)
target —— 是要包装的对象,可以是任何东西,包括函数
handler —— 代理配置:带有“捕捉器”(“traps”,即拦截操作的方法)的对象
带有 “get” 捕捉器的默认值
最常见的捕捉器是用于读取/写入的属性
拦截读取操作,handler 应该有 get(target, property, receiver) 方法
target —— 是目标对象,该对象被作为第一个参数传递给 new Proxy
property —— 目标属性名
receiver —— 如果目标属性是一个 getter 访问器属性,则 receiver 就是本次读取属性所在的 this 对象
使用 “set” 捕捉器进行验证
set(target, property, value, receiver)
target —— 是目标对象,该对象被作为第一个参数传递给 new Proxy
property —— 目标属性名称
value —— 目标属性的值
receiver —— 与 get 捕捉器类似,仅与 setter 访问器属性相关
如果写入操作(setting)成功,set 捕捉器应该返回 true,否则返回 false(触发 TypeError)
Reflect
Reflect 是一个内建对象,可简化 Proxy 的创建
代理一个 getter
let userProxy = new Proxy(user, { get(target, prop, receiver) { // receiver = admin return Reflect.get(target, prop, receiver); // (*) }});
Proxy 的局限性
内建对象:内部插槽(Internal slot)
许多内建对象,例如 Map,Set,Date,Promise 等,都使用了所谓的“内部插槽”
模块 (Module)
简介
一个模块(module)就是一个文件。一个脚本就是一个模块。就这么简单
语法
export 关键字标记了可以从当前模块外部访问的变量和函数
import 关键字允许从其他模块导入功能
功能
始终使用'use strict'
模块级作用域
模块代码只在第一次导入时被解析
import.meta 对象包含关于当前模块的信息
浏览器特定功能
模块脚本 总是 被延迟的
不允许裸模块(“bare” module)
Async 可用于内联脚本
模块只能通过HTTP(s)工作,在本地文件上不行
构建工具
webpack等
导出和导入
在声明前导出
export let months = ['Jan', 'Feb', 'Mar', 'Oct', 'Nov', 'Dec'];
Import*
import * as <obj> 将所有内容导入为一个对象
import {sayHi, sayBye} from './say.js';
as
Import “as”
import {sayHi as hi, sayBye as bye} from './say.js';
Export “as”
export {sayHi as hi, sayBye as bye};
Export default(默认导出)
将 export default 放在要导出的实体前
export default class User { // 只需要添加 "default" 即可 constructor(name) { this.name = name;}}
将其导入而不需要花括号
“default” 名称
在某些情况下,default 关键词被用于引用默认的导出
另一种情况,假设模块 user.js 导出了一个主要的默认的导出和一些命名的导出(这种情况很少见,但确实会发生)
重新导出
export ... from ... 允许导入内容,并立即将其导出
最后
我们把 import/export 语句放在脚本的顶部或底部,都没关系
动态导入
import() 表达式
import(module) 表达式加载模块并返回一个 promise,该 promise resolve 为一个包含其所有导出的模块对象。我们可以在代码中的任意位置调用这个表达式。
<script>元素
async属性
表示应该立即开始下载脚本,但不能阻止其它动作比如下载资源或者等待其它脚本加载即不必等到该异步脚本下载和执行后再执行和加载其它脚本,只对外部脚本文件有效
defer属性
表示在文档解析和显示完成后再执行脚本是没有问题的,即推迟执行脚本只对外部文件有效,且是顺序执行脚本
src属性
表示包含要执行的代码的外部文件
type属性
表示代码块中脚本语言的内容类型(MIME)一般值是text/javascript
charset(src指定的代码字符集)crossorgin(跨院资源共享(CORS)默认不使用integrity(验证和加密签名)可以拿来防范不同域的js文件的恶意更改
动态加载脚本
现代模式,"use strict"
请确保 "use strict" 出现在脚本的最顶部,否则严格模式可能无法启用。
还可以放在函数体的开头,这样可以让函数启用"严格模式"
变量
一个变量名应该有一个清晰、明显的含义,对其存储的数据进行描述。
let(现代的变量声明方式)
var(老的变量声明方式)
常量
const(如果这个值在声明之后不再改变了,那么就请这样声明吧)声明出来的要尽量大写
交互函数
这些方法都是模态的:它们暂停脚本的执行,并且不允许用户与该页面的其余部分进行交互,直到窗口被解除。
alert
prompt
result = prompt(title, [default]);
prompt 以字符串的形式返回用户的输入
confirm
返回true或者false
八大数据类型
number
InfinityNaN
bigint
数字后加n
string
”“双引号
’‘单引号
` `反引号(功能扩展 引号)
允许我们将变量包装在¥{。。。}中,并且我们可以通过它来进行计算
使用反引号的另一个优点是它们允许字符串跨行
Boolean
undfined(未被赋值)
null(未知)
symbol
主要起一个隐藏属性的作用
object
我们可以通过typeof来获得储存在变量中的数据类型
typeof(x)或者typeof x
数据类型进阶
Number
科学计数法:5.36e5
toString(base) 返回给定base进制数字系统中num的字符串表示形式
toFixed(n)将数字舍入到小数点后n位
Math.floor 向下舍入Math.ceil向上舍入Math.round向最近的整数舍入Math.trunc移除小数点后的内容(没有舍入)
isNaN( value ) 是NaN就返回trueisFinite(value)常数为true其他为falseparseInt( )和parseFloat( )返回字符串中的数字第二个参数可以选择进制Math.random()、Math.max(a,b,c...)、Math.pow(n,value)
String
字符串长度 str.length
访问字符
str[n]访问str的第n+1个字符
str.charAt(n)同上
str[str.lenth-1 ]访问最后一个字符
for..of 遍历字符
for (let char of "hello")
他们的区别是,如果没有找到字符。[]返回undefined而charAt返回NaN
字符串是不可变的
通常的解决方法是创建一个新的字符串,并将其分配给 str 而不是以前的字符串。
toLowerCase() 和 toUpperCase() 方法可以改变大小写
'haha'[0].toLowerCase( )
查找子字符串
str.indexOf(substr, pos)(第二个参数可选)
它从给定位置 pos 开始,在 str 中查找 substr,如果没有找到,则返回 -1,否则返回匹配成功的位置。
str.lastIndexOf(substr, position)
str.includes(substr, pos) 根据 str 中是否包含 substr 来返回 true/false
str.startsWith() 和 str.endsWith() 的功能与其名称所表示的意思相同
获取子字符串
str.slice(start , end)(第二个参数可选)
支持负参数不支持start<end
str.substring(start , end)
不支持负参数支持start<end
str.substr(start , length)
比较字符串
小写字母总是大于大写字母带变音符号的字母存在乱序的情况
str.codePointAt(pos) 返回在 pos 位置的字符代码
String.fromCodePoint(code) 通过数字 code 创建字符
调用 str.localeCompare(str2) 会根据语言规则返回一个整数
数组
声明
let arr = new Array();
new Array(number) 创建的数组的所有元素在没定义之前都是 undefined
let fruits = ["Apple", "Orange", "Plum"];(多数情况下使用此语法)
pop/push, shift/unshift 方法
pop/push用于数组末端
shift/unshift用于数组首端
循环
for
for..in
for..of
方法
添加/移除数组元素
delete
删除若测量数组长度,数组长度不变
splice
arr.splice(n,i,"content","content") 从索引n开始删除i个元素并添加content
允许负向引索
slice
arr.slice([start], [end]) 返回一个新数组
concat
arr.concat(arg1, arg2...)
创建一个新数组,其中包含来自于其他数组和其他项的值也包括自身
Symbol.isConcatSpreadable属性
遍历
arr.forEach
为数组的每个元素都运行一个函数
该函数的结果(如果它有返回)会被抛弃和忽略。
arr.forEach(function(item, index, array){ });
item代表当前元素
index代表引索
array代表数组
搜寻
indexOf/lastIndexOf
includes (检查是否存在
find 和 findIndex
let result = arr.find(function(item, index, array) { // 如果返回 true,则返回 item 并停止迭代 // 对于假值(falsy)的情况,则返回 undefined});
findIndex返回的不是对象,返回的是引索
filter
let results = arr.filter(function(item, index, array) { // 如果 true item 被 push 到 results,迭代继续 // 如果什么都没找到,则返回空数组});
返回数组中符合我们要求的全部元素
转换数组
arr.map
let result = arr.map(function(item, index, array) { // 返回新值而不是当前元素})
它对数组的每个元素都调用函数,并返回结果数组。
arr.sort
默认情况下被按字符串进行排序
要使用我们自己的排序顺序,我们需要提供一个函数作为 arr.sort() 的参数
arr.reverse
返回反转的数组
split 和 join
split通过给定的分隔符 delim 将字符串分割成一个数组。(第二个参数可以设定数组长度的限制)
arr.join(glue) 与 split 相反。它会在它们之间创建一串由 glue 粘合的 arr 项
reduce/reduceRight
let value = arr.reduce(function(accumulator, item, index, array) { // ...}, [initial]);
该函数一个接一个地应用于所有数组元素,并将其结果“搬运(carry on)”到下一个调用。
Array.isArray
Array.isArray(value)。如果 value 是一个数组,则返回 true;否则返回 false。
以下的不常用
arr.some(fn)/arr.every(fn) 检查数组
arr.fill(value, start, end) —— 从索引 start 到 end,用重复的 value 填充数组。
arr.copyWithin(target, start, end) —— 将从位置 start 到 end 的所有元素复制到 自身 的 target 位置(覆盖现有元素)
Map and Set(映射和集合)
Map
new Map()
创建map
map.set(key, value)
根据键储存值
map.get(key)
根据键来反返回值,如果map中不存在对应的key,则返回undefined
map.has(key)
如果key存在则返回true,反之false
mao.delete(key)
删除指定键的值
map.clear()
清空map
map.size
返回当前元素个数
Map迭代
map.keys()
遍历并返回所有的键
map.values()
遍历并返回所有的值
map.entries()
遍历并返回所有的实体
for..of默认情况下用的就是它
这三者返回的都是可迭代对象而非数组
Set
new Set(iterable)
创建一个 set,如果提供了一个 iterable 对象(通常是数组),将会从数组里面复制值到 set 中。
set.add(value)
添加一个值,返回 set 本身
set.delet(value)
删除值,如果 value 在这个方法调用的时候存在则返回 true ,否则返回 false。
set.has(value)
如果 value 在 set 中,返回 true,否则返回 false。
set.clear()
清空 set。
set.size
返回元素个数。
Set迭代
方法
set.keys()
set.values()
set.entries()
for..of
forEach
forEach 的回调函数有三个参数:一个 value,然后是 同一个值 valueAgain,最后是目标对象。没错,同一个值在参数里出现了两次。
forEach 的回调函数有三个参数,是为了与 Map 兼容。当然,这看起来确实有些奇怪。但是这对在特定情况下轻松地用 Set 代替 Map 很有帮助,反之亦然。
WeakMap and WeakSet(弱映射和弱集合)
WeakMap
WeakMap 的键必须是对象,不能是原始值
只有这些方法
weakMap.get(key)weakMap.set(key, value)weakMap.delete(key)weakMap.has(key)
WeakSet
WeakSet 的键必须是对象,不能是原始值
WeakSet 支持 add,has 和 delete 方法,但不支持 size 和 keys(),并且不可迭代。
使用案例
额外的数据
缓存
Object.entries
从对象中创建map
let map = new Map(Object.entries(obj));
Object.fromEntries
从map中创建对象
let prices = Object.fromEntries([ ['banana', 1], ['orange', 2], ['meat', 4]]);
期望得到的是一个可迭代对象,不一定是数组
类型转换
字符串转换
格式:String(a)
数字型转换
格式:Number(a)
规则:undefined NaNnull 0ture/false 1/0string 去掉首尾空格后的数字,为空则0 出现error时返回NaNfunction(){}是undefined
布尔型转换
格式:Boolean(a)
规则:0、null、undefined、NaN、"" 、false false其它 ture
基础运算符(这里只列举易错的)
+运算符(二元)
可以用于连接字符串
可以字符串和其它参数混加
+运算符(一元)
相当于Number(...)一元运算符加号,或者说,加号 + 应用于单个值,对数字没有任何作用。但是如果运算元不是数字,加号 + 则会将其转化为数字。
%
在js中%运算符似乎不要求两个参数都是整数
**运算符
a**b即为a的b次方可以为小数
自增自减
只可以用于变量
数值的比较
> < >=<= !======!==
流程控制
条件分支?语句可以代替if-else语句但这样可读性差、不建议这样写
if-else语句
?语句
switch
和c语言不一样的是,这里的相等运算是严格相等
for
++i和i++没有区别
while、do..while
标签break,continue
逻辑运算符
&&的优先级是大于||的
||
或运算寻找第一个真值(不是指如果是真值则返回1这种,而是切实的返回那个真值)
&&
与运算寻找第一个假值若没有找到,则返回最后一个真值
!
!!可以把值转换为布尔类型
空值合并运算符
空值合并运算符的写法为两个问号 ??
通常 ?? 的使用场景是,为可能是未定义的变量提供一个默认值。
函数
箭头函数
没有自己的this
如果我们在这样的函数中引用 this,this 值取决于外部“正常的”函数。
回调函数
函数声明
可以在区域块内被访问
函数表达式
在声明之后才可以被访问
变量
为了使代码简洁易懂,建议在函数中主要使用局部变量和参数,而不是外部变量。
局部变量
外部变量
参数
默认值
只有在缺少实参的时候才会被调用
四种方法:1.声明时2.if(text===undefined)3.||语句4.??运算符
若没有实参传递,则形参为undefined
返回值
若没有ruturn则返回undefined
函数命名
函数==注释
对象
入门
key-value
方括号
属性值简写
in操作符
for...in循环
对象引用
对象拷贝
深拷贝
浅拷贝
Object.assign(dest, [src1, src2, src3...])
垃圾回收
可达性
自动回收
方法
即储存在对象中的函数
this
this 的值是在程序运行时得到的
Global对象
不属于任何其它对象的属性或者方法都属于Global对象
构造函数(构造器)
就是常规的函数
规定:开头大写
只能通过new来调用
return
若返回值为原始类型则忽略
若返回值为对象则返回这个对象
若没有return语句则默认返回this对象
可选链?.
可以用于安全读取和安全删除
仅当左边不存在也没问题的时候来使用为宜
若左边不存在则报undefined
内建对象
创建
new Date()
不带参数
创建一个当前日期和时间的Date对象
带参数
milliseconds
传入时间戳
datestring
自动解析,例如("2017-01-26")
new Date(year, month, date, hours, minutes, seconds, ms)
访问日期组件
getFullYear()
获取年份
getMonth()
获取月份,从0到11
getDate()
获取日期
getDay()
获取一周中的第几天,星期天为0
getTime()
返回日期的时间戳
getTimezoneOffset()
返回 UTC 与本地时区之间的时差,以分钟为单位
getHours(),getMinutes(),getSeconds(),getMilliseconds()
设置日期组件
setFullYear(year, [month], [date])
setMonth(month, [date])
setDate(date)
setHours(hour, [min], [sec], [ms])
JSON 方法
概念
JSON(JavaScript Object Notation)是表示值和对象的通用格式
方法
JSON.stringify 将对象转换为 JSON
JSON.parse 将 JSON 转换回对象
函数进阶
Rest 参数与 Spread 语法
使用场景
Rest 参数用于创建可接受任意数量参数的函数。
Spread 语法用于将数组传递给通常需要含有许多参数的列表的函数。
它们俩的出现帮助我们轻松地在列表和参数数组之间来回转换
Rest参数
function sumAll(...args)所有参数都在args数组中了
Spread语法
Math.max(...arr)数组arr被转换成列表
如何区分
若 ... 出现在函数参数列表的最后,那么它就是 rest 参数,它会把参数列表中剩余的参数收集到一个数组中。若 ... 出现在函数调用或类似的表达式中,那它就是 spread 语法,它会把一个数组展开为列表。
setTimeout 和 setInterval
setTimeout
setTimeout 允许我们将函数推迟到一段时间间隔之后再执行。
语法
let timerId = setTimeout(func|code, [delay], [arg1], [arg2], ...)
例子:setTimeout(() => alert('Hello'), 1000);
嵌套的 setTimeout
setInterval
setInterval 允许我们重复运行一个函数,从一段时间间隔之后开始运行,之后以该时间间隔连续重复运行该函数。
语法
let timerId = setInterval(func|code, [delay], [arg1], [arg2], ...)
例子:let timerId = setInterval(() => alert('tick'), 2000);
clearTimeout
取消调度
new function 语法
函数对象
属性“name”
属性“length”
自定义属性
代替闭包
命名函数表达式
属性标志和属性描述符
属性标志
标志
writable — 如果为 true,则值可以被修改,否则它是只可读的。
enumerable — 如果为 true,则会被在循环中列出,否则不会被列出。
configurable — 如果为 true,则此特性可以被删除,以上这些属性也可以被修改,否则不可以。
方法
let descriptor = Object.getOwnPropertyDescriptor(obj, propertyName);
返回值是一个所谓的“属性描述符”对象:它包含值和所有的标志。
Object.defineProperty(user, "name", { writable: false});
如果该属性存在,defineProperty 会更新其标志。否则,它会使用给定的值和标志创建属性;在这种情况下,如果没有提供标志,则会假定它是 false。
访问器属性
访问器属性由 “getter” 和 “setter”组成
它们本质上是用于获取和设置值的函数,但从外部代码来看就像常规属性。
原型、继承
默认的F.prototype,构造器属性
原型继承
特点
不会影响this
for..in循环会遍历自己以及继承的属性
obJect.value不会遍历继承的属性
原生的原型
Object.prototype
obj = {} 和 obj = new Object() 是一个意思
Object 就是一个内建的对象构造函数
请注意在 Object.prototype 上方的链中没有更多的 [[Prototype]]
其他内建原型
Array、Date、Function 及其他,都在 prototype 上挂载了方法
所有的内建原型顶端都是 Object.prototype
不要改动原生原型
没有_proto_的对象
_proto_在js规范中规定,proto必须浏览器环境下才可以得到支持,所以我们要用现代方法
现代方法
Object.create(proto, [descriptors])
利用给定的 proto 作为 [[Prototype]] 和可选的属性描述来创建一个空对象。
第二个参数
我们可以在此处为新对象提供额外的属性
Object.getPrototypeOf(obj)
返回对象 obj 的 [[Prototype]]
Object.setPrototypeOf(obj, proto)
将对象 obj 的 [[Prototype]] 设置为 proto
类
类的基本语法
class MyClass { // class 方法 constructor() { ... } method1() { ... } ...}
然后使用 new MyClass() 来创建具有上述列出的所有方法的新对象。
类也可以有表达式
类其实是一种函数
class字段
类继承
extends关键字
例子:class Rabbit extends Animal
重写方法、constructor
执行 super.method(...) 来调用一个父类方法
执行 super(...) 来调用一个父类 constructor(只能在我们的 constructor 中
静态属性和静态方法
用static关键字把方法或属性赋值给类本身,而不是他的prototype
私有的和受保护的属性和方法
受保护
受保护的字段以 _ 开头。这是一个众所周知的约定,不是在语言级别强制执行的。程序员应该只通过它的类和从它继承的类中访问以 _ 开头的字段。
私有
私有字段以 # 开头。JavaScript 确保我们只能从类的内部访问它们。
扩展内建类
类检查:"instanceof"
instanceof 操作符
语法:obj instanceof Class如果 obj 隶属于 Class 类(或 Class 类的衍生类),则返回 true
它还可以与构造函数一起使用
通常,instanceof 在检查中会将原型链考虑在内
Mixin模式
Mixin — 是一个通用的面向对象编程术语:一个包含其他类的方法的类。
错误处理
try..catch
语法
try { } catch (err) { }
如果try错误,则转向catch,这里的err将包含一个error对象将包含发生事件的信息,err可以忽略
Error 对象
name
Error 名称。例如,对于一个未定义的变量,名称是 "ReferenceError"
message
关于 error 的详细文字描述。
次要stack
当前的调用栈:用于调试目的的一个字符串,其中包含有关导致 error 的嵌套调用序列的信息。
throw操作符
throw 操作符会生成一个 error 对象
throw <error object>
再次抛出技术
try…catch…finally
作用
无论是否错误,都会执行finally的代码
场景
finally 子句(clause)通常用在:当我们开始做某事的时候,希望无论出现什么情况都要完成完成某个任务。
全局catch
规范中没有相关内容,但是代码的执行环境一般会提供这种机制,因为它确实很有用。例如,Node.JS 有 process.on("uncaughtException")。在浏览器中,我们可以将将一个函数赋值给特殊的 window.onerror 属性,该函数将在发生未捕获的 error 时执行。
语法
window.onerror = function(message, url, line, col, error) { // ...};
作用
记录error
Promise,async/await
简介:回调
函数指针a作为参数传入函数b,在函数b中调用函数a,则a为回调函数
Promise
Promise对象的构造器语法
let promise = new Promise(function(resolve, reject) { // executor(生产者代码,“歌手”)});
当 executor 获得了结果,无论早晚,应调用两者回调之一
resolve(value) — 如果任务成功完成并带有结果 value
reject(error) — 如果出现了 error,error 即为 error 对象
promise对象的内部属性
state
最初是 "pending",然后在 resolve 被调用时变为 "fulfilled",或者在 reject 被调用时变为 "rejected"
result
最初是 undefined,然后在 resolve(value) 被调用时变为 value,或者在 reject(error) 被调用时变为 error
消费者函数
.then、.catch 和 .finally 方法
最重要最基础的一个就是 .then
promise.then( function(result) { }, function(error) { });
.then 的第一个参数是一个函数,该函数将在 promise resolved 后运行并接收结果。 .then 的第二个参数也是一个函数,该函数将在 promise rejected 后运行并接收 error。
.catch
如果我们只对 error 感兴趣,那么我们可以使用 null 作为第一个参数:.then(null, errorHandlingFunction)。或者我们也可以使用 .catch(errorHandlingFunction),其实是一样的
promise链
.then的结果可以作为下一个.then的参数来允许,如果.then里面由新的promise则等待这个promise允许完后再进行下一个then,下一个then的参数为这个promiser里面的resolve或者reject的结果
promise错误处理
Promise 链在错误(error)处理中十分强大。当一个 promise 被 reject 时,控制权将移交至最近的 rejection 处理程序(handler)
常用api
Async/await
async
async 确保了函数返回一个 promise,也会将非 promise 的值包装进去
async function f() { return 1;}
Await
Await只在 async 函数内工作
关键字 await 让 JavaScript 引擎等待直到 promise 完成(settle)并返回结果
promisification
微任务(Microtask)
Generator,高级 iteration
Generator
Generator 函数
语法
function* generateSequence() { yield 1; yield 2;return 3;}
会返回一个“generator object” 的特殊对象
generator可以调用的方法是next()返回value和done值
Generator 是可迭代的
可以对generator对象使用forof语句并且value为yield值
可以与[Symbol.iterator]()组合使用
*[Symbol.iterator]() // [Symbol.iterator]: function*() 的简写形式
使代码更加简洁
组合Generator
对于 generator 而言,我们可以使用 yield* 这个特殊的语法来将一个 generator “嵌入”(组合)到另一个 generator 中
yield* 指令将执行 委托 给另一个 generator。这个术语意味着 yield* gen 在 generator gen 上进行迭代,并将其产出(yield)的值透明地(transparently)转发到外部。就好像这些值就是由外部的 generator yield 的一样。
“yield” 是一条双向路
它不仅可以向外返回结果,而且还可以将外部的值传递到 generator 内。
方法
调用 generator.next(arg),我们就能将参数 arg 传递到 generator 内部。这个 arg 参数会变成 yield 的结果