跳到主要内容

JS高级特性,闭包和异步

危险

这篇是重中之重, 不要光看,要多写写,预计2天能完成本篇。

JS这块内容,主要是学习一下,在JS中经常会用到的一些知识,便于能够看懂程序员写的代码。

异步

所谓「同步(synchronization)」,简单来说,就是「顺序执行」,指的是同一时间只能做一件事情,只有目前正在执行的事情做完之后,才能做下一件事情。

「同步操作的优点」在于做任何事情都是依次执行,井然有序,不会存在大家同时抢一个资源的问题。

「同步操作的缺点」在于「会阻塞后续代码的执行」。如果当前执行的任务需要花费很长的时间,那么后面的程序就只能一直等待。

所谓「异步(Asynchronization)」,指的是当前代码的执行不影响后面代码的执行。当程序运行到异步的代码时,会将该异步的代码作为任务放进「任务队列」,而不是推入主线程的调用栈。等主线程执行完之后,再去任务队列里执行对应的任务即可。

因此,「异步操作的优点就是:不会阻塞后续代码的执行。」

提示

这篇文档要学习一下,

里面有这两项"micro 和 taskevent loop的处理过程",这两项不要学习。

目标是:能够按照文章所示,第三小节里面的,Promise,也能自己实现一个Promise https://www.jianshu.com/p/667936441cb5

基本类型和引用类型

JS有7种内置类型

存放位置:基本类型值在内存中占据固定大小,直接存储在栈内存中的数据。引用类型:在栈中存储了指针,这个指针指向内存中的地址,真实的数据存放到堆内存里面。 分类:

基本数据类型 null, undefined, boolean, number, string, symbol

引用类型(Object子类和基本包装类型) Object子类 Array, Function, Date, RegExp 基本包装类型 Boolean, Number, String

获得一个变量的正确类型,可以通过 Object.prototype.toString.call(xx)。这样我们就可以获得类似 [object Type] 的字符串。

Object.prototype.toString.call(22)            //"[object Number]"
Object.prototype.toString.call('22') //"[object String]"
Object.prototype.toString.call(null) //"[object Null]"
Object.prototype.toString.call(undefined) //"[object Undefined]"
Object.prototype.toString.call(a) //"[object Undefined]"
Object.prototype.toString.call(true) //"[object Boolean]"
Object.prototype.toString.call({a:1}) //"[object Object]"

类型转换

四则运算

加法,只要有一个字符串就全部是字符串 其他符号,直接全部转为数字,转不动的话是NaN

1 + "" // "1"
true + true // 2
4 + [1,2,3] // "41,2,3"

判断数组的方式有哪些

[] instanceof window.Array
Array.isArray([])
Object.prototype.toString.call([])
[].__proto__.constructor === window.Array

显式类型转换

Boolean([]) // true
String(1) // "1"
Number("2") // 2
Object({}) // {}
parseInt("") // NaN

隐式类型转化

typeof (1 + "") // "1" string 
+"123" // 一元加 Number 123
+"1你好" // NaN
+"你好" // NaN
!![] // true
+[] // 0
+![] // 0
null、undefined、NaN详解
null // 代表不存在,
undefined // 代表未定义
NaN // 不是一个数字
NaN === NaN // false
Number.isNaN(NaN, NaN) // true

Promise

信息

学会Promise

前面异步里面的知识已经接触了Promise,这里进行总结,总结Promise,方便记忆。

什么是Promise?

Promise是一种用于处理异步操作的模式。有三种状态 待定(pending):初始状态,既没有被兑现,也没有被拒绝。 已兑现(fulfilled):意味着操作成功完成。 已拒绝(rejected):意味着操作失败。

Promise有哪些常见方法?

  • then 该方法返回一个Promise,当原始Promise的状态变为fulfilled或rejected时,它就会调用相应的回调函数。回调函数中的this关键字指向原始Promise。
  • catch 该方法返回一个Promise,用于处理原始Promise状态为rejected的情况。与then不同的是,catch不接受回调函数参数,并且catch中的回调函数会捕获到原始Promise状态为rejected时的任何错误信息。
  • finally 该方法返回一个Promise,不论原始Promise的状态是fulfilled还是rejected,finally的回调函数都会被执行。
  • all 必须全部成功,then返回的参数是一个数组,只要有一个失败了,那么直接走catch逻辑。
  • 静态方法接受一个 Promise 可迭代对象作为输入,并返回一个 Promise。当所有输入的 Promise 都被兑现时,返回的 Promise 也将被兑现(即使传入的是一个空的可迭代对象),并返回一个包含所有兑现值的数组。如果输入的任何 Promise 被拒绝,则返回的 Promise 将被拒绝,并带有第一个被拒绝的原因。
  • race 该方法返回一个Promise,当原始Promise数组中的任何一个Promise的状态变为fulfilled或rejected时,就会调用相应的回调函数。与all不同的是,race只关心第一个改变状态的Promise。
  • resolve 该方法返回一个fulfilled状态的Promise,其结果值是传递给resolve的参数。
  • reject 该方法返回一个rejected状态的Promise,其错误信息是传递给reject的参数。
  • allSettled 不管是已兑现还是已拒绝,会把所有的promise数组的结果都输出。 静态方法将一个 Promise 可迭代对象作为输入,并返回一个单独的 Promise。当所有输入的 Promise 都已敲定时(包括传入空的可迭代对象时),返回的 Promise 将被兑现,并带有描述每个 Promise 结果的对象数组。Promise.allSettled() 方法是 promise 并发方法之一。在你有多个不依赖于彼此成功完成的异步任务时,或者你总是想知道每个 promise 的结果时,使用 Promise.allSettled() 。 相比之下,如果任务相互依赖,或者如果你想在任何 promise 被拒绝时立即拒绝,Promise.all() 返回的 Promise 可能更合适。
let promise1 = Promise.resolve(1)
let promise2 = Promise.reject("error")
let promiseAll = Promise.allSettled([promise1, promise2]).then(data => {
console.log("then", JSON.stringify(data))
})
// [{"status":"fulfilled","value":1},{"status":"rejected","reason":"error"}]

any 静态方法将一个 Promise 可迭代对象作为输入,并返回一个 Promise。当输入的任何一个 Promise 兑现时,这个返回的 Promise 将会兑现,并返回第一个兑现的值。当所有输入 Promise 都被拒绝(包括传递了空的可迭代对象)时,它会以一个包含拒绝原因数组的 AggregateError 拒绝

什么是作用域链

信息

了解即可,不要深究

作用域链:是在使用变量时,从内到外,自下而上(作用域)查找的链条。

作用域链是JavaScript中一个重要的概念,它决定了变量和函数的可访问性。作用域链的形成是基于函数的嵌套关系。当一个函数被创建时,它会保存对其父级作用域的引用,形成一个链式结构。

每个执行上下文(Execution Context)都有一个变量对象(Variable Object),用于存储函数内部的变量、函数和参数。当函数执行时,会创建一个新的变量对象,其中包含函数内部的变量和参数。同时,这个新的变量对象会保留对上一级作用域的引用,以便在函数执行期间可以访问上一级作用域中的变量和函数。

当一个变量被访问时,JavaScript会首先在当前作用域中查找这个变量。如果找不到,则会向上一级作用域继续查找,直到找到对应的变量或达到顶层作用域。这个查找的过程就称为作用域链的查找。

在JavaScript中,全局变量可以在任何地方访问,而局部变量只能在定义它的函数内部访问。如果一个变量既不是全局变量也不是局部变量,那么它就是闭包中的变量。闭包是一种特殊的作用域,它允许一个函数访问其外部的作用域中的变量。

通过理解作用域链的概念,我们可以更好地理解JavaScript中的变量作用域和函数执行机制。同时,掌握作用域链的使用也可以帮助我们编写更加健壮和可维护的代码。

什么是闭包

信息

学会

在javascript中,只有函数内部的子函数才能读取局部变量,所以闭包可以理解成“定义在一个函数内部的函数”。在本质上,闭包是将函数内部和函数外部连接起来的桥梁。 在JavaScript中,闭包是一种特殊的功能,它使函数可以访问并操作函数外部的变量。要理解闭包,首先要了解JavaScript中的变量作用域。 在JavaScript中,变量的作用域可以是全局的或局部的。全局变量在整个代码中都可见,而局部变量只在定义它的函数内部可见。当一个函数执行时,会创建一个作用域,在这个作用域内声明的所有变量都是局部变量。 闭包是由两部分组成的:一个闭包定义和闭包使用。 闭包定义:在函数内部定义另一个函数,这个函数可以访问其外部函数的变量和参数。 例如:

function outerFunction(outerParam) {
var outerVar = outerParam;
function innerFunction() {
console.log(outerVar); // 可以访问外部函数的变量
}
return innerFunction; // 返回内部函数,使得内部函数可以继续访问外部函数的变量
}

在这个例子中,innerFunction 是一个闭包,它可以访问 outerFunction 的局部变量 outerVar 和参数 outerParam。

闭包使用:通过调用返回的内部函数,可以实际使用闭包。 例如:

var innerFunc = outerFunction("Hello"); // 调用外部函数,并将内部函数赋值给 innerFunc  
innerFunc(); // 执行 innerFunc,输出 "Hello"

在这个例子中,我们首先调用 outerFunction 并传入一个参数 "Hello"。这个函数返回了 innerFunction 的引用,我们将这个引用存储在 innerFunc 变量中。然后我们调用 innerFunc,它访问并输出了 outerFunction 的局部变量 outerVar 的值 "Hello"。这是闭包的典型应用之一,常用于实现数据封装和私有方法等。

原型和原型链

信息

做到能够完成作业的水平

参考文章学习

https://www.jianshu.com/p/60b1eefa33ed

https://blog.csdn.net/m0_55734030/article/details/127971640

这篇文章需看懂最后的图。 https://www.jianshu.com/p/3b9f01c9692f

信息

作业:假如自己创建了一个数组 let arr = new Array[],请画出他的原型链。