现代JavaScript教程学习笔记
这是我学习现代JavaScript教程的笔记,他们的内容确实好,有一种相见恨晚的感觉,当时要是初学js能遇到就好了。。。 没有抄袭,只是笔记,并尝试自己稍微讲一下,如果涉及侵权,会立刻删除
try catch
try {
} catch(err) {
}
对于setTimeout
setTimeout(function() {
try {
} catch(err) {
}
}, 1000)
Error对象
有name message stack属性
throw可以跑出错误对象,此刻中断try,立刻执行catch
try {
return 1
} catch {
} finally {
}
如果return, finally在return前执行
自定义Error
class AError extends Error {
}
try {
} catch(err) {
if (err instanceof AError) {
} else {
throw err
}
}
创建MyError
class MyError extends Error {
constructor(message) {
super(message)
this.name = this.constructor.name
}
}
class ValidationError extends MyError {}
class PropertyRequiredError extends ValidationError {
constructor(property) {
super('no property: ' + property)
this.property = property
}
}
console.log(new PropertyRequiredError('filed').name)
包装异常
我们没必要把所有异常讨论清除,所以可以用ReadError封装,把错误保存其中并输出
class ReadError extends Error {
constructor(message, cause) {
super(message);
this.cause = cause;
this.name = 'ReadError';
}
}
class ValidationError extends Error { /*...*/ }
class PropertyRequiredError extends ValidationError { /* ... */ }
function validateUser(user) {
if (!user.age) {
throw new PropertyRequiredError("age");
}
if (!user.name) {
throw new PropertyRequiredError("name");
}
}
function readUser(json) {
let user
try {
user = JSON.parse(json)
} catch(err) {
if (err instanceof SyntaxError) {
throw new ReadError('syntax error', err)
} else {
throw err
}
}
try {
validateUser(user)
} catch (err) {
if (err instanceof ValidationError) {
throw new ReadError('validationError', err)
} else {
throw err
}
}
}
try {
readUser('')
} catch(e) {
if (e instanceof ReadError) {
console.log(e)
console.log(e.cause)
} else {
throw e
}
}
Promise
promise
为了处理回调地域,引入了Promise Promise对象有state和result属性,最初state为pending,resolve后未'fulfilled',reject后未'rejected' result最初undefined,resolve后未resolve的value, reject后未reject 的error
new Promise(function (resolve, reject) {
resolve('done') //resolve
console.log('888')//照常运行
reject('')//将忽略
}).then(function (res) {
console.log(res)//res 为resolve值
return Promise.resolve('aaa')
}).finally(function () {
console.log('kkk')
}).then(function (res) {
console.log(res)//为之前未处理的
})
promise链
new Promise(function(resolve, reject) {
setTimeout(() => resolve(1), 1000)
}).then(function(result) {
return new Promise(function(resolve, reject) {
setTimeout(() => resolve(2), 1000)
})
}).then(function(result) {
console.log(result)
})
Thenable对象
class Thenable {
constructor(num) {
this.num = num
}
then(resolve, reject) {
setTimeout(() => resolve(this.num), 1000)
}
}
new Promise(resolve => resolve(1))
.then(result => {
return new Thenable(result)
})
.then(result => console.log(result))
具有.then方法的对象,可以被当做promise处理 then中handler返回就是这种对象
如果throw error,等于是reject了,直接取catch处理,且当前函数内容不执行了
相关方法
Promise.all()全部promise都resolve,将结果数组组成新promise返回,顺序和之前一致
Promise.all([
new Promise(res => setTimeout(() => res(1), 1000)),
new Promise(res => setTimeout(() => res(2), 2000))
]).then(res => {
console.log(res)
})
Promise.allSettled对于结果reject也起作用,其他和Promise.all一样
Promise.race 只等待第一个 settled 的 promise 并获取其结果(或 error)
Promise.any只等待第一个 fulfilled 的 promise,并将这个 fulfilled 的 promise 返回。如果给出的 promise 都 rejected,那么则返回 rejected 的 promise 和 AggregateError 错误类型的 error 实例—— 一个特殊的 error 对象,在其 errors 属性中存储着所有 promise error。
Promise.resolve/Promise.reject返回resolve或reject的promise,就是将值进行封装
promisification
promisification指一个接受回调的函数转换为一个返回 promise 的函数。
function promisify(f) {
return function(...args) {
return new Promise((resolve, reject) => {
function callback(err,res) {
if (err) {
reject(err)
} else {
resolve(res)
}
}
args.push(callback)
f.call(this, args)
})
}
}
let loadScriptPromise = promisify(loadScript)
loadScriptPromise(...).then(...)
async await
async function f() {
let res = await new Thenable(1) //await 对Thenable对象也可以使用
return 1
}
f().then(res => console.log(res))
async返回一个promise
Generator
Generator可以按需一个接一个的返回多个值,可以与iterable配合使用
function* generateSequence() {
yield 1;
yield 2;
return 3;
yield 4;
}
let generator = generateSequence()
console.log(generator.next())
console.log(generator.next())
console.log(generator.next())
console.log(generator.next())
for (let val of generator) {
console.log(val)
}
使用Generator迭代
let range = {
from: 1,
to: 5,
*[Symbol.iterator]() {
for (let val = this.from; val <= this.to; val++) {
yield val
}
}
}
console.log([...range])
双向yield
function* gen() {
let result = yield '2 + 2 = ?'
console.log(result)
}
let generator = gen()
let question = generator.next().value
generator.next(4)
先是next到第一个yield取出值,然后再next传入4到result,再到下一个yield
generator.throw
function* gen() {
try {
let res = yield '2 + 2'
console.log(res)
} catch(e) {
console.log(e)
}
}
let generator = gen()
let question = generator.next().value
generator.throw(new Error('aaa'))
错误被穿进去了, 如果内部没有处理错误,就会出来
function* generate() {
let result = yield "2 + 2 = ?"; // 这行出现 error
}
let generator = generate();
let question = generator.next().value;
try {
generator.throw(new Error("The answer is not found in my database"));
} catch(e) {
alert(e); // 显示这个 error
}
generator.return
它直接完成执行,后面的就都结束了
function* gen() {
yield 1;
yield 2;
yield 3;
}
let generator = gen()
generator.next()
generator.return('foo')
generator.next()
异步Generator
异步可迭代对象 使用Symbol.asyncIterator, next()返回一个promise,可以通过async实现 使用for await ()
let range = {
from: 1,
to: 5,
[Symbol.asyncIterator]() {
return {
current: this.from,
last: this.to,
async next() {
await new Promise(resolve => setTimeout(resolve, 1000))
if (this.current <= this.last) {
return { done: false, value: this.current++}
} else {
return { done: true }
}
}
}
}
};
(async () => {
for await (let val of range) {
console.log(val)
}
})()
异步Generator
async function* generateSequence(start, end) {
for (let i = start; i <= end; i++) {
await new Promise(resolve => setTimeout(resolve, 1000))
yield i
}
}
由异步generator实现异步可迭代对象
let range = {
from:1,
to: 5,
async *[Symbol.asyncIterator]() {
for (let val= this.from; val <= this.to; val++) {
await new Promise(resolve => setTimeout(resolve, 1000))
yield val
}
}
}
模块
仅在第一次导入被解析,模块执行一次,在导入间共享
import.meta对象包含关于当前模块的信息
模块要在
<script type="module" src="">
</script>
中使用, 下载外部模块不会阻止html处理,它们会与其他资源并行加载,等html加载完成然后运行; 保持脚本相对顺序
import * as say from '...';
say.sayHi()
say.sayBye()
export { sayHi as hi }
export { sayBye as default }
重新导出
export { sayHi } from ''
动态导入
import '' 返回promise
let a = await import('')
不能根据条件或者在运行时导入
if () {
import ...;//Error
}
Proxy Reflect
let proxy = new Proxy(target, handler)
hanlder是捕捉器,通过丰富它来让proxy变得强大, 例如get
let numbers = [0, 1, 2];
numbers = new Proxy(numbers, {
get(target, prop) {
if (prop in target) {
return target[prop]
} else {
return 0
}
}
});
Reflect是一个内建对象,可以简化proxy的创建, 对于每个可以被proxy捕获的内部方法,在Reflect中都有一个对应的方法,其名称和参数与Proxy捕捉器相同 例如
let user = {
name: 'john'
}
user = new Proxy(user, {
get(target, prop, receiver) {
return Reflect.get(target, prop, receiver)
//或者
return Reflect.get(...arguments)
}
})
撤销Proxy
let object = {
data: "Valuable data"
};
let {proxy, revoke} = Proxy.revocable(object, {})
console.log(proxy.data)
revoke()
console.log(proxy.data)
Reference Type
let user = {
name: "John",
hi() { alert(this.name); },
bye() { alert("Bye"); }
};
user.hi(); // 正常运行
// 现在让我们基于 name 来选择调用 user.hi 或 user.bye
(user.name == "John" ? user.hi : user.bye)(); // Error!
为什么? 为确保user.hi()调用正常运行,js中'.'返回的不是一个函数,而是一个特殊的Reference Type的值 他是一个三个值的组合(base, name, strict) base是对象名, name是属性名, strict在严格模式下为true user.hi是一个Reference Type值, 为(user, 'hi', true),当()被Reference Type上调用时, 它们会接收到关于对象和对象的方法的完整信息,设置this(为user) 但是如果
let hi = user.hi
hi()
例如此类的赋值等操作,会将Reference Type作为一个整体丢弃掉,而是用user.hi(一个函数)的值并继续传递,所以任何后序操作都失去this,只有obj.method() obj'method' 才能被正确传递
BigInt
let bigint = 1111111111111111111111111111n;
let aBig = BigInt('2222222222222222222222222222222')
let big = BigInt(10) // 10n
无限长
console.log(1n + 2n)
console.log(5n / 2n)
结果也是BigInt
console.log(1n + 2)//不可以,不能混着用
let bigint = 1n;
let number = 2;
// 将 number 转换为 bigint
alert(bigint + BigInt(number)); // 3
// 将 bigint 转换为 number
alert(Number(bigint) + number); // 3
console.log(1 == 1n) // true
console.log(1 === 1n) // false
console.log(2n > 1) // true
这是我用vue3实现的饿了么,如果您感兴趣,希望您能看看,谢谢 github.com/goddessIU/v…
项目预览地址 goddessiu.github.io/