跳至主要內容

JavaScript

TenSoFlow...大约 37 分钟前端JavaScript

JavaScript

第01章 简介

是一种运行在客户端(浏览器)的编程语言,实现人机交互效果。分为ECMAScript(语言基础)和Web APIs(分为DOM和BOM)两大类。

DOM:页面文档对象模型

BOM:浏览器对象模型

第02章 基础语法

书写位置

位置一:内部JS

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title></title>
  </head>
  <body>
    <button>点击</button>

    <!-- 内部js -->
    <script>
      alert("你好");
    </script>
  </body>
</html>

要写在body标签的最后面,因为HTML是按照顺序加载的,而JS是为哪些标签服务的,所以要写在最后。

位置二:外部JS

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title></title>
  </head>
  <body>
    <!-- 通过src引入外部js文件 -->
    <script src="study.js">
      // 中间不要写内容,写了也不执行的。
    </script>
  </body>
</html>

位置三:行内

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title></title>
  </head>
  <body>
    <!-- 写在标签内部 -->
    <button onclick="alert('逗你玩~~~')">点我月薪过万</button>
  </body>
</html>

注释

单行注释

// 我是单行注释
console.log('Hello')

VSCode快捷键 Ctrl + /

多行注释

/*
 我是多行注释
 我是多行注释
*/
console.log('Hello');

VSCode快捷键 Shift + Alt + A

结束符

以英文;结束,可写可不写

输入输出

输出-document.write

// document.write是向body里面写内容,会将字符串自动转为HTML
// 页面显示的只是普通的字符串
document.write('我是标题')
// 页面上显示的是h1标签的字符串
document.write('<h1>我是标题</h1>')

输出-alert

// 弹框输出
alert("Hello");
alert('Hello');

输出-console.log

// 控制台输出
console.log('Hello');

输入-prompt

const age = prompt("请输入您的年龄!");
console.log('age:', age);

注意

一般JavaScript会按照顺序执行代码,但是alert()和prompt()它们两个会先被执行。

变量

let

// 定义变量
let age;
// 用=来为变量赋值
age = 20;
// 声明变量的时候同时给值
let name = "小明";
// 一次声明多个变量
let sex = '男' , height = 175;

变量名规则:

  • 变量名不能用关键字如if else let for try等等。
  • 只能用下划线、字母、数字、$组成,数字不能开头。
  • 字母区分大小写,如A和a是不同的变量。

变量名规范:

小驼峰命名法:第一个单词首字母小写,后面每个单词首字母大写。如:userName

常量

const

const G = 9.8;

常量定义时必须赋值,并且常量赋值后就不能再次赋值。常量其实就是不能改变的变量。通常表示不能更改的量。如重力加速度G,圆周率π等。

数据类型

基本数据类型

null 空类型
number 数字型
string 字符串型
boolean 布尔型
undefined 未定义型

// 只声明变量,不赋值的情况下,变量的默认值为undefined。

let flag = "";
if (flag) { // flag = "" | undefined | 0 | -0 | null | NaN 都会被判为false
    console.log("ten")
}

引用数据类型

object 对象

算术运算符

+-*/% 模

a += b   // 等价于 a = a + b
a -= b   // 等价于 a = a - b
a *= b   // 等价于 a = a * b
a /= b   // 等价于 a = a / b
a %= b   // 等价于 a = a % b
a **= b  // 等价于 a = a ** b 即a的b次方 ==》2 ** 3 = 8
a <<= b  // 等价于 a = a << b
a >>= b  // 等价于 a = a >> b
a >>>= b // 等价于 a = a >>> b
a &= b   // 等价于 a = a & b
a |= b   // 等价于 a = a | b
a ^= b   // 等价于 a = a ^ b
a &&= b  // 等价于 a = a && b
a ||= b  // 等价于 a = a || b
a ??= b  // 等价于 a = a ?? b

NaN 表示一个计算错误,它是一个不正确的或者一个未定义的数字操作所得到的结果。
 ('Ten' - 2) // NaN

检测数据类型

两种方法
1. typeof xxx  // xxx表示变量名或者直接是值
2. typeof(xxx) // xxx表示变量名或者直接是值

let flag = false;
console.log(typeof flag); // 输出boolean
console.log(typeof(flag)); // 输出boolean
console.log(typeof 'flag') // 输出string

数据类型转换

隐式转换

// +号两边只要有一个是字符串,都会把另外一个转成字符串
console.log("Ten" + 2) // Ten2
console.log("45" + 3) // 453

// 除了+以外的算术运算符比如-*/等都会把数据转为数字类型
console.log("45" - 5) // 40
console.log(5 - "45") // -40

// 小技巧
+号作为正号解析可以转换为数字型
console.log(+"45" + 5) // 50
// 任何数据和字符串相加结果都是字符串

显示转换

// Number(var) 将var转为数字型
console.log(Number("123")); // 123
console.log(Number("Ten" - 3)); // NaN

// parseInt(var) 将var转为整数,只会保留整数部分,不会四舍五入
console.log(parseInt("123.75")); // 123
console.log(parseInt("123.75Ten")); // 123
console.log(parseInt("Ten123.75So")); // NaN

// parseFloat(var) 将var保留小数
console.log(parseFloat("123.75")); // 123.75
console.log(parseFloat("123.75Ten")); // 123.75
console.log(parseFloat("Ten123.75So")); // NaN

逻辑运算符

// || 运算符:如果第一个值是真值(在不计算第二个值的情况下),它将返回第一个值。否则,它将返回第二个值。
// && 运算符:如果第一个值是假值(在不计算第二个值的情况下),它将返回第一个值。否则,它将返回第二个值。
// ?? 运算符:与||相同,只是它只将null和undefined视为假值。
let textInput = null
let stringOr = textInput || "TenSoFlow"
let stringAnd = textInput && "TenSoFlow"
let stringPlus = textInput ?? "TenSoFlow"
console.log(stringOr) // TenSoFlow
console.log(stringAnd) // null
console.log(stringPlus) // TenSoFlow

textInput = 10
stringOr = textInput || "TenSoFlow"
stringAnd = textInput && "TenSoFlow"
stringPlus = textInput ?? "TenSoFlow"
console.log(stringOr) // 10
console.log(stringAnd) // TenSoFlow
console.log(stringPlus) // 10

// 应用1:从列表中选择第一个真值
const a = null
const b = undefined
const c = 0
const d = 10
const firstTrue = a || b || c || d
console.log(firstTrue) // 10

运算符优先级

// 以下按照优先级从高到低排序
括号 ()
逻辑非 !
乘除 * / %
加减 + -
位运算(如 & | ^)
比较运算(如 === !== < > <= >= )
逻辑与 &&
逻辑或 ||
赋值运算 = += -= *= /= %=

功能函数

判断是否为正整数

// 其中self.forecastDays是用字符串代表的数字
// 预测天数处理
let days = Number(self.forecastDays);
// 如果输入的不是正整数则设置预测天数为0
if (!Number.isInteger(days) || days < 0) {
    days = 0;
}

判断是否为正数或者正小数

/**
 * 数字校验-只能为正数或者正小数,并将小数保留指定位数
 * 
 * @param {object} row 当前行数据
 * @param {string} attributeName 属性名
 * @param {number} digits 小数保留为指定位数,默认为2
 */
numCheck(row, attributeName, digits = 2) {
  if (!row[attributeName]) {
    row[attributeName] = '';
    return;
  }
  // 是数字
  if (!isNaN(row[attributeName])) {
    const number = Number(row[attributeName]);
    // 数字大于等于0时保留指定位数小数
    if (number >= 0) {
      // 转为指定小数位
      const attributeValue = parseFloat(number);
      if (!Number.isInteger(attributeValue)) {
        row[attributeName] = parseFloat(attributeValue.toFixed(digits));
      }
      return;
    }
  }
  row[attributeName] = '';
  this.seedMessage('请输入正确的数字!');
  this.$forceUpdate();
},

判断只能为正整数或者0

/**
 * 数字校验-只能为正整数或者0
 * 
 * @param {object} row 当前行数据
 * @param {string} attributeName 属性名
 */
numCheck(row, attributeName) {
  if (!row[attributeName]) {
    row[attributeName] = '';
    return;
  }
  // 是数字
  if (!isNaN(row[attributeName])) {
    const number = Number(row[attributeName]);
    
    // 检查是否为正整数或者0
    if (number >= 0 && Number.isInteger(number)) {
      row[attributeName] = number; // 保留原值
      return;
    }
  }
  row[attributeName] = '';
  this.seedMessage('请输入正确的正整数或者0!');
  this.$forceUpdate();
},

对象遍历

const person = {
  name: 'TenSoFlow',
  age: 18,
  sex: '男',
}

for (const key in person) {
  console.log('key:', key);
  console.log('value:', person[key]);
}

// 输出
key: name
value: TenSoFlow
key: age
value: 18
key: sex
value:

第03章 函数

数字操作函数

Number

Number 用于将一个值转换为数字类型。如果转换失败,返回 NaN(不是一个数字)。

console.log(Number("123"));      // 123
console.log(Number("123.45"));   // 123.45
console.log(Number("abc"));      // NaN
console.log(Number(true));       // 1
console.log(Number(false));      // 0
console.log(Number(null));       // 0
console.log(Number(undefined));  // NaN

parseInt

parseInt 用于将字符串解析为整数。它可以接受第二个参数作为基数(进制),默认是10。解析时遇到非数字字符会停止。

console.log(parseInt("123"));          // 123
console.log(parseInt("123.45"));       // 123
console.log(parseInt("abc123"));       // NaN
console.log(parseInt("123abc"));       // 123
console.log(parseInt("  42  "));       // 42
console.log(parseInt("10", 2));        // 2  (将二进制10转为十进制)
console.log(parseInt("10", 16));       // 16 (将十六进制10转为十进制)

parseFloat

parseFloat 用于将字符串解析为浮点数。它与 parseInt 类似,但会解析为浮点数,并且会解析小数部分。

console.log(parseFloat("123.45"));     // 123.45
console.log(parseFloat("123.00abc"));  // 123
console.log(parseFloat("abc123.45"));  // NaN
console.log(parseFloat("  42.5  "));   // 42.5
console.log(parseFloat("3.14"));       // 3.14
console.log(parseFloat("10.5", 2));    // 10.5 (第二个参数被忽略)

toFixed

// 基本用法
toFixed(num) // num为需要保留的位数

// 将cumu转化为数字并乘以1000然后保留两位小数
cumu = (Number(cumu) * 1000).toFixed(2)

注意

toFixed()返回的是string类型

round

// 小数化整数 四舍五入
this.money = Math.round(this.num * 2.63);

注意

round()返回的是number类型

ceil

可以使用 Math.ceil() 函数来向上取整。这个函数会返回大于或等于给定数字的最小整数。例如:

Math.ceil(4.2) // 返回 5
Math.ceil(-4.2) // 返回 -4

setTimeout

在JavaScript中一旦调用setTimeout函数,即会设置定时器,但随后立即继续执行任何后续代码,不会暂停或等待定时器完成,这展示了JavaScript的非阻塞特性。

// 会立刻打印出'So'然后等待2000毫秒(2秒)后打印出'Ten'
setTimeout(() => {
    console.log('Ten')
}, 2000)
console.log('So')

另外,与其配套使用的是clearTimeout见名知义,它能取消先前调用setTimeout建立的定时器。值得注意的是:如果取消,setTimeout里面的回调函数将不会被调用。

// 会立刻打印出'So'
let timeoutId = setTimeout(() => {
  console.log('Ten')
}, 2000)
console.log('So')
if (true) {
  // 会立刻清除定时器,不会打印出'Ten'
  clearTimeout(timeoutId)
}

第04章 Array

at

// 此方法接受一个整数值,并返回该索引处的元素,允许使用正整数和负整数。负整数从数组末尾开始计数。如果数组为空,则at(-1)为undefined
const arr = [1, 2, 3]
console.log(arr.at(0)) // 输出1
console.log(arr.at(1)) // 输出2
console.log(arr.at(2)) // 输出3
console.log(arr.at(3)) // 输出undefined
console.log(arr.at(-1)) // 输出3
console.log(arr.at(-2)) // 输出2

map

// 对数组中的每个元素执行回调函数,并返回一个新数组。
const arr = [1, 2, 3]
const newArr = arr.map((item) => {
  return item + 1
})
console.log(newArr) // 输出 [2, 3, 4]

pop

// 该方法从数组中移除最后一个元素并返回它。如果数组为空,则pop()返回undefined
const arr = [1, 2, 3]
console.log(arr.pop()) // 输出3
console.log(arr.length) // 输出2

find

// 返回数组中通过测试函数的第一个元素。
const arr = [1, 2, 3, '4']
const element = arr.find((item) => {
  return typeof item === 'number'
})
console.log(element) // 输出 1

join

// 数组各项连接,返回类型是string
const dateArray = [2024, 4, 11]
const formattedDate = dateArray.join('-')
console.log(formattedDate) // 2024-4-11

sort

// 对数组中的元素进行排序。会原地改变数组顺序,不用另外使用一个变量接收。
const arr = [1, 3, 2, '0']
arr.sort()
console.log(arr) // [ '0', 1, 2, 3 ]

// 注意:在JavaScript中,sort()方法默认将数组中的元素转换为字符串,并按照Unicode编码进行排序,因此对于负数就不能排序。
const arr = [-1, -100, -4, '0']
arr.sort()
console.log(arr) // [ -1, -100, -4, '0' ]

// 想对数组中的数字进行精准的数值排序,可以传递一个比较函数给sort()方法
const arr = [-1, -100, -4, '0']
arr.sort((a, b) => a - b)
console.log(arr) // [ -100, -4, -1, '0' ]

push

// 将新的项添加到数组的末尾并返回新的长度
const arr = [1, 2, 3]
console.log(arr.push(4)) // 输出4
console.log(arr) // 输出[1, 2, 3, 4]

slice

// 此方法提取数组的一部分并返回一个新的数组,并不会改变原始数组。传入的参数长度超过原始数组长度不会报错,会返回整个原始数组
const arr = [1, 2, 3]
console.log(arr.slice(0, 1)) // 输出 [ 1 ]
console.log(arr.slice(0, 2)) // 输出 [ 1, 2 ]
console.log(arr.slice(0, 3)) // 输出 [ 1, 2 , 3 ]
console.log(arr.slice(0, 4)) // 输出 [ 1, 2 , 3 ]
console.log(arr.slice(-1)) // 输出 [ 3 ]
console.log(arr.slice(-2)) // 输出 [ 2, 3 ]
console.log(arr.slice(-3)) // 输出 [ 1, 2, 3 ]
console.log(arr.slice(-4)) // 输出 [ 1, 2, 3 ]

shift

// 移除数组的第一个元素,并返回该元素。
const arr = [1, 2, 3]
const firstElement = arr.shift()
console.log(firstElement) // 输出: 1
console.log(arr) // 输出: [2, 3]

filter

// 创建一个新数组,包含通过提供的函数测试的所有元素。
const arr = [1, 2, 3, '4']
const newArr = arr.filter((item) => {
  return typeof item === 'number'
})
console.log(newArr) // 输出 [1, 2, 3]

### every

// 测试数组中的所有元素是否都满足指定的条件。一旦有元素不满足条件,every 会立刻返回 false,并停止进一步的测试。
// 空数组的特殊性:every 对空数组始终返回 true,因为没有元素会违背条件。

// 实例一:检查数组中的元素是否都为正数
const numbers = [1, 2, 3, 4];
const allPositive = numbers.every(num => num > 0);
console.log(allPositive); // true

// 示例二:验证数组是否为空
const emptyArray = [];
const isEmptyValid = emptyArray.every(() => false); // 空数组默认返回 true
console.log(isEmptyValid); // true

splice

// 主要用于添加、删除或替换数组中的元素。它会直接修改原数组,并返回被删除的元素(如果有删除操作的话)。
// 语法
array.splice(start, deleteCount, item1, item2, ...)
// 参数解释
start: 必须。指定从哪个索引位置开始修改数组。可以为负数,表示从数组末尾倒数的位置开始。
deleteCount: 可选。要删除的元素个数。如果为 0,则不会删除任何元素。
item1, item2, ...: 可选。要添加到数组中的元素。如果没有提供此参数,splice() 只删除元素。
// 返回
返回一个包含被删除元素的数组。如果没有删除任何元素,则返回一个空数组。
// 用法示例
const arr = [1, 2, 3, 4, 5];
arr.splice(2, 1); // 从索引 2 开始,删除 1 个元素
console.log(arr); // [1, 2, 4, 5]

const arr = [1, 2, 3, 4, 5];
arr.splice(2, 1, 'a'); // 从索引 2 开始,删除 1 个元素,并添加 'a'
console.log(arr); // [1, 2, 'a', 4, 5]

const arr = [1, 2, 3, 4, 5];
arr.splice(2, 0, 'a', 'b'); // 从索引 2 开始,插入 'a' 和 'b'
console.log(arr); // [1, 2, 'a', 'b', 3, 4, 5]

const arr = [1, 2, 3, 4, 5];
arr.splice(-2, 1); // 从倒数第二个元素开始,删除 1 个元素
console.log(arr); // [1, 2, 3, 5]

concat

// 连接两个或多个数组,返回一个新数组。
const arrOne = [1, 2, 3]
const arrTwo = [4, 5, 6]
const arrThree = arrOne.concat(arrTwo)
console.log(arrThree) // 输出: [ 1, 2, 3, 4, 5, 6 ]

reduce

// 操作对象为数组,用于对数组中的每个元素进行累积操作,这个函数常用于对数组进行求和,求积,扁平化,统计等操作
const arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
// 初始时会把第二个参数(0)给acc,即第二个参数为acc的初始值,cur代表遍历的数组项,函数每次的返回值会给acc
const result = arr.reduce((acc, cur) => acc + cur, 0)
console.log(result) // 输出55

unshift

// 在数组的开头添加一个或多个元素,并返回新数组的长度。
const arr = [1, 2, 3]
const newLength = arr.unshift(0)
console.log(newLength) // 输出: 4
console.log(arr) // 输出: [ 0, 1, 2, 3 ]

forEach

// 遍历数组
const arr = [1, 2, 3]
arr.forEach((item) => [
  console.log(item)
])

reverse

// 反转数组中的元素。
const arr = [1, 2, 3, '4']
const reversedArray = arr.reverse()
console.log(reversedArray) // [ '4', 3, 2, 1 ]

indexOf

// 返回数组中某个元素的第一个索引,如果不存在,返回 -1。
const arr = [1, 2, 3]
console.log(arr.indexOf(2)) // 输出 1
console.log(arr.indexOf(4)) // 输出 -1

includes

// 检查数组是否包含某个元素,返回布尔值。
const arr = [1, 2, 3]
console.log(arr.includes(2)) // 输出 true
console.log(arr.includes(5)) // 输出 false

findIndex

// 返回数组中通过测试函数的第一个元素的索引。
const arr = [1, 2, 3, '4']
const element = arr.findIndex((item) => {
  return typeof item === 'number'
})
console.log(element) // 输出 0

Array.from

Array.from 是 JavaScript 中创建数组的一个工具方法,它可以根据类数组对象(如 { length: n })或可迭代对象(如String、Set、Map等类型)生成一个新的数组。

// arrayLike:类数组对象或可迭代对象。
// mapFunction:可选,用于对生成的每个元素执行的映射操作。
Array.from(arrayLike, mapFunction)

// 示例一
const n = 3
const arr = Array.from({ length: n + 1 }, () => [0, 0])
// 输出: [ [0, 0], [0, 0], [0, 0], [0, 0] ]
console.log(arr)

// 示例二
const str = 'hello'
const arr = Array.from(str)
// 输出 ['h', 'e', 'l', 'l', 'o']
console.log(arr)

// 示例三
const set = new Set([1, 2, 3, 4])
const arr = Array.from(set)
// 输出 [1, 2, 3, 4]
console.log(arr)

// 示例四
const map = new Map([
    ['a', 1],
    ['b', 2],
    ['c', 3],
])
const arr = Array.from(map)
// 输出 [['a', 1], ['b', 2], ['c', 3]]
console.log(arr)

reduceRight

它的功能和 reduce 类似,不同的是,reduceRight 从数组的右边开始遍历元素(从最后一个元素到第一个元素),而 reduce 是从左边开始(从第一个元素到最后一个元素)。

const arr = [1, 2, 3, 4]
const result = arr.reduceRight((acc, cur) => {
  return acc - cur
}, 0)
console.log(result) // -10

第05章 对象

简介

对象用于存储键值对的集合。对象的键可以是可以转换为字符串的任何值,相应的值可以是任何数据类型,包括对象和数组。

// 使用对象的示例:
const person = {
  name: "Pavitr Prabhakar",
  age: 17,
  city: "Mumbattan"
};
console.log(person.name) // 输出: Pavitr Prabhakar
console.log(person.age) // 输出: 17
console.log(person.city) // 输出: Mumbattan

Object.isopen in new window

判断两个值是否严格相等,类似于===,但是更加严格。

console.log(Object.is(NaN, NaN)); // 输出 true
console.log(Object.is(0, -0));    // 输出 false

Object.keys

返回自身可枚举属性名的数组。

const obj = { a: 1, b: 2 }
console.log(Object.keys(obj)) // 输出 ['a', 'b']

Object.seal

封闭一个对象,阻止添加新属性,但允许修改现有属性。

const obj = { name: 'John' };
Object.seal(obj);

obj.name = 'Doe'; // 可以修改现有属性
console.log(obj.name); // 输出 'Doe'

obj.age = 30; // 无法添加新属性
console.log(obj.age); // 输出 undefined

Object.assign

将一个或多个源对象的属性复制到目标对象中。目标对象和源对象公共的属性,以目标对象为准。

const target = { a: 1, b: 4 }
const source = { b: 2, c: 3 }

Object.assign(target, source)
console.log(target); // 输出 { a: 1, b: 2, c: 3 }

Object.create

使用指定的原型对象和属性创建一个新对象。

const person = {
  greet() {
    console.log("Hello")
  }
};

const john = Object.create(person)
john.greet() // 输出 "Hello"

Object.entries

返回对象自身可枚举属性的键值对数组。

const obj = { a: 1, b: 2 }
console.log(Object.entries(obj)) // 输出 [ ['a', 1], ['b', 2] ]

Object.values

返回自身可枚举属性值的数组。

const obj = { a: 1, b: 2 }
console.log(Object.values(obj)) // 输出 [1, 2]

Object.freeze

冻结一个对象,使其不能被修改。

const obj = { name: 'John' }
Object.freeze(obj)
obj.name = 'Doe' // 修改无效
console.log(obj.name) // 输出 'John'

Object.fromEntries

将键值对数组转换为对象。

const entries = [['a', 1], ['b', 2]];
const obj = Object.fromEntries(entries);
console.log(obj); // 输出 { a: 1, b: 2 }

Object.defineProperty

为对象定义一个新的属性,或者修改现有属性的特性。

const obj = {};
Object.defineProperty(obj, 'name', {
  value: 'John',
  writable: false // 属性不可修改
});

console.log(obj.name) // 输出 "John"
obj.name = 'Doe' // 无法修改
console.log(obj.name) // 仍然输出 "John"

Object.hasOwnProperty

检查对象是否包含指定的属性,且该属性不是继承自原型链。

const obj = { name: 'John' };
console.log(obj.hasOwnProperty('name')); // 输出 true
console.log(obj.hasOwnProperty('age'));  // 输出 false

Object.getOwnPropertyDescriptors

返回对象所有自身属性的描述符。

const obj = { name: 'John' };
const descriptors = Object.getOwnPropertyDescriptors(obj);
console.log(descriptors);
/*
输出:
{
  name: {
    value: 'John',
    writable: true,
    enumerable: true,
    configurable: true
  }
}
*/

第06章 String

trim

去掉字符串两端的空白字符。

let str = "   Hello World   ";
console.log(str.trim()); // "Hello World"

let str = '   I Love You  '
console.log(str.trim()) // "I Love You"
console.log(str.trimStart()) // "I Love You  "
console.log(str.trimEnd()) // "   I Love You"

slice

提取字符串的子字符串。

let str = "Hello World";
console.log(str.slice(0, 5)); // "Hello"

split

将字符串分割为子字符串,并返回一个数组。

let str = "Hello World";
console.log(str.split(" ")); // ["Hello", "World"]

length

返回字符串的长度

let str = "Hello World";
console.log(str.length); // 11

charAt

返回指定索引处的字符。

let str = "Hello";
console.log(str.charAt(1)); // "e"

concat

连接两个或多个字符串,并返回新的字符串。

let str1 = "Hello";
let str2 = "World";
console.log(str1.concat(" ", str2)); // "Hello World"

replace

替换字符串中的指定子字符串。

let str = "Hello World";
console.log(str.replace("World", "JavaScript")); // "Hello JavaScript"

includes

判断字符串是否包含指定的子字符串,返回布尔值。

let str = "Hello World";
console.log(str.includes("World")); // true

indexOf

返回指定子字符串首次出现的索引,如果未找到则返回 -1

let str = "Hello World";
console.log(str.indexOf("o")); // 4

charCodeAt

返回指定位置的字符的 Unicode 编码

let str = "hello";
let code = str.charCodeAt(0); // 返回 104,因为 'h' 的 Unicode 编码是 104
console.log(code); // 输出 104

startsWith

判断字符串是否以指定子字符串开头。

let str = "Hello World";
console.log(str.startsWith("Hello")); // true

lastIndexOf

返回指定子字符串最后一次出现的索引。

let str = "Hello World";
console.log(str.lastIndexOf("o")); // 7

toLowerCase

将字符串转换为小写。

let str = "Hello World";
console.log(str.toLowerCase()); // "hello world"

toUpperCase

将字符串转换为大写。

let str = "Hello World";
console.log(str.toUpperCase()); // "HELLO WORLD"

fromCharCode

根据 Unicode 编码返回相应的字符或者字符串。

let char = String.fromCharCode(104); // 返回 'h'
console.log(char); // 输出 'h'

let chars = String.fromCharCode(104, 101, 108, 108, 111); // 返回 'hello'
console.log(chars); // 输出 'hello'

第07章 日期

// ======= 创建 ======= \\
// 创建当前日期
let currentDate = new Date()
console.log(currentDate) // 输出2024-09-24T06:25:09.766Z

// 根据给定的毫秒数(自1970年1月1日以来的毫秒数)创建日期
currentDate = new Date(1672531200000)
console.log(currentDate) // 输出2023-01-01T00:00:00.000Z

// 使用ISO日期格式字符串创建日期
currentDate = new Date("2024-09-24")
console.log(currentDate) // 输出2024-09-24T00:00:00.000Z

// 使用具体的年、月、日创建日期
// 注意:月份从0开始,8表示9月
// 注意:如果只提供年和月,日默认为1
// 注意:构造出来的日期总是少一天
currentDate = new Date(2023, 8, 2)
console.log(currentDate) // 输出2023-09-01T16:00:00.000Z

// ======= 获取 ======= \\
const now = new Date()
// 获取年
const year = now.getFullYear()
console.log(year) // 输出2024
// 获取当前月份,0 表示1月, 所以实际的月份要加1
const month = now.getMonth() + 1
console.log(month) // 输出9
// 获取当前星期,0 表示星期日,1 表示星期一,以此类推
const weekday = now.getDay()
console.log(weekday) // 输出2
// 获取当前日
const day = now.getDate()
console.log(day) // 输出24
// 获取当前小时
const hour = now.getHours()
console.log(hour) // 输出14
// 获取当前分钟
const minute = now.getMinutes()
console.log(minute) // 输出35
// 获取当前秒
const second = now.getSeconds()
console.log(second) // 输出48
// 获取当前毫秒
const millisecond = now.getMilliseconds()
console.log(millisecond) // 输出710
// 获取当前时间戳(自1970年1月1日以来的毫秒数)
const timestamp = now.getTime()
console.log(timestamp) // 输出1727159900710

// ======= 设置 ======= \\
const futureDate = new Date()
// 设置年
futureDate.setFullYear(2025)
// 设置月 月份从0开始,8表示9月
futureDate.setMonth(8)
// 设置日
futureDate.setDate(15)
// 设置小时
futureDate.setHours(18)
// 设置分钟
futureDate.setMinutes(30)
// 设置秒
futureDate.setSeconds(45)
// 设置毫秒
futureDate.setMilliseconds(500)

// ======= 方法 ======= \\
// 返回当前时间的时间戳(自1970年1月1日以来的毫秒数)
console.log(Date.now())
// 将日期解析为时间戳
console.log(Date.parse("2024-09-24T00:00:00"))
// 格式化为ISO字符串
const time = new Date()
console.log(time.toISOString()) // 输出2024-09-24T06:47:13.386Z
// 格式化为本地字符串
console.log(time.toLocaleDateString()); // 仅输出日期部分 2024/9/24
console.log(time.toLocaleTimeString()); // 仅输出时间部分 14:47:51
console.log(time.toLocaleString()); // 输出完整日期和时间 2024/9/24 14:47:51
// 获取UTC时间格式字符串
console.log(time.toUTCString()); // 获取 UTC 时间格式的字符串 Tue, 24 Sep 2024 06:51:48 GMT
// 比较日期
const date1 = new Date("2023-09-24");
const date2 = new Date("2024-09-24");
console.log(date1 < date2); // 比较两个日期,返回 true
// 计算两个日期之间的天数
const startDate = new Date("2023-09-01");
const endDate = new Date("2023-09-24");
const timeDifference = endDate - startDate;
const daysDifference = timeDifference / (1000 * 60 * 60 * 24); // 将毫秒转换为天
console.log(daysDifference); // 输出日期之间的天数差

第08章 Map

和Java中的Map大同小异

set(key, value)

set(key, value)添加键值对到 Map 中。可以使用任何类型的值作为键。如果键已存在,则更新其值。

const map = new Map();
map.set('name', 'Alice');
map.set(1, 'one'); // 数字键
map.set(true, 'yes'); // 布尔键
console.log(map); // 输出: Map(3) { 'name' => 'Alice', 1 => 'one', true => 'yes' }

get(key)

返回与指定键关联的值,如果键不存在则返回 undefined

const map = new Map();
map.set('name', 'Alice');
map.set(1, 'one'); // 数字键
map.set(true, 'yes'); // 布尔键
console.log(map.get('name')); // 输出: Alice
console.log(map.get(1)); // 输出: one
console.log(map.get('age')); // 输出: undefined

has(key)

检查 Map 中是否存在某个键,返回布尔值。

const map = new Map();
map.set('name', 'Alice');
map.set(1, 'one'); // 数字键
map.set(true, 'yes'); // 布尔键
console.log(map.has('name')); // 输出: true
console.log(map.has('age'));  // 输出: false

delete(key)

删除 Map 中指定的键值对,返回 true 表示成功删除,键不存在则返回 false

const map = new Map();
map.set('name', 'Alice');
map.set(1, 'one'); // 数字键
map.set(true, 'yes'); // 布尔键
console.log(map.delete('name')); // 输出: true
console.log(map.has('name')); // 输出: false

clear()

清空 Map 中的所有键值对。

const map = new Map();
map.set('name', 'Alice');
map.set(1, 'one'); // 数字键
map.set(true, 'yes'); // 布尔键
map.clear();
console.log(map.size); // 输出: 0

size()

返回 Map 中键值对的数量。

const newMap = new Map();
newMap.set('a', 1);
newMap.set('b', 2);
console.log(newMap.size); // 输出: 2

keys()

返回一个包含 Map 中所有键的 Iterator 对象。

const map = new Map();
map.set('name', 'Alice');
map.set(1, 'one'); // 数字键
map.set(true, 'yes'); // 布尔键
const keys = map.keys();
console.log(keys); // 输出 [Map Iterator] { 'name', 1, true }
for (let key of keys) {
  console.log(key); // 输出 'name', 1, true
}

values()

返回一个包含 Map 中所有值的 Iterator 对象。

const map = new Map();
map.set('name', 'Alice');
map.set(1, 'one'); // 数字键
map.set(true, 'yes'); // 布尔键
const values = map.values();
console.log(values); // 输出 [Map Iterator] { 'Alice', 'one', 'yes' }
for (let value of values) {
  console.log(value); // 输出 'Alice', one, yes
}

entries()

返回一个包含所有键值对的 Iterator 对象,每个元素是一个 [key, value] 数组。

const map = new Map();
map.set('name', 'Alice');
map.set(1, 'one'); // 数字键
map.set(true, 'yes'); // 布尔键
const entries = map.entries();
console.log(entries); // 输出 [Map Entries] { [ 'name', 'Alice' ], [ 1, 'one' ], [ true, 'yes' ] }
for (let entrie of entries) {
  console.log(entrie); // 输出 [ 'name', 'Alice' ], [ 1, 'one' ], [ true, 'yes' ]
}

forEach(callback)

遍历 Map 的每个键值对,并为每个元素调用一次回调函数。

const map = new Map();
map.set('name', 'Alice');
map.set(1, 'one'); // 数字键
map.set(true, 'yes'); // 布尔键
map.forEach((value, key) => {
  console.log(key + ': ' + value); // 输出: 'name: Alice', '1: one', 'true: yes'
});

第09章 JSON

简介

JSON是一种流行的数据交换格式,它作为XML的轻量级替代品。广泛用于以结构化格式传输和存储数据。JSON由两种主要数据机构组成:对象和数组。数据表示为键值对的组合。对象用花括号{}括起来,数组使用方括号[]括起来。对象中的键必须是字符串,而值可以是任何有效的JSON数据类型,包括对象和数组。

// JSON对象的示例:
{
    "name": "Pavitr Prabhakar",
    "age": 17,
    "city": "Mumbattan"
}

// JSON数组的示例:
{
    “Peter”,
    "Gwen",
    "Miles"
}

JSON.parse()

JSON.parse() 是 JavaScript 中内置的函数,它将 JSON 字符串转换为 JavaScript 对象、数组或原始值(如字符串、数字、布尔或 null)。它以有效的 JSON 字符串作为输入,并返回相应的 JavaScript 对象、数组或原始值。这允许开发人员以本机 JavaScript 格式处理 JSON 数据。

// 使用JSON.parse()示例:
const jsonString = '{"name":"Pavitr Prabhakar","age":17,"city":"Mumbattan"}';
const parsedObject = JSON.parse(jsonString);
console.log(parsedObject.name); // 输出: Pavitr Prabhakar
console.log(parsedObject.age); // 输出: 17
console.log(parsedObject.city); // 输出: Mumbattan

JSON.stringify()

当你使用 JSON.stringify() 字符串化一个对象时,结果的 JSON 字符串将以字符串形式表示对象的键值对。在这个上下文中,结果字符串的 "length" 属性将表示字符串中的字符数,而不是原始对象中键值对的数量。

const person = {
  name: "Pavitr Prabhakar",
  age: 17,
  city: "Mumbattan"
}
// 如果使用JSON.stringify()字符串化此对象,它将生成以下JSON字符串:
{"name":"Pavitr Prabhakar","age":17,"city":"Mumbattan"}
// 此JSON字符串的长度将包括开头和结尾的花括号、引号、冒号和逗号。即如果是空对象则为'{}'

第10章 转换

数组转Map

二维数组转Map

如果有一个包含键值对的二维数组,可以直接用 Map 构造函数将其转换为 Map 对象。

const array = [['key1', 'value1'], ['key2', 'value2'], ['key3', 'value3']];
const map = new Map(array);
console.log(map); // 输出: Map(3) { 'key1' => 'value1', 'key2' => 'value2', 'key3' => 'value3' }
console.log(map.get('key1')); // 输出: value1

对象数组转Map

如果你有一个对象数组,并且想要某个属性作为键,另一个属性作为值,可以用 map()reduce() 来转换。

const users = [
  { id: 1, name: 'Alice' },
  { id: 2, name: 'Bob' },
  { id: 3, name: 'Charlie' }
];
// 方法一:使用 map() 方法转换
const userMap = new Map(users.map(user => [user.id, user.name]));
console.log(userMap); // 输出: Map(3) { 1 => 'Alice', 2 => 'Bob', 3 => 'Charlie' }
console.log(userMap.get(1)); // 输出: Alice
// 方法二:使用 reduce() 方法转换
const userMap = users.reduce((map, user) => {
    map.set(user.id, user.name);
    return map;
}, new Map());

对象数组某个属性转为一维数组

const users = [
    { id: 1, name: 'Alice' },
    { id: 2, name: 'Bob' },
    { id: 3, name: 'Charlie' }
];
// 使用 map() 方法提取 name 属性
const names = users.map(user => user.name);
console.log(names); // 输出: ['Alice', 'Bob', 'Charlie']

第11章 原型和原型链

简介

每个函数都有prototype属性称之为原型,这个属性的值是个对象,也称为原型对象

作用

存放一些属性和方法共享给实例对象使用,在JavaScript中实现继承。

const arr = new Array(1,2,3);
// 翻转
arr.reverse()
// 排序
arr.sort()
问:为什么数组创建好之后可以直接使用reverse方法和sort方法呢?

答:Array的构造函数有一个Array.prototype原型,原型中有很多方法,通过构造函数实例化的对象可以使用原型中的方法。

问:为什么实例化的对象可以使用原型中的方法呢?

答:每个对象都有_proto_属性,这个属性指向它的原型对象。

原型链

对象都有_proto_属性,这个属性指向它的原型对象,原型对象也是对象,也有_proto_属性,指向原型对象的原型对象,这样一层一层形成的链式结构称为原型链,最顶层找不到则返回null。

第12章 ES6

简介

ES全称EcmaScript是脚本语言的规范,而平时经常编写的JavaScript是EcmaScript的一种实现,所以ES新特性其实指的就是JavaScript新特性。ESMA(European Computer Manufacturers Association)中文名称为欧洲计算机制造商协会,这个组织的目标是评估,开发和认可电信和计算机标准。1994年后该主旨改名为Ecma国际。

关键字

let

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title>let</title>
	</head>
	<body>
		<script>
			// 声明变量
			let a;
			let b,c,d;
			let e = 100;
			let f = 521, g = 'I Love You!' ,h = [];
			console.log(g);
			
			// 1.变量不能重复声明,用var声明的变量可以重复
			// 2.作用域 -> 块级作用域 只能作用于代码块内
			// 3.不允许没声明变量前使用变量,即不存在变量提升
		</script>
	</body>
</html>

const

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title>const</title>
	</head>
	<body>
		<script>
			// 声明常量
			const SCHOOL = '希望小学';
		
			// 1.一定要赋初始值
			// 2.一般常量使用大写(潜规则)
			// 3.常量的值不能更改
			// 4.作用域 -> 块级作用域
			// 5.对于数组和对象的元素修改,不算做对常量的修改,不会报错
			const TEAM = ['UZI','MXLG','MING','XCM'];
			TEAM.push('MEIKO');
			console.log(TEAM);
		</script>
	</body>
</html>

变量的解构赋值

ES6允许按照一定模式从数组和对象中提取值,对变量进行赋值,这被称为解构赋值。

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title></title>
	</head>
	<body>
		<script>
			// 数组的解构
			const F4 = ['刘备','关羽','张飞','诸葛亮'];
			let [liu,guan,zhang,zhu] = F4;
			console.log(liu);   // liu = '刘备';
			console.log(guan);	// guan = '关羽';
			console.log(zhang); // zhang = '张飞';
			console.log(zhu);   // zhu = '诸葛亮';]
			
			// 对象的解构
			const zhao = {
				name: '赵本山',
				age: '不祥',
				xiaopin: function(){
					console.log("我可以演小品");
				}
			};
			let {name,age,xiaopin} = zhao;
			console.log(name);	// name = '赵本山';
			console.log(age);	// age = '不祥';
			xiaopin();			// 调用小品函数
			/*
				注意:let中的变量名要和对象中的属性名完全一样。
				上述 let {name,age,xiaopin} = zhao;中的{name}
				要和zhao对象中的属性name完全一样这样才能一一对应
				写成name1就不行
			*/
		</script>
	</body>
</html>

使用解构赋值的好处是简化书写,如上述的对象解构,如果不解构则每次调用函数都要写成zhao.xiaopin();解构赋值之后只需要写xiaopin()调用即可;如果需要频繁调用函数则可以使用解构赋值。

模板字符串

声明字符串有单引号 ' ' 和双引号 " "

ES6引入新的声明字符串的方式 ``

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title></title>
	</head>
	<body>
		<script>
			let str = `我也是一个字符串哦!`;
			console.log(str,typeof str);
			
			// 1.内容中可以直接出现换行符
			let str1 = `我可以换行哦!
						我换
						我在换`;
			console.log(str1);
			
			// 2.变量拼接
			let lovest = '沈腾';
			let out = `${lovest}是我心目中最搞笑的演员!`;
			console.log(out);
		</script>
	</body>
</html>

对象的简化写法

ES6允许在大括号里面直接写入变量和函数作为对象的属性和方法这样书写更加简洁。

传统写法

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title></title>
	</head>
	<body>
		<script>
			const SCHOOL = {
				name: "希望小学",
				change: function() {
					console.log('我可以改变你们!');
				},
				improve: function() {
					console.log("改善技能!");
				},
			}
			console.log(SCHOOL);
		</script>
	</body>
</html>

简化写法

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title></title>
	</head>
	<body>
		<script>
			let name = "希望小学";
			let change = function() {
				console.log('我可以改变你们!');
			}
			
			const SCHOOL = {
				name,
				change,
				improve() {
					console.log("改善技能!");
				}
			}
			
			console.log(SCHOOL);
		</script>
	</body>
</html>

箭头函数

ES6允许使用 => 定义函数

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title></title>
	</head>
	<body>
		<script>
			// 传统定义函数
			// let fn = function(){
				
			// }
			let fn = (a,b) => {
				return a + b;
			}
			let result = fn(1,2);
			console.log(result);
			
			// 1. this是静态的,this始终指向函数声明时所在作用域下的this的值
			function getName() {
				console.log(this.name);
			}
			let getName2 = () => {
				console.log(this.name);
			}
			// 设置window对象的name属性
			window.name = "希望小学";
			getName(); 	//输出希望小学
			getName2(); //输出希望小学
			const SCHOOL = {
				name: "ATGUIGU",
			}
			//使用call改变函数内部this的值
			getName.call(SCHOOL); 	//输出ATGUIGU
			getName2.call(SCHOOL);	//输出希望小学

			// 2.不能作为构造方法实例化对象
			// let Person = (naem,age) => {
			// 	this.name = name;
			// 	this.age = age;
			// }
			// let me = new Person("xiao",21);
			// console.log(me); 这是不行的
			
			// 3. 不能使用arguments变量
			// let f = () => {
			// 	console.log(arguments);
			// }
			// f(1,2,3); 这是不行的
			
			// 4.箭头函数的简写
				// 1)当形参有且只有一个的时候可以省略小括号
				let add = n => {
					return n + n;
				}
				console.log(add(4)); // 输出8
				// 2)当代码体只有一条语句的时候可以省略花括号,return也要省略
				// 语句的执行结果就是函数的返回值
				let pow = n => n * n;
				console.log(pow(5)); // 输出25
		</script>
	</body>
</html>

arguments

在JavaScript中,arguments 是一个特殊的对象,它代表了函数被调用时传递的参数列表。这个对象类似于数组,但并不是真正的数组(没有数组的方法),它主要用于访问函数的参数。

参数访问: 通过 arguments 对象,你可以访问函数中传递的所有参数。例如,arguments[0] 表示第一个参数,arguments[1] 表示第二个参数,依此类推。

function exampleFunction(a, b, c) {
  console.log(arguments[0]); // 访问第一个参数
  console.log(arguments[1]); // 访问第二个参数
  console.log(arguments[2]); // 访问第三个参数
}
exampleFunction(1, 2, 3);

动态参数: arguments 对象允许你在函数定义时不指定具体的参数,而在运行时通过 arguments 访问传递的参数。

function modifyArguments(a, b) {
  arguments[0] = 'modified';
  console.log(a); // 'modified'
}
modifyArguments('original', 2);

rest参数

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title></title>
	</head>
	<body>
		<script>
			// rest参数必须要放到参数最后
			function date(...args){
				// args与arguments不同是一个数组所以可以对其使用数组方法如filter等
				console.log(args);
			}
			date("Cao","Zhao","Jiang");
		</script>
	</body>
</html>

第13章 Promise

简介

Promise是JS中进行异步编程的新解决方案,旧方案是单纯的使用回调函数。从语法上来说Promise是一个构造函数,从功能上来说Promise对象用来封装一个异步操作并可以获取其成功或者失败的结果值。

简单案例

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title></title>
	</head>
	<body>
		<h2 class="page-header">Promise初体验</h2>
		<button class="btn btn-primary" id="btn">点击抽奖</button>
		<script>
			/*
				点击按钮 1s后显示是否中奖 中奖概率30%
				若中奖弹出 恭喜恭喜,奖品为10万RMB劳斯莱斯优惠劵
				未中奖弹出 再接再厉
			*/
			// 生成随机数
			let rand = (m,n) => Math.ceil(Math.random() * (n-m+1)) + m-1;
			// 获取元素对象
			const btn = document.querySelector('#btn');
			// 绑定单机事件
			btn.addEventListener('click',function(){
				// 传统实现
				// 设置定时器
				// setTimeout(() => {
				// 	// 从1到100中获取随机数字
				// 	let n = rand(1,100);
				// 	// 判断
				// 	if(n < 30){
				// 		alert("恭喜恭喜,奖品为10万RMB劳斯莱斯优惠劵");
				// 	}else{
				// 		alert("再接再厉");
				// 	}
				// }, 1000);
				
				// Promise实现
				// resolve 解决 函数类型的数据 成功调resolve
				// reject  拒绝 函数类型的数据 失败调reject
				const p = new Promise((resolve, reject) => {
					setTimeout(() => {
						// 从1到100中获取随机数字
						let n = rand(1,100);
						// 判断
						if (n <= 30) {
							resolve(); // 调完之后可以把Promise对象的状态设置为成功
						} else {
							reject(); // 调完之后可以把Promise对象的状态设置为失败
						}
					}, 1000);
				});
				// 调用then方法 第一个方法是成功之后的回调,第二个是失败之后的回调
				// p.then(() => {},() => {})
				p.then(() => {
					alert("恭喜恭喜,奖品为10万RMB劳斯莱斯优惠劵");
				},() => {
					alert("再接再厉");
				})
			});
		</script>
	</body>
</html>

案例进阶

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title></title>
	</head>
	<body>
		<h2 class="page-header">Promise初体验</h2>
		<button class="btn btn-primary" id="btn">点击抽奖</button>
		<script>
			/*
				点击按钮 1s后显示是否中奖 中奖概率30%
				若中奖弹出 恭喜恭喜,奖品为10万RMB劳斯莱斯优惠劵,您的中奖号码为xxx
				未中奖弹出 再接再厉,您的数字为xxx
			*/
			// 生成随机数
			let rand = (m,n) => Math.ceil(Math.random() * (n-m+1)) + m-1;
			// 获取元素对象
			const btn = document.querySelector('#btn');
			// 绑定单机事件
			btn.addEventListener('click',function(){
				// resolve 解决 函数类型的数据 成功调resolve
				// reject  拒绝 函数类型的数据 失败调reject
				const p = new Promise((resolve, reject) => {
					setTimeout(() => {
						// 从1到100中获取随机数字
						let n = rand(1,100);
						// 判断
						if (n <= 30) {
							resolve(n); // 调完之后可以把Promise对象的状态设置为成功
						} else {
							reject(n); // 调完之后可以把Promise对象的状态设置为失败
						}
					}, 1000);
				});
				// 调用then方法 第一个方法是成功之后的回调,第二个是失败之后的回调
				// p.then(() => {},() => {})
				p.then((value) => {
					alert("恭喜恭喜,奖品为10万RMB劳斯莱斯优惠劵,您的中奖号码为" + value);
				},(reason) => {
					alert("再接再厉,您的数字为" + reason);
				})
			});
		</script>
	</body>
</html>

封装AJAX请求

小案例

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title></title>
	</head>
	<body>
		<h2 class="page-header">Promise封装AJAX操作</h2>
		<button class="btn btn-primary" id="btn">点击发送AJAX请求</button>
		<script>
			// 接口地址 https://api.apiopen.top/getJoke
			// 获取元素对象
			const btn = document.querySelector('#btn');
			// 绑定单机事件
			btn.addEventListener('click',function(){
				// 传统使用
				// 创建对象
				// const xhr = new XMLHttpRequest();
				// // 初始化
				// xhr.open('GET','https://api.apiopen.top/getJoke');
				// // 发送
				// xhr.send();
				// // 处理响应结果
				// xhr.onreadystatechange = function(){
				// 	if(xhr.readyState === 4){
				// 		// 判断响应码
				// 		if(xhr.status >= 200 && xhr.status < 300){
				// 			// 控制台输出响应体
				// 			console.log(xhr.response);
				// 		}else{
				// 			// 控制台输出响应码
				// 			console.log(xhr.status);
				// 		}
				// 	}
				// }
				
				// Promise使用
				const p = new Promise((resolve,reject) => {
					const xhr = new XMLHttpRequest();
					// 初始化
					xhr.open('GET','https://api.apiopen.top/getJoke');
					// 发送
					xhr.send();
					// 处理响应结果
					xhr.onreadystatechange = function(){
						if(xhr.readyState === 4){
							// 判断响应码 2xx
							if (xhr.status >= 200 && xhr.status < 300) {
								resolve(xhr.response);
							} else {
								reject(xhr.status);
							}
						}
					}
				});
				p.then((value) =>{
					console.log(value);
				},(reason) => {
					console.log(reason);
				});
			});
		</script>
	</body>
</html>

封装AJAX请求

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title></title>
	</head>
	<body>
		<h2 class="page-header">Promise封装AJAX操作</h2>
		<button class="btn btn-primary" id="btn">点击发送AJAX请求</button>
		<script>
			function sendAJAX(url){
				return new Promise((resolve,reject) => {
					const xhr = new XMLHttpRequest();
					// 设置响应类型为JSON格式
					xhr.responseType = 'json';
					// 初始化
					xhr.open('GET',url);
					// 发送
					xhr.send();
					// 处理响应结果
					xhr.onreadystatechange = function() {
						if(xhr.readyState === 4){
							// 判断响应码 2xx
							if (xhr.status >= 200 && xhr.status < 300) {
								resolve(xhr.response);
							} else {
								reject(xhr.status);
							}
						}
					}
				});
			}
			sendAJAX('https://api.apiopen.top/getJoke')
			.then((value) =>{
				console.log(value);
			},(reason) => {
				console.log(reason);
			});
		</script>
	</body>
</html>

第14章 异步问题

并发|并行|异步|同步

并发:指计算机(一般是单核计算机)能够同时执行多项任务,一个任务执行一段时间然后执行另一段任务

并行:在不同的核心(多核)上真正并行地执行任务

同步:需要等到前一个任务执行完毕之后才会执行下一个

异步:不同的任务之间并不会相互等待,即可以同时运行任务A和任务B

异步实现方式

第一种:回调函数(CallBack)

// 让打印在3秒后再运行
setTimeout(() => { 
  console.log('兄弟你好!');
}, 3000)

const delayTime = 3000;
setTimeout(() => {
  console.log('兄弟你好!');
}, delayTime)
console.log('我会立刻执行哦!');

// 上面这段代码会先立刻打印出 '我会立刻执行哦!' 过三秒之后才会打印出 '兄弟你好!'
// 可以看出JavaScript并不像Java一样是同步的,而是异步的。

第二种:发送请求。即JavaScript代码遇到请求不会等请求响应之后再执行下方的代码。

Promise

JavaScript发送请求和使用setTimeout函数会出现异步的情况,其它都是同步的。有时候我们希望同步,传统的方式如下。

const delayTIme = 1000;
setTimeout(() => {
  console.log('1:');
  setTimeout(() => {
    console.log('2');
    setTimeout(() => {
      console.log('3');
    }, delayTIme)
  }, delayTIme)
}, delayTIme)
// 这会按顺序打印出 '1' '2' '3' 是同步的
// 但是如此写代码不够优雅,并且一直回调,此情况也被叫做函数的"回调地狱"

为了解决"回调地狱"问题Promise应运而生

fetch("https://...")
	.then((response) => response.json())
	.then((json) => console.log(json))
	.catch((error) =>{console.log(error)})
	.finally(() => {});
// fetch封装了Ajax,能发送网络请求,并且返回类型为Promise类型
// Promise有then方法,里面传递一个回调函数,如果请求成功完成,请求的响应数据会以参数的形式传递进来如上例中的response。此时我们可以链式调用then方法实现同步。上例中的第二个then方法参数接收的是第一个then方法中返回的数据。第二个then方法会等第一个then方法执行完毕之后再运行,如此就实现了同步。Promise还提供了catch方法捕捉错误,如果某一个then中出现了错误,会执行catch中的代码,并且之后的then都不会执行。finally和Java一样无论成功或失败都会在最后执行finally中的代码。

async | await

async和await是基于Promise上的语法糖。可以让异步操作更加简洁明了。

async function test() {
  const response = await fetch("https://...");
  const json = await response.json();
  console.log(json);
}
// 使用async标记函数为异步函数
// 异步函数就是返回值为Promise对象的函数
// 上例中使用await会让后面的代码执行完才会执行下一步

注意

async只能用于函数。await只能运用在async标记的函数内并且只能用于返回值是Promise类型的。

async function test() {
  await setTimeout(() => {
    console.log("TenSoFlow");
  }, 3000)
  console.log("Hello World!")
}
test();
// 这样写照样是异步的,会先打印'Hello World!'。因为await只能作用于返回值类型是Promise类型的。

// 下面给出正确的写法,只需将setTimeout包装成一个异步函数即可
async function test() {
  await new Promise(resolve => {
    setTimeout(() => {
      console.log("TenSoFlow");
      resolve(); // 完成时调用 resolve
    }, 3000);
  });
  console.log("Hello World!");
}
test();
评论
  • 按正序
  • 按倒序
  • 按热度
Powered by Waline v2.15.8