首页IT科技javascript高级程序设计最新(JavaScript进阶)

javascript高级程序设计最新(JavaScript进阶)

时间2025-09-19 13:22:18分类IT科技浏览5277
导读:javaScript进阶 一、作用域...

javaScript进阶

一               、作用域

JS的作用域简单来说就是变量(变量作用于又称上下文)和函数生效(能被访问)的区域

1.全局作用域

函数之外声明的变量               ,会成为全局变量               。

变量在程序的任何地方都能被访问                       ,表示它是全局变量       ,window 对象的内置属性都拥有全局作用域                      。

自动全局

如果您为尚未声明的变量赋值       ,此变量会自动成为全局变量

2.函数作用域

在固定的代码片段(函数)才能被访问

函数作用域就是一个独立的地盘                       ,让变量不会外泄                      、暴露出去        。也就是说作用域最大的用处就是隔离变量               ,不同作用域下同名变量不会有冲突               。

变量取值:到创建 这个变量 的函数的作用域中取值

3.作用域链

变量取值到 创建 这个变量 的函数的作用域中取值                      。

但是如果在当前作用域中没有查到值       ,就会向上级作用域去查                      ,直到查到全局作用域               ,这么一个查找过程形成的链条就叫做作用域链        。

JavaScript 属于解释型语言,JavaScript 的执行分为:解释和执行两个阶段,这两个阶段所做的事并不一样:

解释阶段: 词法分析 语法分析 作用域规则确定 执行阶段: 创建执行上下文 执行函数代码 垃圾回收

JavaScript 解释阶段便会确定作用域规则                      ,因此作用域在函数定义时就已经确定了                      ,而不是在函数调用时确定,但是执行上下文是函数执行之前创建的       。执行上下文最明显的就是 this 的指向是执行时确定的                      。而作用域访问的变量是编写代码的结构确定的               。

作用域和执行上下文之间最大的区别是:

执行上下文在运行时确定               ,随时可能改变;作用域在定义时就确定                      ,并且不会改变       。

一个作用域下可能包含若干个上下文环境                      。有可能从来没有过上下文环境(函数从来就没有被调用过);有可能有过       ,现在函数被调用完毕后               ,上下文环境被销毁了;有可能同时存在一个或多个(闭包)               。同一个作用域下                       ,不同的调用会产生不同的执行上下文环境       ,继而产生不同的变量的值。

二        、this指向

在函数内       ,this是非常特殊的关键词标识符                       ,在每个函数的作用域中被自动创建

当函数被调用               ,一个上下文就被创建                      。上下文包括函数在哪调用       ,谁调用的                      ,参数是哪些               ,等等,上下文中的this                      ,指的就是函数指行期间的this                      。this的上下文基于函数调用的情况。和函数在哪定义无关                      ,但是和函数怎么调用有关

this理解的关键:

1:this永远指向一个对象;

2:this的指向完全取决于函数调用的位置;

1               、全局

在全局上下文(任何函数以外),this指向全局对象               。

console.log(this === window); // true

2                      、函数

在函数内部时               ,this由函数怎么调用来确定

//简单调用                      ,即独立函数调用 function f1(){ return this; } //当前调用者其实是window window.f1() f1() === window;

当函数作为对象方法调用时       ,this指向该对象

var obj = { type: 1, name: Tina, age: 18, sayHi:function(){ console.log(this) console.log(hi~~) } } //this === obj obj.sayHi()

3.构造函数

构造函数的this指向创建的实例对象

function Obj (name,age){ this.name = name this.age = age this.sayHai= function(){ console.log(this) } } let o = new Obj(Tina               ,18) //{name: tina, age: 18}

构造函数执行过程分为4步:

第一步: 创建一个Object对象实例                      。

第二步: 将构造函数的执行对象赋给新生成的这个实例        。

第三步: 执行构造函数中的代码

第四步: 返回新生成的对象实例
function Obj (name){ this.name = name return name } let o = new Obj(Tina) // ???

构造函数在new的时候                       ,会默认创建一个空的 { },并且把构造函数的prototype赋值给空对象的__proto__       ,当构造函数返回值不是对象时       ,返回值就会默认成构造函数自己创建的对象

4.call和apply

call和apply可以指定函数运行时的this

call方法使用的语法规则

函数名称.call(obj,arg1,arg2...argN);

参数说明:

obj:函数内this要指向的对象,

arg1,arg2...argN :参数列表                       ,参数与参数之间使用一个逗号隔开

apply方法使用的语法规则

函数名称.apply(obj,[arg1,arg2...,argN])

参数说明:

obj :this要指向的对象

[arg1,arg2...argN] : 参数列表               ,要求格式为数组 function add(c, d){ return this.a + this.b + c + d; } var o = {a:1, b:3}; add.call(o, 5, 7); // 1 + 3 + 5 + 7 = 16 add.apply(o, [10, 20]); // 1 + 3 + 10 + 20 = 34

练习题

var A = { name: 张三, f: function () { console.log(姓名: + this.name); } }; var B = { name: 李四 }; B.f = A.f; B.f() A.f() function foo() { console.log(this.a); } var obj2 = { a: 2, fn: foo }; var obj1 = { a: 1, o1: obj2 }; obj1.o1.fn(); var o = { a:10, b:{ a:12, fn:function(){ console.log(this.a); console.log(this); } } } var j = o.b.fn; j(); var x = 3; var y = 4; var obj = { x: 1, y: 6, getX: function() { var x =5; return function() { return this.x; }(); }, getY: function() { var y =7; return this.y; } } console.log(obj.getX()) console.log(obj.getY()) var name="the window"; var object={ name:"My Object", getName:function(){ return this.name; } } object.getName(); (object.getName)(); (object.getName=object.getName)();

三        、原型

1.prototype

在JavaScript中       ,每个函数 都有一个prototype属性                      ,当一个函数被用作构造函数来创建实例时               ,这个函数的prototype属性值会被作为原型赋值给对象实例(也就是设置 实例的__proto__属性),也就是说                      ,所有实例的原型引用的是函数的prototype属性               。

构造函数使用方式

function Person(name,age){ this.name = name this.age = age } var p = new Person(张三,20);

每一个JavaScript对象(除了 null )都具有的一个属性                      ,叫__proto__,这个属性会指向该对象的原型

console.log(p.__proto__ === Person.prototype); // true

2.constructor

每个原型都有一个 constructor 属性指向关联的构造函数

console.log(Person === p.__proto__.constructor); //true

在 Javascript 语言中               ,constructor 属性是专门为 function 而设计的                      ,它存在于每一个 function 的prototype 属性中                      。这个 constructor 保存了指向 function 的一个引用

通过构造函数创建的对象       ,constructor 指向构造函数               ,而构造函数本身的constructor                       ,则指向Function本身       ,因为所有的函数都是通过new Function()构造的

function Person() { } var p = new Person() console.log(Person.prototype); // Object{} console.log(p.prototype); // undifined console.log(p.constructor); //function Person(){} 此处的p是通过 Person函数构造出来的       ,所以p的constructor属性指向Person console.log(Person.constructor); //function Function(){} 之前提过                       ,每个函数其实是通过new Function()构造的 console.log({}.constructor); // function Object(){} 每个对象都是通过new Object()构造的 console.log(Object.constructor); // function Function() {} Object也是一个函数               ,它是Function()构造的 console.log([].constructor); //function Array(){}

函数是对象构造的 对象也是函数构造的       ,俩者即是函数也是对象                      ,所以为什么构造函数它是一个函数却返回一个对象               ,俩者是互相继承的关系

var o1 = new f1(); typeof o1 //"object"

prototype的用法

最主要的方法就是将属性暴露成公用的

代码对比:

function Person(name,age){ this.name = name; this.age = age; this.sayHello = function(){ console.log(this.name + "say hello"); } } var girl = new Person("bella",23); var boy = new Person("alex",23); console.log(girl.name); //bella console.log(boy.name); //alex console.log(girl.sayHello === boy.sayHello); //false function Person(name,age){ this.name = name; this.age = age; } Person.prototype.sayHello=function(){ console.log(this.name + "say hello"); } var girl = new Person("bella",23); var boy = new Person("alex",23); console.log(girl.name); //bella console.log(boy.name); //alex console.log(girl.sayHello === boy.sayHello); //true

总结:

function Person(){ } var person1=new Person() person1.__proto__==Person.prototype person1.constructor==Person Person.__proto__==Function.prototype Person.prototype.constructor==Person person1.__proto__.constructor==Person

四       、原型链

在js中,大部分东西都是对象                      ,数组是对象                      ,函数也是对象,对象更加是对象        。不管我们给数组和函数定义什么内容               ,它们总是有一些相同的方法和属性       。比如说valueOf()                      ,toString()等

这说明一个对象所拥有的属性不仅仅是它本身拥有的属性       ,它还会从其他对象中继承一些属性                      。当js在一个对象中找不到需要的属性时               ,它会到这个对象的父对象上去找                       ,以此类推       ,这就构成了对象的原型链

function Foo(_name) { this.name = _name; } Foo.prototype.show = function() { console.log(I am , this.name); }; var f1 = new Foo(obj1); var f2 = new Foo(obj2); f1.show(); // I am obj1 f2.show(); // I am obj2 //我们定义的show函数在Foo.prototype中       ,当我们执行f1.show()时                       ,js发现f1本身没有show这个属性               ,所以它就到f1的原型(也就是__proto__指向的对象)去找       ,找到了就可以调用

图片第一行告诉了我们4点:

所有函数都有一个prototype指针                      ,指向原型对象               ,如图中的Foo的prototype指针               。prototype指针的意义是,当我们使用这个构造函数new出新对象的时候                      ,新对象的__proto__指向prototype

构造函数的prototype所指向的原型对象有一个constructor指针                      ,指回构造函数       。如图中Foo.prototype的constructor指针指向Foo                      。constructor指针有助于我们找到一个对象的构造函数是谁               。

__proto__每个对象都有,js在new一个对象的时候               ,会将它的__proto__指向构造函数的prototype指向的那个对象。在上图中                      ,f1                      、f2这些实例对象的__proto__都指向了Foo.prototype                      。

如果一个对象的__proto__指向了另一个对象       ,那么前者就继承了后者的所有属性

function Foo(_name) { this.name = _name; } Foo.prototype.show = function() { console.log(I am , this.name); }; var f1 = new Foo(obj1); var f2 = new Foo(obj2); var obj = { type:1 } f1.__proto__ = obj console.dir(f1) f1.show(); // I am obj1 f2.show(); // I am obj2

Foo是一个函数               ,它的构造函数是js内部的function Function()                       ,Function的prototype指向了一个对象Function.prototype       ,因此Foo的__proto__就指向了Function.prototype

所有的函数都以function Function()为构造函数       ,因此                       ,所有函数(包括function Function()和function Object())的__proto__都指向Function.prototype这个对象               ,这个对象中定义了所有函数都共有的方法       ,比如call()               、apply()等                      。

我们继续深入下去                      ,Function.prototype这个对象               ,它就是一个普通的对象,它的构造函数是js内置的function Object()                      ,function Object()的prototype指向Object.prototype                      ,因此Function.prototype.__proto__就指向Object.prototype,这个对象中定义了所有对象共有的属性               ,比如我们之前说的hasOwnProperty()和toString()等。

同理                      ,Foo.prototype和其他自定义的对象也是__proto__指向Object.prototype对象

Object.prototype就是原型链的终点了       ,它的__proto__是null               ,js查找属性时                       ,如果到这里还没有找到       ,那就是undefined了

五       、闭包

函数和函数内部能访问到的变量加在一起就是一个闭包

常规认为       ,一个函数嵌套另一个函数                       ,两个函数中间的环境               ,叫闭包       ,但其实这也是制造一个不会被污染沙箱环境                      ,实质上               ,由于js函数作用域的存在,所有的函数                      ,都可以是一个闭包

function foo(){ var num = 1 function add(){ num++ return num } return add } var func = foo() func()

闭包常常用来间接访问一个变量也可以理解为隐藏一个变量

function foo(){ var num = 18 var obj = { text:我是一个字符串, getNUm:function(){ return num } } return obj } var obj = foo() var age = obj.getNUm() console.log(age)

由于 JS 的函数内部可以使用函数外部的变量                      ,而函数外部无法访问到函数内部的变量,所以正好符合了闭包的定义               。所以只要懂了 JS 的作用域               ,自然而然就懂了闭包                      。

六                      、事件机制

JavaScript语言的一大特点就是单线程                      ,也就是说       ,同一个时间只能做一件事

单线程就意味着               ,所有任务需要排队                       ,前一个任务结束       ,才会执行后一个任务        。如果前一个任务耗时很长       ,后一个任务就不得不一直等着               。于是                       ,所有任务可以分成两种               ,一种是同步任务       ,另一种是异步任务

同步任务指的是                      ,在主线程上排队执行的任务               ,只有前一个任务执行完毕,才能执行后一个任务;

异步任务指的是                      ,不进入主线程               、而进入"任务队列" 的任务                      ,只有"任务队列"通知主线程,某个异步任务可以执行了               ,该任务才会进入主线程执行                      。

所有同步任务都在主线程上执行                      ,形成一个执行栈        。

主线程之外       ,还存在一个"任务队列"       。只要异步任务有了运行结果               ,就在"任务队列"之中放置一个事件

一旦"执行栈"中的所有同步任务执行完毕                       ,系统就会读取"任务队列"       ,看看里面有哪些事件                      。那些对应的异步任务       ,于是结束等待状态                       ,进入执行栈               ,开始执行

主线程不断重复上面的第三步

console.log(1); setTimeout(function() { console.log(2); },1000) setTimeout(function() { console.log(3); },0) console.log(4); /* 分析: 同步任务       ,按照顺序一步一步执行 异步任务                      ,当读取到异步任务的时候               ,将异步任务放置到任务队列 中,当满足某种条件或者说指定事情完成了(这里的是时间分别是达到了0ms和1000ms)当指定 事件完成了才从任务队列中注册到主线程的事件队列                      ,当同步事件完成了                      ,便从 事件队列中读取事件执行               。(因为3的事情先完成了,所以先从任务队列中注册到 事件队列中               ,所以先执行的是3而不是在前面的2) */ 宏任务与微任务

宏任务:script代码                      ,setTimeout       ,setInterval

微任务:Promise               ,process.nextTick

不同类型的任务会进入对应的任务队列       。

事件循环的顺序                       ,决定js代码的执行顺序                      。

进入整体代码(宏任务)后       ,开始第一次循环               。

接着执行所有的微任务。然后再次从宏任务开始       ,找到其中一个任务队列执行完毕                       ,再执行所有的微任务

console.log(1); setTimeout(function() { console.log(2) },1000); new Promise(function(resolve) { console.log(3); resolve(); } ).then(function() { console.log(4) }); console.log(5); /* 为什么是这样呢?因为以同步异步的方式来解释执行机制是不准确的               ,更加准确的方式是宏任务和微任务: 因此执行机制便为:执行宏任务 ===> 执行微任务 ===> 执行另一个宏任务 ===> 不断循环 即:在一个事件循环中       ,执行第一个宏任务                      ,宏任务执行结束               ,执行当前事件循环中的微任务, 执行完毕之后进入下一个事件循环中                      ,或者说执行下一个宏任务 */

七、ES6

1.let

let 声明的变量只在 let 命令所在的代码块内有效

{ let a = 0; a // 0 } a // 报错 ReferenceError: a is not defined

let 只能声明一次 (var 可以声明多次)

let a = 1; let a = 2; var b = 3; var b = 4; a // Identifier a has already been declared 标识符“a               ”已声明 b // 4

let 不存在变量提升                      ,var 会变量提升

console.log(a); //ReferenceError: a is not defined 引用错误:未定义a let a = "apple"; console.log(b); //undefined var b = "banana";

2.const

const 声明一个只读的常量,一旦声明               ,常量的值就不能改变

const PI = "3.1415926"; PI = 123 //Assignment to constant variable 常量变量的赋值

暂时性死区:

var PI = "a"; if(true){ console.log(PI); // ReferenceError: PI is not defined const PI = "3.1415926"; }

ES6 明确规定                      ,代码块内如果存在 let 或者 const       ,代码块会对这些命令声明的变量从块的开始就形成一个封闭作用域                      。代码块内               ,在声明变量 PI 之前使用它会报错                      。

3.解构赋值

解构赋值是对赋值运算符的扩展                       ,是一种针对数组或者对象进行模式匹配       ,然后对其中的变量进行赋值处理

基本

let [a, b, c] = [1, 2, 3]; // a = 1 // b = 2 // c = 3 let { foo, bar } = { foo: aaa, bar: bbb }; // foo = aaa // bar = bbb let { baz : foo } = { baz : ddd }; // foo = ddd

可嵌套

let [a, [[b], c]] = [1, [[2], 3]]; // a = 1 // b = 2 // c = 3 let obj = {p: [hello, {y: world}] }; let {p: [x, { y }] } = obj; // x = hello // y = world let obj = {p: [hello, {y: world}] }; let {p: [x, { }] } = obj; // x = hello

可忽略

let [a, , b] = [1, 2, 3]; // a = 1 // b = 3

不完全解构

let [a = 1, b] = []; // a = 1, b = undefined let obj = {p: [{y: world}] }; let {p: [y, x] } = obj; // x = undefined // y = world

剩余运算符

let [a, ...b] = [1, 2, 3]; //a = 1 //b = [2, 3] let {a, b, ...rest} = {a: 10, b: 20, c: 30, d: 40}; // a = 10 // b = 20 // rest = {c: 30, d: 40}

解构默认值

let [a = 2] = [undefined]; // a = 2 let {a = 10, b = 5} = {a: 3}; // a = 3; b = 5; let {a: aa = 10, b: bb = 5} = {a: 3}; // aa = 3; bb = 5;

字符串等

在数组的解构中       ,解构的目标若为可遍历对象                       ,皆可进行解构赋值

let [a, b, c, d, e] = hello; // a = h // b = e // c = l // d = l // e = o

4.Proxy

Proxy 可以对目标对象的读取                      、函数调用等操作进行拦截               ,然后进行操作处理。它不直接操作对象       ,而是像代理模式                      ,通过对象的代理对象进行操作               ,在进行这些操作时,可以添加一些需要的额外操作

let target = { name: Tom, age: 24 } let handler = { get: function(target, key) { console.log(getting +key); return target[key]; // 不是target.key }, set: function(target, key, value) { console.log(setting +key); target[key] = value; } } let proxy = new Proxy(target, handler) proxy.name // 实际执行 handler.get proxy.age = 25 // 实际执行 handler.set // getting name // setting age // 25

5.箭头函数

箭头函数提供了一种更加简洁的函数书写方式               。基本语法是:

参数 => 函数体 var f = v => v; //等价于 var f = function(a){ return a; } f(1); //1

当箭头函数没有参数或者有多个参数                      ,要用 () 括起来

var f = (a,b) => a+b; f(6,2); //8

当箭头函数函数体有多行语句                      ,用 {} 包裹起来,表示代码块               ,当只有一行语句                      ,并且需要返回结果时       ,可以省略 {} , 结果会自动返回

var f = (a,b) => { let result = a+b; return {}; } f(6,2); // 8

当箭头函数要返回对象的时候               ,为了区分于代码块                       ,要用 () 将对象包裹起来

// 报错 var f = (id,name) => {id: id, name: name}; f(6,2); // SyntaxError: Unexpected token : // 不报错 var f = (id,name) => ({id: id, name: name}); f(6,2); // {id: 6, name: 2}

箭头函数没有 this                      、arguments绑定

var func = () => { // 箭头函数里面没有 this 对象       , // 此时的 this 是外层的 this 对象       ,即 Window console.log(this) } func(55) // Window var func = () => { console.log(arguments) } func(55); // ReferenceError: arguments is not defined

箭头函数体中的 this 对象                       ,是定义函数时的对象               ,而不是使用函数时的对象

function fn(){ setTimeout(()=>{ // 定义时       ,this 绑定的是 fn 中的 this 对象 console.log(this.a); },0) } var a = 20; fn() // fn 的 this 对象为 window 所以打印20

6.class类

在ES6中                      ,class (类)作为对象的模板被引入               ,可以通过 class 关键字定义类                      。class 的本质是 function        。

它可以看作一个语法糖,让对象原型的写法更加清晰、更像面向对象编程的语法

注意要点:不可重复声明

class Example { constructor(a) { this.a = a; } } let obj = new Example(1) console.log(obj)

通过 extends 实现类的继承

class Child extends Example { constructor(a,b) { super(b); this.b = a; this.hi=()=>alert(hi) } } let b = new Child(1,2) console.log(b)//{a:2,b:1,hi:()=>alert(hi)}

7.模块

export和import

ES6 的模块化分为导出(export) @与导入(import)两个模块

模块导入导出各种类型的变量                      ,如字符串                      ,数值,函数               ,类               。

导出的函数声明与类声明必须要有名称(export default 命令另外考虑)                      。 不仅能导出声明还能导出引用(例如函数)        。 export 命令可以出现在模块的任何位置 import 命令会提升到整个模块的头部                      ,首先执行       。 /*-----export [test.js]-----*/ let myName = "Tom"; let myAge = 20; let myfn = function(){ return "My name is" + myName + "! Im " + myAge + "years old." } let myClass = class myClass { static a = "yeah!"; } export { myName, myAge, myfn, myClass } /*-----import [xxx.js]-----*/ import { myName, myAge, myfn, myClass } from "./test.js"; console.log(myfn());// My name is Tom! Im 20 years old. console.log(myAge);// 20 console.log(myName);// Tom console.log(myClass.a );// yeah! as 的用法

export 命令导出的接口名称       ,须和模块内部的变量有一一对应关系

导入的变量名               ,须和导出的接口名称相同                       ,顺序可以不一致

不同模块导出接口名称命名重复       , 使用 as 重新定义变量名

/*-----export [test.js]-----*/ let myName = "Tom"; export { myName as exportName } /*-----import [xxx.js]-----*/ import { exportName } from "./test.js"; console.log(exportName);// Tom //使用 as 重新定义导出的接口名称       ,隐藏模块内部的变量 /*-----export [test1.js]-----*/ let myName = "Tom"; export { myName } /*-----export [test2.js]-----*/ let myName = "Jerry"; export { myName } /*-----import [xxx.js]-----*/ import { myName as name1 } from "./test1.js"; import { myName as name2 } from "./test2.js"; console.log(name1);// Tom console.log(name2);// Jerry export default 在一个文件或模块中                       ,export               、import 可以有多个               ,export default 仅有一个                      。 export default 中的 default 是对应的导出接口变量               。 通过 export 方式导出       ,在导入时要加{ }                      ,export default 则不需要       。 export default 向外暴露的成员               ,可以使用任意变量来接收                      。 var a = "My name is Tina!"; export default a; // 仅有一个 import b from "./xxx.js"; // 不需要加{}, 使用任意变量接收

8.Promise

Promise 异步操作有三种状态:pending(进行中)                      、fulfilled(已成功)和 rejected(已失败)               。除了异步操作的结果                      ,任何其他操作都无法改变这个状态。

Promise 对象只有:从 pending 变为 fulfilled 和从 pending 变为 rejected 的状态改变                      。只要处于 fulfilled 和 rejected                       ,状态就不会再变了即 resolved(已定型)

const p1 = new Promise(function(resolve,reject){ resolve(success1); // resolve(success2); }); const p2 = new Promise(function(resolve,reject){ resolve(success3); // reject(reject); }); p1.then(function(value){ console.log(value); // success1 }); p2.then(function(value){ console.log(value); // success3 });

无法取消 Promise ,一旦新建它就会立即执行               ,无法中途取消                      。

如果不设置回调函数                      ,Promise 内部抛出的错误       ,不会反应到外部。

当处于 pending 状态时               ,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)

then方法

then 方法接收两个函数作为参数                       ,第一个参数是 Promise 执行成功时的回调       ,第二个参数是 Promise 执行失败时的回调       ,两个函数只会有一个被调用               。

在 JavaScript 事件队列的当前运行完成之前                       ,回调函数永远不会被调用

const p = new Promise(function(resolve,reject){ resolve(success); }); p.then(function(value){ console.log(value); }); console.log(first); // first // success

通过 .then

形式添加的回调函数               ,不论什么时候       ,都会被调用                      。

then 方法将返回一个 resolved 或 rejected 状态的 Promise 对象用于链式调用                      ,且 Promise 对象的值就是这个返回值

多次调用

const p = new Promise(function(resolve,reject){ resolve(1); }).then(function(value){ // 第一个then // 1 console.log(value); return value * 2; }).then(function(value){ // 第二个then // 2 console.log(value); }).then(function(value){ // 第三个then // undefined console.log(value); return Promise.resolve(resolve); }).then(function(value){ // 第四个then // resolve console.log(value); return Promise.reject(reject); }).then(function(value){ // 第五个then //reject:reject console.log(resolve: + value); }, function(err) { console.log(reject: + err); });

9.async

async 函数返回一个 Promise 对象               ,可以使用 then 方法添加回调函数

async function helloAsync(){ return "helloAsync"; } console.log(helloAsync()) // Promise {<resolved>: "helloAsync"} helloAsync().then(v=>{ console.log(v); // helloAsync })

async 函数中可能会有 await 表达式,async 函数执行时                      ,如果遇到 await                       ,那么await标记的表达式会先执行一遍,将await后面的代码加入到微任务中               ,然后就会跳出整个async函数来执行后面的代码        。

await 关键字仅在 async function 中有效

function testAwait(){ return new Promise((resolve) => { setTimeout(function(){ console.log("testAwait"); resolve(); }, 1000); }); } async function helloAsync(){ await testAwait(); console.log("helloAsync"); } helloAsync(); // testAwait // helloAsync 练习题 const promise = new Promise((resolve, reject) => { console.log(1); resolve(); console.log(2); reject(error); }) promise.then(() => { console.log(3); }).catch(e => console.log(e)) console.log(4); const promise = new Promise((resolve, reject) => { setTimeout(() => { console.log(once) resolve(success) }, 1000) }) promise.then((res) => { console.log(res) }) promise.then((res) => { console.log(res) }) const p1 = () => (new Promise((resolve, reject) => { console.log(1); let p2 = new Promise((resolve, reject) => { console.log(2); const timeOut1 = setTimeout(() => { console.log(3); resolve(4); }, 0) resolve(5); }); resolve(6); p2.then((arg) => { console.log(arg); }); })); const timeOut2 = setTimeout(() => { console.log(8); const p3 = new Promise(reject => { reject(9); }).then(res => { console.log(res) }) }, 0) p1().then((arg) => { console.log(arg); }); console.log(10); async function async1() { console.log(1) await async2() console.log(2) } async function async2() { console.log(3) } console.log(4) setTimeout(() => { console.log(5) }, 0); async1() new Promise(resolve => { console.log(6) resolve() }) .then(() => { console.log(7) }) console.log(8)

创心域SEO版权声明:以上内容作者已申请原创保护,未经允许不得转载,侵权必究!授权事宜、对本内容有异议或投诉,敬请联系网站管理员,我们将尽快回复您,谢谢合作!

展开全文READ MORE
函数调用语句举例(函数调用过程中对象优化)