我会在这里记录一下我最近学习的HTML&CSS&JS的基础知识,以及使用VScode能经常用到的快捷键,笔记内容有极少部分粘贴于其他博主的整理。其中JS进阶课程来自于b站,链接如下:
【【Udemy排名第一的JavaScript课程】2023最新完整JavaScript课程 从入门到精通 -- 通过项目、挑战和理论掌握JS(中英文字幕)下】 https://www.bilibili.com/video/BV15S4y1N7Mu/?share_source=copy_web&vd_source=ddc00a8c8fe74fa87c6567446a0a1b9d
VScode创建html文件时可以使用“!”来加载默认语句
Ctrl+k后按Ctrl+c可以多行选中注释
Ctrl+X删除单行
alt+shift+f格式化
Ctrl+B关闭左侧边栏
Ctrl+Shift+P快捷打开命令行
可以使用open in default browser在默认浏览器中打开当前页面
使用open with live server可以实时显示页面的修改
Child: > 例如:nav>ul>li,会快捷创建子标签
Item numbering: $ 例如:ul>li.item$*5,会自动在ul下创建五个li并且为每个li创建id选择器,名称分别为item1-item5
#header: 会创建一个div带有id选择器名为header
.title: 会创建一个div带有class选择器名为title
{Text}: 标签中的内容
头部
主体部分,只有一个
文章
表示一个独立的区块,如果上面的标签不能用 就用section
没有语义,就用来表示一个区块,目前div是主要的布局元素
行内元素,没有任何的语义,一般用于在网页中选中文字
一级标题
二级标题
一个段落
补充块元素的定义,其中html元素分为行内元素、块元素和行内块元素。
常见的块级元素:< h1 >~< h6 >、< p >、< div >、< ul >、< li >等,其中 < div > 标签是最典型的块元素。
块元素的特点:① 比较霸道,自己独占一行。② 高度,宽度、外边距以及内边距都可以控制。③ 宽度默认是容器(父级宽度)的100%。④ 是一个容器及盒子,里面可以放行内或者块级元素。注意:文字类的元素内不能使用块级元素例如:< p > 标签主要用于存放文字,因此 < p > 里面不能放块级元素,特别是不能放< div >。同理, < h1 >~< h6 >等都是文字类块级标签,里面也不能放其他块级元素
常见的行内元素: < a >、< strong >、< i >、< span >、< img />、< input />、< select >、< textarea >、< br />、等,其中 < span > 标签是最典型的行内元素。有的地方也将行内元素称为内联元素。行内元素的特点:① 相邻行内元素在一行上,一行可以显示多个。② 高、宽直接设置是无效的。③ 默认宽度就是它本身内容的宽度。④ 行内元素只能容纳文本或其他行内元素。注意:链接里面不能再放链接。特殊情况链接 < a > 里面可以放块级元素,但是给 < a > 转换一下块级模式最安全。
在行内元素中有几个特殊的标签 —— < img />、< input />,它们同时具有块元素和行内元素的特点。 有些资料称它们为行内块元素。行内块元素的特点:① 和相邻行内元素(行内块)在一行上,但是他们之间会有空白缝隙。一行可以显示多个(行内元素特点)。② 默认宽度就是它本身内容的宽度(行内元素特点)。③ 高度,行高、外边距以及内边距都可以控制(块级元素特点)
1.无序列表(unorder list):使用ul标签来创建,li表示列表项
- 结构
- 表现
- 行为
2.有序列表(order list):使用ol标签来创建有序列表,li表示列表项
- 结构
- 表现
- 行为
3.定义列表:dl标签,dt表示定义的内容,dd对内容进行解释说明
- 结构
- 结构表示网页的结构,结构用来规定网页中哪里是标题,哪里是段落
列表之间可以互相嵌套
- 嵌套第一层
- 嵌套第二层
- 嵌套第三层
meta
空格
>大于号
<小于号
©版权符号
在head内通过link引入其他css文件(最灵活,经常使用)
在CSS内引入CSS
@importurl(test.css)
优先级高的方式(指定的越确切,优先级越高)
优先级最高的方式(加important,谨慎使用!)
p{
color: green!important;
}
//index.html
h1
h2
index.css
h1,h2{
color: gray;
background: black;
}
h1{
border: 3px solid green;
}
h2{
border: 2px solid red;
}
在index.css文件中,类选择器符号为”.”,ID选择器符号为”#”
同时存在属性的可以通过“.red.bold{}”在CSS内实现,但是.red和.bold中间不能存在空格
用属性作为属性选择器的依据(”*=”包含内容即可,”^=”以该内容开始,”$=”以该内容结束)
a
b
c
相邻选择器只会从上往下选择,符号为(+);通用选择器符号为(~)
a
b
c
测试
/* 伪类选择器 link表示没有访问过的 visited表示访问过的 */
a:link{
color: blue;
}
a:visited{
color: gray;
}
/* 悬停在按钮上的反馈 */
button:hover,
a:hover{
background: #fff000;
}
/* active是激活时的反馈 */
button:active,
a:active{
background: black;
}
/* 被选中时(聚焦在输入框时) */
input:focus{
outline:none;
background: #aaaaaaaa;
}
忘记密码请点击这里
Hello world
1
2
3
p:first-letter{
font-size: 50px;
}
.help:before{
content:"*";
color: red;
}
.help:after{
content: "[?]";
color: blue;
}
div p:first-child{
color:red;
}
div p:last-child{
color:darkred;
}
/* 第二个孩子 nth-child(2) */
div p:nth-child(2){
color:darkgoldenrod;
}
font-family 字体类型font-weigth 字重font-size 字体大小
text-align:left right center justify(向两端对齐,但是最后一行不会) line-height: 行高text-decoration: 文字装饰
div{
background: #000000;
width: 100px;
height: 100px;
padding: 20px;
border: 5px solid #777;
max-resolution: 20px;
}
JAVASCRIPT is a high-level(高等级的), object-oriented(面向对象), muti-paradigm(多范式的) programming language.
程序编程语言PROGRAMMING LANGUAGE: BUILDING WEB APPLICATIONS.
编译型语言(c、c++、java):通篇先编译出一个文件,程序会自动执行这个文件。
解释型语言:编译一句执行一句,没有编译文件,相当于直接编译成1010机器语言,然后执行。
JS曾经是解释型语言,现在是及时编译(Just-in-time),提前编译,编译后立即执行。
JS代码转化为AST(抽象语法树),编译时将AST转换为二进制代码(0和1),因为JS是及时编译型语言,二进制机器代码会被立刻执行,这段机器代码会不断地在执行过程中被优化(Optimization),在这一整个的过程中,我们无法用代码去访问。
JS在浏览器中运行的时候,可以把浏览器看成一个盒子,里面装有JS ENGINE、WEB APIs、CALLBACK QUEUE(回调队列),若使用node.js执行js文件则不存在WEB APIs,无法使用dom方法。在发生事件时,回调函数会进入CALL STACK(调用堆栈:按调用顺序保存所有在运行期被调用的方法)执行,执行后从顶部出栈(执行完毕一个出栈一个)。
文档对象模型(Document Object Model)简称 DOM ,它提供了一套用于表示和操作 HTML 和 XML 文档内容的接口(API)。(或者可以说是JS和浏览器之间的接口)
DOM 描绘了一个层次化的节点树,允许开发人员通过添加节点、删除节点或修改该节点来更新文档页面内容。其中document对象是该节点树的其中一个根节点。
#DOM的运行方式
没有 defer 或 async浏览器会立即加载并执行指定的脚本,“立即”指的是在渲染该 script 标签之下的文档元素之前,也就是说不等待后续载入的文档元素,读到就加载并执行。
如果一个script加了defer属性,即使放在head里面,它也会在html页面解析完毕之后再去执行,也就是类似于把这个script放在了页面底部。虽然是异步加载,但是不会阻塞dom元素的解析,并且严格按照书写顺序执行!(常用)
对于async,这个是html5中新增的属性,它的作用是能够异步的加载和执行脚本,一旦加载到就会立刻执行。虽然是异步加载,会阻塞dom元素的解析,并且执行顺序是无序的,谁先加载完谁先执行!有可能在DOMContentLoaded事件之前执行,也可能在DOMContentLoaded事件之后执行,但是一定在onload事件之前执行
在JS中所有的可以由我们自主命名的都可以是标识符
例如:变量名、函数名、属性名都属于标识符
命名一个标识符时需要遵守如下的规则:
标识符中可以含有字母、数字、$
标识符不能以数字开头
标识符不能是ES中的关键字或保留字
标识符一般都采用驼峰命名法(首字母小写,每个单词的开头字母大写,其余字母小写,例如helloWorld)
JS底层保存标识符时实际上是采用的Unicod编码,所以只要存在utf-8内的都可以使用(但是不要用!)
7种原始数据类型:Number、String、Boolean、Undefined、Null、Symbol(ES2015)、Bigint(ES2020)
其中String要用引号引起来,单引号或双引号皆可,嵌套需要用转义字符“\”
Null类型的值只有一个,就是null
null这个值专门用来表示一个为空的对象
使用typeof检查一个null值时,会返回object
Undefined类型的值只有一个,就是undefined
当声明一个变量,但是并不给变量赋值时,它的值就是undefined
使用typeof检查一个undefined的值时,会返回undefined
BigInt
有一些很大的数字在js中无法显示出,所以要使用到BigInt。
形式可以在大数的后面加n:2564689765456n 或者 BigInt(2564689765456)
BigInt不能和其他普通数字做运算。想做运算需要把另一个数字也转换为BigInt类型的。
其中原始数据类型储存在调用堆栈,引用数据类型存储在HEAP(堆)里。
原始数据类型在改变值的时候会在调用堆栈内创建一个新的地址来存值,而引用数据类型只会修改在堆里面的值,地址不会发生变化。
const不能只声明变量而不为它赋值。
var是在ES6之前定义变量的旧方法,可以重复声明,在声明前使用会得到undefined,函数作用域。
目前多使用于let,在声明前使用会报错,不可以重复声明,块作用域。
ES6引入了模板字面量(Template Literals),对多行字符串和字符串占位符的操作进行了增强。
const myName = '王君博';
const myAge = 23;
const myIntroduction = '我是' + myName + ',今年' +myAge + '岁了。';
console.log(myIntroduction);
const myIntroductionNew = `我是${myName},今年${myAge}岁了。`;
console.log(myIntroductionNew);
上面的代码就是使用ES6字符串占位符的机制,提供了简单的字符串插值功能,直接在输出的字符串中使用${NAME}占位符语法,其中花括号{}里面的NAME可以是变量、JS表达式和函数。特别需要注意的是:字符串用的是反引号,而不是单引号或者双引号。
需要注意的是:模板字符串中所有的空格、新行、缩进,都会原样的输出在生成的字符串中。
const str1 = 'my name is \n\
wangjunbo';
const str2 = `my name is
wangjunbo`;
强制类型转换是指将一个数据类型强制转换为其他的数据类型。
//将其他的数据类型转换为String
/*
* 方式一:
* - 调用被转换数据类型的toString()方法
* - 该方法不会影响到原变量,它会将转换的结果返回
* - 但是注意:null和undefined这两个值没有toString()方法
* 如果调用他们的方法会报错
* 方式二:
* - 调用String()函数,并将被转换的数据作为参数传递给函数
* - 使用String()函数做强制类型转换时,对于Number和Boolean实际上调用的toString()方法
* 但是对于null和undefined就不会调用toString()方法,它会将null直接转换为"null"
* 将undefined直接转换为"undefined"
*/
let a = 123;
//调用a的toString()方法
a = a.toString();
console.log(a);
console.log(typeof a);
//调用String()函数
let b = 123;
b = String(b);
console.log(typeof b);
console.log(b);
/*
* 将其他的数据类型转换为Number
* 转换方式一:
* 使用Number()函数
* - 字符串—>数字
* 1.如果是纯数字的字符串,则直接将其转换为数字
* 2.如果字符串中有非数字的内容,则转换为NaN
* 3.如果字符是一个空串或者是一个全是空格的字符串,则转换为0
* - 布尔—>数字
* true 转成 1
* false 转成 0
* - Null —>数字 0
* - Undefined —>数字 NaN
* 转换方式二:
* 这种方式专门对付字符串(如果对非String使用parseInt()和parseFloat(),它会先将其转换为 String然后在操作)
* - parseInt() 把一个字符串转换为一个整数
* - parseFloat() 把字符串转换为浮点数
*/
//方式一
let a = "123";
a = Number(a);
console.log(a);
console.log(typeof a);
//方式二
a = "123px";
a = parseInt(a);//可以将一个字符串中的有效整数内容取出来(从左往右,直到碰到非整数后面全都舍弃)
console.log(a);
console.log(typeof a);
a="123.456px";
a = parseFloat(a);//可以取出有效的小数部分
console.log(a);
console.log(typeof a);
使用Boolean()函数
数字转布尔值时,除了0和NaN其余的都是true
字符串转布尔值时,除了空串其余的都是true
null和undefined都会转换为false
对象也会转换为true
所以,0, "", undefined, null, NaN这些值在做布尔运算时会被转换为false。
当使用==进行比较两个值时,如果两个值的类型不同则会自动进行类型转换,将其转换为相同的类型然后在进行比较。
如果使用===进行比较时,两个值的数据类型也必须是一样的,否则会返回false。
例如"18" == 18返回true,但是"18" === 18返回false。
console.log(undefined == null); //undefined衍生自null,所以判断时会返回true
console.log(undefined === null); //相等 但是不全等,返回false
非(!)可以为一个任意数据类型取两次反,将其转换为boolean类型
与(&&)
或(||)
非布尔值的情况下的&&和||
与(&&)如果两个值中有false,则返回靠前的false;如果第一个值为true,则直接返回第二个值。(找假值)
或(||)如果第一个值为true,则直接返回第一个值;如果第一个值为false,则直接返回第二个值。(找真值)
const a = '' || undefined || 12450;
console.log(a); //输出12450
const b = 12 && '450' && undefined;
console.log(b); //输出undefined
条件表达式?语句1:语句2
条件运算符在执行时,首先对表达式进行求值,如果为true,执行语句1并返回结果;否则执行语句2
//1.对数组使用
const arr = [7, 8, 9];
const newArr = [1, 2, ...arr];
console.log(newArr); //输出[1,2,7,8,9]
//2.对字符串使用
const str = 'kingflyz';
console.log([...str]); //输出['k', 'i', 'n', 'g', 'f', 'l', 'y', 'z']
//3.REST
const [a,b,...others] = [1,2,3,4,5];
console.log(others); //输出[3,4,5]
//4.使用扩展运算符解构函数的参数
const add = function (...numbers) {
let sum = 0;
for (let i = 0; i < numbers.length; i++) sum += numbers[i];
console.log(sum);
};
add(5, 4, 3, 2, 1);//输出15
const x = [23,5,7];
add(...x);//输出35
使用??时,前面的变量只要是null或undefined就返回后面的,如果不是就返回前面的。
const x = null ?? 12;
const y = 12 ?? 450;
console.log(x, y); //输出12 12
使用?.时,如果前面的变量不存在就不会继续访问后续变量,前面的变量只要不是null或undefined就继续访问后面的,不是的话就会返回undefined。
const obj = {
name: 'kingflyz',
mytools: {
qq: '342133194',
wechat: 'kyzr2000',
},
speak:function(){
console.log(`im kingflyz`);
},
};
console.log(obj.mytools?.qq); //输出字符串 '342133194'
console.log(obj.mytools?.blog); //输出undefined
console.log(obj.speak?.() ?? '没有这个函数诶'); // ?.同样可以检查一个函数是否存在
// ?.在数组中使用
const arr = [{ name: 'wjb', age: 23 }];
console.log(arr[0]?.name ?? 'not exist');
var num = 3;
//switch语句内将num和case后面的值从上向下比较,一直找到相等的地方
switch(num){
case 1:
console.log("一");
break; //break用来跳出,如果没有break会继续执行下一个case中的内容
case 2:
console.log("二");
break;
default:
console.log("我不知道"); //所有的结果都比较为false后 执行default的
break;
}
注:continue是退出本次循环,while是终止整个循环。
#The for-of Loop
对于数组可以用:数组.entries();
对于对象需要用:Object.entries(对象名称);
const arr = ['wjb', 'kyzr', 'kingflyz'];
for (let name of arr) console.log(name);
//使用arr.entires()时,每次遍历都会得到一个数组,数组index为1的位置记录第几个,2的位置记录名字
for (let name of arr.entries()) console.log(`${name[0] + 1}顺位,${name[1]}`);
//解构
for (let [i, el] of arr.entries()) console.log(`${i + 1}顺位,${el}`);
#forEach
在数组中的使用:
const movements = [200, 450, -400, 3000, -650, -130, 70, 1300];
for (const moment of movements) {
if (moment > 0) {
console.log(`You deposited ${moment}`);
} else {
console.log(`You withdrew ${Math.abs(moment)}`);
}
}
使用forEach高阶函数来实现
console.log(`-----forEach-----`);
//forEach内的函数参数并不唯一,顺序为(movement,index,array),对应着的是forof中对数组使用entries方法。区别在于使用forof时第一个参数为index,使用foreach第二个参数是index。
movements.forEach(moment => {
if (moment > 0) {
console.log(`You deposited ${moment}`);
} else {
console.log(`You withdrew ${Math.abs(moment)}`);
}
});
在Map和Set中的使用:
//在Map和Set中使用forEach
//Map
const currencies = new Map([
['USD', 'United States dollar'],
['EUR', 'Euro'],
['GBP', 'Pound sterling'],
]);
currencies.forEach(function (value, key, map) {
console.log(`${key}:${value}`);
});
//Set
const currenciesUnique = new Set(['USD', 'GBP', 'USD', 'ERU', 'ERU']);
currenciesUnique.forEach(function (value, _, set) {
console.log(`${value}`); //函数的第二个参数在这里没有意义所以用下划线
});
为整个脚本文件开启严格模式,需要在所有语句之前放一个特定语句 "use strict"; (或 'use strict';)
严格模式禁用了未来版本中可能会定义的一些关键字、语法。
使用函数声明的形式创建的function 函数(){},它会在所有代码执行之前就被创建(函数的声明提前)。
const birthYear = 2000;
//函数的声明式
function myAge(nowYear){
return nowYear - birthYear;
}
console.log(`我的年龄是${myAge(2023)}岁`);
//函数的表达式
const myAge2 = function(nowYear){
return nowYear - birthYear;
}
console.log(`我的年龄是${myAge2(2023)}岁`);
删掉function关键字加上=>
没有参数加括号
一个参数可以选择不加()
多个参数必须加(),并且参数之间用逗号分割。
箭头函数无法使用this keyword和arguments object(函数的参数)
//Arrow Function
//1.简短的一行带有返回值的可以省略掉return
const myAge1 = myBirthYear => 2023-myBirthYear;
console.log(myAge1(2000));
//2.多个参数需要加括号
const myAge2 = (myBirthYear,myName) => `我叫${myName},出生于${myBirthYear}年`;
console.log(myAge2(2000,"王君博"));
//3.无参写作 () => {}
const myAge3 = () => {
console.log(`你好,我是2000年出生的!`);
}
myAge3();
创建数组的两种方法:
const ages1 = ["10","15","20"];
const ages2 = new Array(20,30,40);
数组测增删操作:
push("XXX"):在数组末尾加数据,返回值是增加数据后数组的长度。
unshift("XXX"):在数组开头加数据,返回值是增加数据后数组的长度。
pop():在数组末尾删除数据,返回值是被删除掉的数据。
shift():在数组开头删除数据,返回值是被删除掉的数据。
indexOf("XXX"):返回值是XXX在数组中的位置(0~data.length-1),不存在返回-1。
includes("XXX"):返回值是boolean类型,用于查询数组中是否存在XXX数据,查询过程严格不会自动进行强制类型转换。
slice(xxx):将数组对象切割,但是原始数组不发生改变。当xxx为-1的时候返回只包含最后一个元素的数组,该方法和字符串的slice方法类似。slice(开始参数,结束参数):可以看成前闭后开区间。
splice(xxx):将数组对象切割,返回切割后的对象,但是原始数组发生改变,原始数组会丢失切割掉的部分。一般很少用来切割,而是用来删除数组中的元素。splice(开始参数,元素个数):包括开始参数,找对应个数的进行切割。
reverse():将数组的元素顺序反转。
arr1.concat(arr2):数组arr1和数组arr2拼接成一个数组。等同于[...arr1,...arr2]。
arr.join('xxx'):在数组的每两个元素中间加上字符串xxx,并且返回一个新的字符串。
arr.at(xxx):访问数组arr在xxx位置(可以是-1或-2等,即倒数第一个元素或倒数第二个元素)的元素,如arr.at(0)等同于arr[0]。该方法也同样适用于字符串。
const arr = [13,22,45];
//获取数组的最后一个元素
console.log(arr[arr.length-1]);
console.log(arr.slice(-1)[0]);
console.log(arr.at(-1));
arr.flat():可以将多维嵌套数组展开一层嵌套,更深层次的嵌套不行,注意只能展开一层。可以设置参数选择展开几层的嵌套。
const arr = [[1, 2, 3], 4, [5, 6, 7], 8];
console.log(arr.flat()); //输出[1, 2, 3, 4, 5, 6, 7, 8]
const arrDeep = [[1, [2, 3]], 4, [5, [6, 7]], 8];
console.log(arrDeep.flat()); //输出[1, Array(2), 4, 5, Array(2), 8]
console.log(arrDeep.flat(2)); //输出[1, 2, 3, 4, 5, 6, 7, 8]
arr.sort():对数组进行排序,默认排序是字符串a-z,数字的话会自动转换成字符串的形式,有“—”的放到前面,然后再看该数的开头数字从0-9排列。
同时sort()内可以添加回调函数,设置排序的方式。
const movements = [200, 450, -400, 3000, -650, -130, 70, 1300];
//return < 0, A,B(keep order)
//return > 0, A,B(switch order)
//其中a和b是数组movements中相邻的第一个和第二个元素
movements.sort((a, b) => a - b); //升序排列
console.log(movements); //输出[-650, -400, -130, 70, 200, 450, 1300, 3000]
arr.fill(xxx,a,b):使用xxx填充数组,也可设置两个参数,第一个参数是填充的内容,第二个参数是开始的索引,第三个参数是结束的索引,同样可以用前闭后开区间来表示。
Array.from({length:xxx},()=>{}):创建一个长度为length的新数组,并使用括号内的回调函数。
const arr = Array.from({ length: 5 }, (_, i) => i + 1);
console.log(arr); //输出Array(5) [1,2,3,4,5]
对象(引用数据类型)
对象的分类:
内建对象:由ES标准中定义的对象,在任何的ES的实现中都可以使用(例如:Math、String、Function)
宿主对象:由JS的运行环境提供的对象,目前来讲主要指由浏览器提供的对象(例如:BOM、DOM)
自定义对象:由开发人员自己创建的对象
//1.创建对象
let obj = new Object();
obj.name = "wjb";
obj.age = 23;
//2.创建对象
let obj = {
name:"wjb",
age:23
}
//调用对象的属性
console.log(obj.name);
console.log(obj['name']);
1.Math.random()方法返回大于等于 0 小于 1 的一个随机数。
在连续整数中取得一个随机数:
值 = Math.floor(Math.random() * 可能值的总数 + 第一个可能的值)例:产生1-20的随机数
//生成一个1-20之间的随机整数,可以用floor或者trunc
const num = Math.floor(Math.random() * 20 + 1);
//求min-max中的随机数 0…1 -> 0…(max-min) ->min…max
const randomInt = (min, max) => Math.trunc(Math.random() * (max - min)) + min;
2.Math.abs(xxx)求xxx的绝对值。
3.Math.sqrt()求平方根。
4.25** 1/2是25的平方根;8**1/3是8的立方根。
5.Math.max()求多个数字中的最大值。
6.Math.min()求多个数字中的最小值。
7.Math.PI是圆周率。
8.Math.ceil()返回大于等于给定数字的整数;Math.trunc()直接取整数部分;Math.round()四舍五入;Math.floor()返回小于等于给定数字的整数。
typeof(xxx)可以查看一个变量的数据类型,但在定义数据类型的时候只需用let、var、const
Object.keys(XXX):可以查询对象XXX的键名,会返回一个数组。
const message = document.createElement('div'):创建一个新的div标签。
message.remove():删除这个创建的message标签。
document.querySelector("XXX"):作用类似于document.getElementsByClassName和document.getElementById能够获取以XXX为ID名或类名的html语句。
document.querySelectorAll("XXX"):获取多个相同类名的html语句。
document.querySelector("XXX").toggle("classname"):如果存在classname就删除,如果没有就添加classname类选择器。
document.querySelector("XXX").classList.add("classname"):添加XXX为ID名或类名html语句中的classname类选择器,多用于弹窗关闭。
document.querySelector("XXX").classList.remove("classname"):移除XXX为ID名或类名html语句中的classname类选择器,多用于弹窗显示。
document.querySelector("XXX").classList.contains("classname"):查询是否包含classname为名称的类选择器,返回一个boolean属性的值。
textContent和innerHTML的区别:textContent多用于修改内部文本内容,innerHTML可以在标签里加标签之类的。
document.querySelector("XXX").getBoundingClientRect():表示了当前盒子在浏览器中的位置以及自身占据的空间的大小,除了 width 和 height 之外,其他的属性是相对于视图窗口的左上角 来计算的。
document.querySelector("XXX").addEventListener("click",function (){}):给XXX为ID名或类名的html元素添加一个点击时的监听器,执行function()函数体内的命令。
其中除了"click"事件外还具有许多事件,例如"keydown"代表按下键盘,“mouseenter”代表鼠标移动到该区域时触发事件,“mouseover”和“mouseenter”有些类似,“mouseover”事件具有冒泡的性质(冒泡是指会影响到他的父元素),"mouseout"代表鼠标离开所选区域,"scroll"代表鼠标滚动,“load“代表加载,”beforeunload”是关闭页面或者刷新页面时的事件,可以用该事件添加弹窗提示
document.addEventListener("keydown",function (e){})
document.addEventListener('keydown', function (e) {
e.preventDefault();//防止默认事件
//其中函数的形参e存储的是键盘按下的具体属性, e.key是按键的具体名称
console.log(e.key);
//可以通过e.currentTarget访问当前目标元素
});
doucument.querySelector('h1').addEventListener('mouseenter',function(e){
alert('you are reading the heading! :D')
})
document.querySelector("XXX").prepend(message):在xxx容器最上面插入message
document.querySelector("XXX").append(message):在xxx容器最下面插入message
document.querySelector("XXX").insertAdjacentHTML("afterbegin",htmlText):在XXX容器内插入一段html代码,其中afterbegin是在该段代码开始时插入。
foo
section1.scrollIntoView({behavior:'smooth'}):平滑滚动到section1所在区域
#DOM Traversing
h1.childNodes:h1的所有子节点
h1.children:h1的直系子节点
h1.parentNode:h1的直系父节点
h1.firstElementChild:h1的第一个子节点
h1.closest('.header'):选择离h1最近的.header,首先检查当前元素是否匹配,如果匹配则直接返回当前元素本身;如果不匹配则沿着dom树一层一层向上查找祖先元素,直到找到匹配的祖先元素为止;如果都不不匹配则返回空null。
h1.parent.children:可以得到所有的兄弟节点
作用域(Scope)是代码中声明变量的地方。Scope分为global scope(全局作用域)、function scope(函数作用域)、 block scope(块作用域)
其中函数、var存在于函数作用域,而const、let存在于块作用域,const、let相比于ES5内的var来说更加安全,不易造成泄露。
Scope Chain(作用域链)能够清晰看出每一个作用域能否访问其他作用域的变量。而且作用域链只能向上工作,不能向下工作。
Scope Chain和Call Stack之间的联系:作用域链和函数调用的顺序无关,不影响作用域链。
var会声明提升,let和const并不会。
使用函数声明的形式创建的function 函数(){},它会在所有代码执行之前就被创建。
使用var声明的函数表达式或箭头函数,只会使得声明提前,输出只显示为undefined。
TDZ:Temporal Dead Zone,因为let和const的声明不会提前,但是代码运行过程中会检测到变量还未初始化,在非法调用时刻和后续的初始化时刻,中间这一段区域就被称之为TDZ。
this在方法中指向调用该方法的对象。
在严格模式下,常规函数调用(function call)的this是undefined,非严格模式会是window。
箭头函数的this指向父函数或父范围。
arguments:调用arguments以访问函数的参数,第一个参数为arguments[0],第二个参数为arguments[1]……
但是arguments只存在常规函数中,不适用于箭头函数。
浅拷贝只会复制对象的属性。
方法:Object.assign({} , object)用于将所有可枚举属性的值从一个或多个源对象复制到目标对象。它将返回目标对象 。
//浅拷贝案例1
var obj1 = { name: "zhangsan", age: 20 };// 源对象 1
var obj2 = { group: 3, id: 2 };
var obj = Obejct.assign({},obj1,obj2); // 第一个参数是目标对象。后面的全是源对象,执行完之后返回目标对象。
console.log(obj);
//浅拷贝案例2
const mainMenuCopy = [...restaurant.mainMenu];//用扩展运算符浅拷贝
//浅拷贝案例3
const mainMenuCopy = restaurant.mainMenu.slice();//用slice方法进行浅拷贝
深拷贝可以复制对象的所有内容。
Destructuring(分解/解构)是分解复杂的数据结构成一个较小的数据结构(如变量)。
在解构的过程中可以用到扩展运算符(...),详细看8.④
//1.简单的解构方法
const arr = [2, 3, 4];
const [x, y, z] = arr;
console.log(x, y, z); //输出时x=2,y=3,z=4
//2.如何解构对象内的数组
const restaurant = {
categories: ['Italian', 'Pizzeria', 'Vegetarian', 'Organic'],
};
const [first, , second] = restaurant.categories;
console.log(first, second); //输出'Italian', 'Vegetarian'
//3.用数组的解构可以实现数据交换
[second, first] = [first, second];
console.log(first, second); //输出'Vegetarian', 'Italian'
//4.解构嵌套数组
const nested = [2, 4, [5, 6]];
const [i, , [j, k]] = nested;
console.log(i, j, k);//输出时i=2,j=5,k=6
//5.默认值
const [p, q, r] = [8, 9];
console.log(p, q, r);//输出时p=8,q=9,r=undefined
//const [p, q, r = 1] = [8, 9];
//console.log(p, q, r);//输出时p=8,q=9,r=1
const restaurant = {
name: 'Classico Italiano',
location: 'Via Angelo Tavanti 23, Firenze, Italy',
categories: ['Italian', 'Pizzeria', 'Vegetarian', 'Organic'],
starterMenu: ['Focaccia', 'Bruschetta', 'Garlic Bread', 'Caprese Salad'],
mainMenu: ['Pizza', 'Pasta', 'Risotto'],
openingHours: {
thu: {
open: 12,
close: 22,
},
fri: {
open: 11,
close: 23,
},
sat: {
open: 0, // Open 24 hours
close: 24,
},
},
};
//1.解构常规对象,新的变量名和对象中的key名相同
const { name, openingHours, categories } = restaurant;
console.log(name, openingHours, categories);//输出的内容和对象里的属性一样
//2.为解构对象设置新的变量名 (原名:新变量名)
const {
name: restaurantName,
openingHours: hours,
categories: tags,
} = restaurant;
console.log(restaurantName, hours, tags);
//3.默认值
const { menu, starterMenu: starters } = restaurant;
console.log(menu, starters); //menu输出为undefined
//const { menu = [], starterMenu: starters } = restaurant;
//console.log(menu, starters); //menu输出为[]
//4.Mutating variables(变异变量?网上这么翻译的)
let a = 111;
let b = 222;
const obj = { a: 23, b: 7, c: 14 };
({ a, b } = obj); //不加小括号,会认为{}是一个代码块,不能接等号
//5.嵌套对象
const {
fri: { open, close },
} = openingHours; //这里的openingHours是在步骤1里面解构出来的对象
console.log(open, close);
//6.使用for-of对数组内嵌套对象进行解构
const arr = Object.entries(restaurant.openingHours);
console.log(arr); //对象解构后会得到的形式为[thu,{open:12,close:22}]...
for (const [week, { open, close }] of arr) console.log(`餐馆在${week}开业时间是${open},下班时间是${close}`);
几种常用的方法:
创建一个空的Set集合:const s = new Set();
查看Set集合的size:s.size;
查看xxx元素是否存在Set集合中(返回值true or false):s.has('xxx');
在Set集合中添加元素xxx:s.add('xxx');
在Set集合中删除元素xxx:s.delete('xxx');
删除集合Set中的所有元素:s.clear();
const ordeSet = new Set(['Pasta', 'Pizza', 'Pizza', 'Risotto']);
console.log(ordeSet); //输出Set(3){'Pasta', 'Pizza', 'Risotto'}
const str = new Set('kingflyz');
console.log(str); //输出{'k', 'i', 'n', 'g', 'f', ...}
//用for-of语句可以遍历Set集合:
for(const x of ordeSet ) console.log(x);
//可以将Set集合用扩展运算符...解构成数组
const arr = [...orderSet];
几种常用的方法:
创建一个空的Map集合:const m = new Map();
为集合Map传入参数:m.set('name','kingflyz');
获取name为'xxx'对应的值:m.get('xxx');
删除name为'xxx'对应的值:m.delete('xxx');
查看Map集合的size:m.size;
删除集合Map中的所有元素:m.clear();
Map集合中的所有key(返回的是一个{}中的对象而不是数组,转成数组需要用到扩展运算符):m.keys();
Map集合中的所有value(返回的是一个{}中的对象而不是数组,转成数组需要用到扩展运算符):m.values();
//1.创建空集合并注入数据
const m = new Map();
m.set('name', 'kingflyz');
m.set(1, 'yzj');
m.set(2, 'wht');
console.log(m); //输出Map(3) {'name' => 'kingflyz', 1 => 'yzj', 2 => 'wht'}
//2.直接创建含有数据的集合
const question = new Map([
['question', 'what is the best programming language in the world?'],
[1, 'c'],
[2, 'java'],
[3, 'javascript'],
[true, 'Correct'],
[false, 'Try again!'],
]);
常用的几种方法(str为字符串):
str.indexOf('r');查询字母r在str字符串中首次出现的位置。(index:0~str.length-1)
str.lastIndexOf('r');查询字母r在str字符串中最后一次出现的位置。
str.slice(4);将str字符串分离,返回的新字符串第一个字母从index为4的地方开始。例如:'kingflyz'.slice(4);//返回的是flyz
str.slice(4,7);用区间表示就是[4,7),左闭右开。例如:'kingflyz'.slice(4,7);//返回的是fly
str.toLowerCase();小写
str.toUpperCase();大写
str.trim();去除字符串的首位空格
str.replace('xxx','aaa');把字符串中的第一个xxx替换为aaa
str.replaceAll('xxx','aaa');把字符串中的所有xxx替换为aaa
str.include('xxx');返回Boolean值,查看数组是否含有xxx
str.startsWith('xxx');同样返回Boolean值,查看数组是否以xxx开头
str.endsWith('xxx');同样返回Boolean值,查看数组是否以xxx结尾
str.split('+');以加号为分隔符把字符串拆分成数组,返回一个新数组
str.repeat(6);重复str6次
str.padStart(25,'+');字符串str前面添加+,添加后新字符串的长度为25
str.padEnd(25,'+');字符串str后面添加+,添加后新字符串的长度为25
函数的类型是Object,函数也是作为值来传递的。
高阶函数:可以接收其他函数作为参数,并且可以返回一个新的函数。
const greet = function (greeting) {
return function (name) {
console.log(`${greeting}${name}`);
};
};
//greet('hey!')('kingflyz');
const greeter = greet('hey!');
greeter('kingflyz'); //输出 hey!kingflyz
call()可以手动改变函数this的指向,括号中的第一个参数为this的指向对象。
const book = lufthansa.book; //将对象的方法重新赋给book
//这时候如果执行 book(23,'kingflyz');会报错,因为book方法中含有this,代码运行的时候不知道this指向了谁
//使用call();可以手动将book()指向对象a
book.call(a, 23, 'kingflyz');
apply()和call()使用方法类似,只不过第二个参数传入的是一个数组,相比于apply(),现代ES6更优先使用call()
const flightData = [58, 'kyzr2000'];
book.apply(a, flightData);
//book.call(a, ...flightData);
除了这两个函数之外还存在着一个bind(),bind可以先绑定一个对象然后进行调用,这会使this绑定到该对象上。
const book = lufthansa.book; //将对象的方法重新赋给book
//使用bind()可以手动将book()绑定对象a
const bookA = book.bind(a);
bookA(58,'kyzr2000');//绑定后即可直接调用该函数
const addTax = (rate, value) => value + value * rate;
const addVAT = addTax.bind(null, 0.23); //这个null代表没绑定任何对象,0.23是函数的第一个参数rate的绑定值
console.log(addVAT(100)); //这个100是函数的第二个参数valeu,最后结果输出123
一个函数即使在执行环境消失后,也总是可以访问变量环境去创建它的执行上下文,这种联系称之为闭包。
通俗点说闭包就是函数返回函数,并且返回的子函数永远可以访问父函数里面的变量。
闭包会自动收集依赖,函数会记录它使用的父函数的变量。
使用console.dir(booker);可以看到在booker函数里面存放着来自secureBooking的内内部属性——闭包passengerCount
#Map:最后的返回值是一个数组
方法flatMap()是map()和flat()的结合,map()执行后会将得到的嵌套数组用flat()展开。
const eurToUsd = 1.1;
const movements = [200, 450, -400, 3000, -650, -130, 70, 1300];
const movementsUSD = movements.map((mov, i) => `第${i + 1}个${mov * eurToUsd}`);
console.log(movementsUSD);
#Filter:最后的返回值是一个新的数组。
filter调用的函数会返回true or false,若为true则记录在新的数组里。
const movements = [200, 450, -400, 3000, -650, -130, 70, 1300];
const deposits = movements.filter(function (mov) {
return mov > 0;
});
console.log(deposits); //输出(5) [200, 450, 3000, 70, 1300]
const withdrawals = movements.filter(function (mov) {
return mov < 0;
});
console.log(withdrawals); //输出(3) [-400, -650, -130]
#Find:最后的返回值是单个值,不是数组。
和filter相似的有一个find方法,但是find方法不像filter那样会返回所有符合条件的值进入数组,它只会返回找到的第一个值,而不是返回一个数组。
#FindIndex::最后返回的是索引
与find非常相似的方法,不过返回的只是找到元素在数组中位置的索引。
#Reduce :最后的返回值是一个数字。
reduce(function(...),num);其中num是最开始累加的数字
reduce的参数和filter、map不太一样。其中reduce(function(第一个参数是Accumulator累加器(比作雪球),第二个参数是当前对象,第三个参数是索引...),num)
const movements = [200, 450, -400, 3000, -650, -130, 70, 1300];
const balance = movements.reduce(function (acc, mov) {
return acc + mov;
}, 0);
console.log(balance); //输出3840 即所有数组内数字的和
#Some:
some的用法接近于include,可以查看一个数组中是否包含符合条件的元素存在,而include只能查看数组中是否存在指定的数字。
const movements = [200, 450, -400, 3000, -650, -130, 70, 1300];
console.log(movements.some(mov => mov > 200)); //返回true
#Every:
相比于some,every会检查一个数组中所有的元素是否符合指定条件,如果都符合才会返回true,不然的话就会返回false。
const movements = [200, 450, -400, 3000, -650, -130, 70, 1300];
console.log(movements.every(mov => mov > 200)); //返回false,只有当movements中所有元素都大于200的时候才会返回一个true
const now = new Date();
console.log(now); //1970.1.1过1000毫秒
console.log(now.getFullYear());
console.log(now.getMonth()); //是从0开始计算的 所以需要+1才是真实的月份
console.log(now.getDate()); //0-6:0是星期日
console.log(now.getDay());
console.log(now.getHours());
console.log(now.getMinutes());
console.log(now.getSeconds());
#时间戳
//时间戳
console.log(new Date(1000)); //1970.1.1过1000毫秒
console.log(now.getTime()); //会得到当前时间距离1970.1.1的毫秒数
console.log(new Date(1678344137083)); //同样可以根据getTime获得的时间戳新建一个时间
//获取时间戳
console.log(+new Date()); //通过转换为number的形式可以将一个date转换为时间戳
new Date(),toISOString():能够将当前时间进行iso格式化。
//根据时间戳计算两个日期的间隔
const calDate = (date1, date2) =>
(date2 - date1) / Math.abs(1000 * 60 * 60 * 24);
console.log(calDate(new Date(2023, 3, 9), new Date(2023, 3, 19))); //输出10
#使用Internationalizing Dates
const now = new Date();
console.log(new Intl.DateTimeFormat('en-GB').format(now));
setTimeout(function () {
console.log(`过一秒显示`);
}, 1000);
setInterval(function () {
console.log(`每秒都会一直显示我${new Date()}`);
}, 1000);
// 创建实例
const io = new IntersectionObserver(callback, option)
IntersectionObserver 是浏览器原生提供的构造函数,接受两个参数:callback 是可见性变化时的回调函数,option 是配置对象(该参数可选)。构造函数的返回值是一个观察器实例。实例的observe方法可以指定观察哪个 DOM 节点。
// 开始观察
io.observe(document.querySelector('#special')
// 停止观察
io.unobserve(element)
// 关闭观察器
io.disconnect()
observe方法的参数是一个 dom 节点,如果需要观察多个对象,则需要多次调用。
io.observe(elementA)
io.observe(elementB)
当观察对象发生变化时,就会触发 callback 函数
const io = new IntersectionObserver((entries) => {
console.log(entries)
})
callback 函数的参数(entries)是一个数组,每个成员都是一个 IntersectionObserverEntry 对象。如果同时有两个被观察的对象的可见性发生变化,entries 数组就会有两个成员。
{
boundingClientRect: { // 目标元素的矩形区域的信息
bottom: 156.4375
height: 21
left: 394
right: 527
top: 135.4375
width: 133
x: 394
y: 135.4375
}
intersectionRatio: 0 // 目标元素的可见比例,即intersectionRect占boundingClientRect的比例,完全可见时为1,完全不可见时小于等于0
intersectionRect: { // 目标元素与视口(或根元素)的交叉区域的信息
// ...
}
isIntersecting: false
isVisible: false // 是否可见
rootBounds: { // 根元素的矩形区域的信息,getBoundingClientRect()方法的返回值,如果没有根元素(即直接相对于视口滚动),则返回null
// ...
}
target: p#special // 被观察的目标元素,是一个 DOM 节点对象
time: 2491 // 可见性发生变化的时间,是一个高精度时间戳,单位为毫秒
}
option: {
threshold:[0.5],
root:element,
rootMargin:'100px'
}
threshold 属性决定了什么时候触发回调函数。它是一个数组,每个成员都是一个门槛值,默认为[0],即交叉比例(intersectionRatio)达到 0 时触发回调函数。(浏览器顶部视口和标签区域重叠大小)
root 属性指定目标元素所在的容器节点(即根元素)rootMargin 属性定义根元素的 margin,用来扩展或缩小 rootBounds 这个矩形的大小,从而影响 intersectionRect 交叉区域的大小。它使用 CSS 的定义方法,比如 10px 20px 30px 40px,表示 top、right、bottom 和 left 四个方向的值。
抽象、封装、继承、多态
//创建一个构造函数
const Person = function (firstName, birthYear) {
this.firstName = firstName;
this.birthYear = birthYear;
};
Person.prototype.calAge = function () {
console.log(2023 - this.birthYear);
};
const kingflyz = new Person('King_FLYz', '2000');
console.log(kingflyz); //输出Person {firstName: 'King_FLYz', birthYear: '2000'}
kingflyz.calAge(); //输出23
class PersonCl {
constructor(firstName, birthYear) {
this.firstName = firstName;
this.birthYear = birthYear;
}
//这种方式和前面的 PersonCl.prototype.calAge(){} 一样
calAge() {
console.log(2023 - this.birthYear);
}
}
const kingflyz = new PersonCl('kyzr2000', 2000);
kingflyz.calAge(); //输出23
class PersonCl {
get birthYear() {
//setter内改变名了,getter内也要改,因为访问一个对象的属性时会先通过getter方法来寻找
return this._birthYear;
}
set birthYear(year) {
//为了防止循环 需要在变量名称前加一个_,同时为了保证构造函数会自动调用这个setter,setter的方法名称也要和变量的名称相同
if (year > 1999) this._birthYear = year;
}
}
在ES6中,静态方法是指被定义在一个类上的模板方法,而不是被定义在类的实例上的方法。静态方法是类的属性,而不是实例对象的属性。
class PersonCl {
static hey() {
console.log(`ciahello~`);
}
}
PersonCl.hey(); //只能通过类来调用静态的方法,无法用实例的对象来调用
const PersonProto = {
calAge() {
console.log(2023 - this.birthYear);
},
init(firstName, birthYear) {
this.firstName = firstName;
this.birthYear = birthYear;
},
};
//通过Object create创建对象
const kingflyz = Object.create(PersonProto);
kingflyz.init('King_FLYz', 2000);
console.log(kingflyz);
kingflyz.calAge();
#使用构造方法继承
const Pesron = function (firstName, birthYear) {
this.firstName = firstName;
this.birthYear = birthYear;
};
Pesron.prototype.calAge = function () {
return 2023 - this.birthYear;
};
//通过原型链将两个构造函数连接到一起,这样Student的实例才能调用Person原型中的方法
//要注意本条语句的位置
Student.prototype = Object.create(Pesron.prototype);
const Student = function (firstName, birthYear, course) {
Pesron.call(this, firstName, birthYear);
this.course = course;
};
//这里的nickyzj在浏览器中显示的原型还是Person,想要改变为Student需要添加此条语句
Pesron.prototype.constructor = Student;
const nickyzj = new Student('yzj', 2001, 'computer and science');
console.log(nickyzj。calAge());
#使用ES6 Classer的extends继承
class StudentCl extends PersonCl {
constructor(firstName, birthYear, course) {
super(firstName, birthYear);
this.course = course;
}
introduce() {
console.log(`${this.birthYear}`);
}
}
#使用Object Create继承
const PersonProto = {
calAge() {
console.log(2023 - this.birthYear);
},
init(firstName, birthYear) {
this.firstName = firstName;
this.birthYear = birthYear;
},
};
//使用Object.create继承
const StudentProto = Object.create(PersonProto);
StudentProto.init = function (firstName, birthYear, course) {
PersonProto.init(firstName, birthYear);
this.course = course;
console.log(`My name is ${this.firstName} and I study ${this.course}`);
};
const yzj = Object.create(StudentProto);
yzj.init('yzj', 2001, 'computer');
class PersonCl {
//私有属性 在前面加#
#height;
//公有属性
language = 'chinese';
constructor(firstName, birthYear, height) {
this.firstName = firstName;
this.birthYear = birthYear;
this.#height = height;
}
//私有方法
#hey() {
console.log(`ciahello~`);
}
//公有方法
calAge() {
console.log(2023 - this.birthYear);
this.#hey();
}
}
通过Geolocation可以获得用户当前的位置。
if (navigator.geolocation) {
//两个参数分别是:成功获取到地址时执行的函数 、 未成功获取地址时执行的函数
navigator.geolocation.getCurrentPosition(
function (position) {
console.log(position);
},
function () {
alert(`Couldn't get ur position`);
}
);
}
异步 JavaScript 是指一种编程技术,其中 JavaScript 代码不会阻塞(即停止执行),而是在后台运行,同时允许其他代码继续执行。这样做的好处是可以提高网页性能,使其更加快速和灵活。
因为JS是单线程的,在处理 JS 代码时,JS引擎会将同步代码放入执行栈中按照顺序执行,遇到异步代码时则将其交给 Web API 处理,并立即将下一条语句从执行栈中移除。Web API 是浏览器提供的一组 API 接口,例如 setTimeout、AJAX、DOM 操作等,它们都是异步的。当 Web API 完成异步操作后,会将回调函数加入到回调队列中,JS引擎在空闲时(Call Stack为空的时候)通过不断地循环处理回调队列(事件循环),就能够实现 JavaScript 的异步编程。
在异步JS中存在一个微任务队列(Microtasks queue),该队列专门存放由异步操作产生的微任务的一种机制,如Promise的回调函数,微任务具有高优先级,同一时间循环中微任务会优先于宏任务(如settimeout、setinterval等)先执行。
Ajax(Asynchronous JavaScript And XML)是一种 Web 开发技术,利用 JavaScript 和 XML(或 JSON 等格式)在客户端和服务器之间进行异步数据交换。
使用回调函数来处理异步操作可能会导致回调地狱(callback hell)问题,可以使用Promise来简化代码的编写。
Promise是一种表示异步操作最终完成或失败的对象。它可以用来处理异步操作的结果,并且提供了更具有可读性的方式来编写异步代码。
fetch是一种新的Web API,它提供了一种获取资源(例如JSON数据)的方法。它基于Promise,因此它也是异步的。
使用fetch方法向服务器请求一个JSON数据。一旦服务器响应,我们使用response.json()方法将响应解析为JSON格式。然后,我们使用第二个.then()方法来处理JSON数据并进行日志记录。如果出现错误,则使用.catch()方法来捕获并处理该错误,finally()方法是最后执行的,在成功/失败之后都会执行,但是有时会出现一些错误。
fetch('https://api.example.com/data.json')
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error(error))
.finally();
const lotteryPromise = new Promise(function (resolve, reject) {
console.log('it will be happend');
if (Math.random() >= 0.5) resolve('you win!!');
else reject('you lose!!');
});
lotteryPromise.then(res => console.log(res)).catch(err => console.error(err));
Promise.resolve('kkkkyzr').then(res => console.log(res));
Promise.reject('kkkkyzr').catch(err => console.error(err));
Promise 对象有两种状态:fulfilled(已解决)和 rejected(已拒绝)。
当 Promise 成功完成异步任务并返回结果时,它进入 fulfilled 状态,并调用 then() 方法来处理结果。fulfilled 状态下的 Promise 将其结果传递给 then() 方法。
如果在异步任务执行期间发生错误或 Promise 被显式地拒绝,则 Promise 进入 rejected 状态,并调用 catch() 方法或者 then() 方法中的第二个参数来处理被拒绝的原因。
需要注意的是,Promise 的状态只能由 pending(等待)转换为 fulfilled 或 rejected 两种状态之一,一旦 Promise 进入其中一种状态,它就不能再回到 pending 状态。
async function foo() {
const result = await someAsyncFunction();
console.log(result);
}
在使用await关键字时必须将其放置在异步函数内,someAsyncFunction()返回一个Promise对象,await关键字暂停了foo()函数的执行,直到该Promise对象的状态被解决为止。await会等待someAsyncFunction()的返回结果并返回该Promise对象的解决值,并且将其赋值给变量result。接下来,console.log()方法被执行,打印出result的值。
Promise.all()
它会接收一个 Promise 数组作为参数,并在所有 Promise 都完成后返回一个 Promise。返回的 Promise 解决为一个数组,其中包含每个 Promise 的解决结果,顺序与传入的 Promise 数组顺序相同。但如果有一个promise被拒绝就会短路,会直接返回rejected状态的。
Promis.race()
它会接收一个 Promise 数组作为参数,返回完成最快的第一个Promise。
Promise.allSettled()
和Promise.all()类似,但是他会返回所有的Promise,不会因为被拒绝的Promise而短路。
Promise.any()
Promise.any()有一个Promise为fulfilled就会正常运行并返回该Promise,全部Promise为rejected才会短路。
总结:Promise.all() 方法是 && 的关系;Promise.any() 方法是 || 的关系; Promise.race()方法是 赛跑机制 。
注意:异步函数始终返回一个 Promise 对象。在异步函数中使用 return 语句时,JavaScript 实际上会将其转换为一个已解决的 Promise 对象。在异步函数中使用 await 关键字时,它会等待 Promise 对象解析后,然后返回 Promise 的解析值(fulfilled或rejected)。
ES模块通过import和export语句实现模块间的依赖管理和导入导出操作。import语句用于导入其他模块中的内容,export语句用于向外部公开当前模块中的某些变量、函数或类等。
import add,{ car, date, money as m } from './shoppingCart.js';
console.log('import.js');
console.log(car, date, m);
add(180);
add(210);
console.log(car);
console.log('export.js');
export const car = [];
const money = 12450;
const date = 33;
export { money, date };
export default function (data) {
car.push(data);
console.log(`${data}已经进了你的兜里了!`);
}