JavaScript基础知识初步掌握

文章目录

  • 一、前言
  • 二、基本语法
    • [2.1 注释](#2.1 注释)
    • [2.2 变量](#2.2 变量)
  • 三、数据类型
    • [3.1 基础数据类型](#3.1 基础数据类型)
    • [3.2 引用数据类型](#3.2 引用数据类型)
    • [3.3 运算符&表达式](#3.3 运算符&表达式)
    • [3.4 更多常用类型](#3.4 更多常用类型)
  • 四、流程控制
    • [4.1 条件语句](#4.1 条件语句)
    • [4.2 异常处理](#4.2 异常处理)
  • 五、循环迭代
    • [5.1 常用语句](#5.1 常用语句)
    • [5.2 其他用法](#5.2 其他用法)
  • 六、函数
    • [6.1 函数定义](#6.1 函数定义)
    • [6.2 函数参数](#6.2 函数参数)
    • [6.3 作用域&函数栈](#6.3 作用域&函数栈)
  • 七、对象
    • [7.1 概述](#7.1 概述)
    • [7.2 this](#7.2 this)
    • [7.3 原型](#7.3 原型)
    • [7.4 更多用法](#7.4 更多用法)
  • 八、类
  • 九、DOM
    • [9.1 概述](#9.1 概述)
    • [9.2 事件](#9.2 事件)
  • 十、BOM
    • [10.1 概述](#10.1 概述)
    • [10.2 核心对象](#10.2 核心对象)
    • [10.3 本地存储](#10.3 本地存储)
  • 十一、异步编程
    • [11.1 回调](#11.1 回调)
    • [11.2 异步](#11.2 异步)

一、前言

参考文档:https://developer.mozilla.org/zh-TW/docs/Web/JavaScript

https://www.w3schools.com/js/js_date_methods.asp

二、基本语法

2.1 注释

注释与其他许多语法都相似,分为单行注释和多行注释:

javascript 复制代码
// 单行注释

/*
多行注释
*/

|----------------------------------------------------------------------------------------------------------|
| 备注:在一些 JavaScript 脚本中有像#!/usr/bin/env node 的第三种注释。 这种注释称为hashbang注释,被用来指定执行 JaveScript 脚本的引擎的路径。 |

为避免出错,可使用严格模式来严格规范语法:

javascript 复制代码
'use strict';

2.2 变量

▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰变量的声明▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰

JavaScript有三种变量声明方式:不建议直接赋值,优先使用const

  1. var:可用于声明局部变量或者全局变量
  2. let:声明块级作用域的局部变量
  3. const:声明块级作用域的只读常量,不能改变值

也可以使用解构语法来声明变量:

javascript 复制代码
let a, b, rest;
[a, b] = [10, 20];

console.log(a);
// 期望输出:10

console.log(b);
// 期望输出:20

[a, b, ...rest] = [10, 20, 30, 40, 50];

console.log(rest);
// 期望输出:Array [30, 40, 50]

变量声明时如果没有初始化,会被赋值为undefined;但是使用const来声明时需要初始化,否则会报SyntaxError错误。

变量有多种作用域:

  1. 全局作用域:当前文档
  2. 函数作用域:函数内部
  3. 块级作用域:花括号里

变量提升:使用var声明的变量可以先使用后声明,但是它的值不会提升

javascript 复制代码
console.log(x === undefined); // true
var x = 3;

(function () {
  console.log(x); // undefined
  var x = "局部值";
})();

▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰变量的命名▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰

变量的命名规范:以字母、下划线或者美元符号开头,后续字符可以为数字;区分大小写,并使用Unicode字符集,以及不能与保留关键字同名:

  1. 驼峰命名规范:第一个单词首字母小写,其余单词首字母大写
  2. ruby风格的命名规范:单词之间使用_连接,每个单词都是小写

保留关键字:

三、数据类型

3.1 基础数据类型

▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰概述▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰

最新的 ECMAScript 标准定义了 8 种数据类型:

数据类型 描述
number 整数或浮点数
boolean true和false
null 表示空值
undefined 未定义值
bigint 任意精度的整数
string 字符序列
symbol 实例是唯一且不可变的数据类型

可使用typeof来判断变量类型:

javascript 复制代码
var a = "string"
console.log(typeof a)  //string

▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰类型转换▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰

使用+运算符的表达式中有数字和字符串,会把数字转换为字符串,举个栗子:

javascript 复制代码
x = "答案:" + 43 ;   // 答案:43

使用其他运算符时,不会将数字转换为字符串:

javascript 复制代码
"37" - 7; // 30

除此之外,还有一些方法也可以进行类型转换:

方法 描述
parseInt(string,radix) 默认将字符串解析为十进制整数,参数radix可选,表示进制的基数
String(x) 将x转换为字符串
Boolean(x)!!x 将x转换为布尔型
Number(x) 将x转换为Number类型,不能转换则返回NaN

▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰Number类型▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰

数字均为双精度浮点类型,数字精度为53位;除了表示浮点数,还能表示三种符号值:+Infinity正无穷、-Infinity负无穷、NaN非数字。

常用属性:

属性 描述
Number.MAX_VALUE 最大值
Number.MIN_VALUE 最小值
Number.NaN 非数字

常用方法:

方法 描述
Number.isNaN(value) value是否为NaN
Number.isInteger(value) value是否为整数

▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰String类型▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰

可以使用以下方式创建字符串:

javascript 复制代码
const string1 = new String("A String object");
const string2 = "A String object";

有两种方式访问字符:索引从0开始

javascript 复制代码
"cat".charAt(1); // "a"
"cat"[1]; // "a"

字符串的比较:区分大小写

javascript 复制代码
// 大于和小于
const a = "a";
const b = "b";
if (a < b) {
  // true
  console.log(`${a} 小于 ${b}`);
} 

字符串常用方法,更多方法参见https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/String

方法 描述
indexOf(searchString[, position]) 返回查询的字符第一次出现的位置索引,参数position指定搜索范围
replace(pattern, replacement) 将多个匹配的pattern被替换为replacement
substring(indexStart[, indexEnd]) 返回起始索引到结束索引(没有则字符串末尾)的部分,左开右闭
match(regexp) 使用正则检索字符串

模板字符串:ES6引入的一种新的字符串语法,使用反引号包裹内容,可以嵌入变量和表达式

javascript 复制代码
const name = "Alice";
const age = 25;
const message = `Name: ${name}, Age: ${age}`; // "Name: Alice, Age: 25"
const sum = `1 + 2 = ${1 + 2}`;               // "1 + 2 = 3"

3.2 引用数据类型

|----------------|
| 引用数据类型保存的是内存地址 |

▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰数组类型▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰

数组创建:可以使用以下方法来创建一个数组:

javascript 复制代码
// 构造函数
const arr1 = new Array(1,2,3); //[1,2,3]

// 字面量
const arr2 = [1,2,3];//[1,2,3]

// ES6新增方法
const arr3 = Array.from("hello")// ["h", "e", "l", "l", "o"](类数组转数组)
const arr4 = Array.of(3)// [3](避免单个数值的歧义)

如果要创建长度不为0,但又没有任何元素的数组:arrayLength需要为整数

javascript 复制代码
const arr1 = new Array(arrayLength);
// 或者
const arr3 = [];
arr3.length = arrayLength;

元素访问与修改:索引从0开始

javascript 复制代码
// 索引访问
let arr =[1,2,3];
console.log(arr[0]); // 1

// 展开运算符
let sparseArr = [1, ,3];
console.log([...sparseArr]); // [ 1, undefined, 3 ]

// 元素修改
arr[1]=20
arr[5]=4; // 动态扩展,如果中间索引未定义则为空值
console.log(arr) // [ 1, 20, 3, <2 empty items>, 4 ]

数组属性: length统计数组元素数量,如果给length赋值,会截断数组:

javascript 复制代码
const cats = ["Dusty", "Misty", "Twiggy"];
console.log(cats.length); // 3

cats.length = 2;
console.log(cats); // [ 'Dusty', 'Misty' ] - Twiggy 已经被移除了

cats.length = 0;
console.log(cats); // 输出 [],猫名称的数组现在已经空了

cats.length = 3;
console.log(cats); // 输出 [ <3 empty items> ]

数组遍历 :可使用循环、forEachmap函数;forEachmap函数的区别在于map函数会返回一个新数组。

javascript 复制代码
const colors = ["red", "green", "blue"];
// 普通循环
for (let i = 0; i < colors.length; i++) {
  console.log(colors[i]);
}
// for... of
for (let color of colors){
  console.log(color)
}

// map方法
colors.map((color) => console.log(color));

// forEach方法
colors.forEach((color) => console.log(color));

forEach函数 :格式为forEach(callbackFn[,thisArg]);参数callbackFn为数组中每个元素执行的函数,并会丢弃它的返回值,该函数被调用时会传入以下参数:

  1. element:数组中正在处理的当前元素
  2. index:数组中正在处理的当前元素的索引
  3. array:调用了forEach的数组

thisArg:执行callbackFn时用作this的值

forEach返回值为undefined,具体参考:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach

数组常见方法一览:

常见方法 描述
concat([value...]) 连接两个数组或多个数组并返回一个新的数组
join([separator]) 将数组中的所有元素连接成一个字符串,separator指定分隔数组元素的字符串
push([element...]) 末尾添加元素,并返回length属性
pop() 移除最后一个元素,并返回该元素
shift() 移除第一个元素,并返回该元素
sort([compareFn]) 对元素进行排序,并返回对数组的引用;compareFn定义排序顺序的函数
indexof(searchElement[,fromIndex]) 搜索searchElement并返回第一个匹配的索引,fromIndex为开始搜索的索引,默认从0开始

▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰Map映射类型▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰

map与object相似,但也有一些区别:map的key可以为任何类型;map没有默认的键

常用方法 描述
new Map() 创建map对象
set(key,value) 存储数据
get(key) 获取指定键的元素
size() 返回键值对数量
clear() 移除所有键值对
delete(key) 删除指定键的元素,如果元素存在且被移除返回true
has(key) 判断指定键的元素是否存在

map的迭代可以使用for...of或者forEach()

javascript 复制代码
const myMap = new Map();
myMap.set(0, "zero");
myMap.set(1, "one");

for (const [key, value] of myMap) {
  console.log(`${key} = ${value}`);
}
// 0 = zero
// 1 = one

for (const key of myMap.keys()) {
  console.log(key);
}
// 0
// 1

for (const value of myMap.values()) {
  console.log(value);
}
// zero
// one

for (const [key, value] of myMap.entries()) {
  console.log(`${key} = ${value}`);
}
// 0 = zero
// 1 = one

myMap.forEach((value,key)=>{
  console.log(`${key} = ${value}`);
}) 

map的复制或合并:数据本身未被克隆

javascript 复制代码
const original = new Map([[1, "one"]]);

const clone = new Map(original);

console.log(clone.get(1)); // one
console.log(original === clone); // false. 浅比较 不为同一个对象的引用

▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰Set集合▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰

集合的值是唯一的,只能出现一次,值可以是任何类型。集合只有一个属性length

集合的基本方法:

方法 描述
new Set() 创建新集合
add() 添加新元素
clear() 删除所有元素
delete() 删除一个元素
entries() 返回一个迭代器,每次迭代会返回[value,value]的键值对
has() 判断值是否存在
keys() values()一样
values() 可以遍历集合中所有元素

集合还可以像数学集合一样进行运算:

3.3 运算符&表达式

▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰概述▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰

以下是一些常用的运算符,更多见https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Guide/Expressions_and_operators

运算符 描述
赋值运算符 =+=-=*=/=%=**=
比较运算符 ==!====!===><>=<=
算数运算符 %++---+**
位运算符 &、`
逻辑运算符 &&、`
字符串运算符 连接运算符+
条件运算符 条件 ? 值1:值2
逗号运算符 ,,从左到右求值,并返回最后一个操作数的值
一元运算符 deletetypeofin
关系运算符 ininstanceof

运算符优先级,从高到低:

▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰更多细节▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰

比较运算符中的 == === ==是值相等,而===是值相等且类型也相同。

算数运算符中的自增与自减 :如果++在操作数前(++x),则返回+1后的值;如果是在后面,则返回操作数原值再+1;自减也同理。

短路求值:逻辑表达式进行求值是从左到右,使用以下规则:

javascript 复制代码
false && anything // 被短路求值为 false
true || anything // 被短路求值为 true

ininstanceofin操作符指如果指定属性在指定对象里会返回true;insatnceof则是判断对象是否是指定的类型,是则返回true

javascript 复制代码
// in 的使用
var trees = new Array("redwood", "bay", "cedar", "oak", "maple");
0 in trees; // true
3 in trees; // true
6 in trees; // false

// instanceof 的使用
var theDay = new Date(1995, 12, 17);
if (theDay instanceof Date) {
  console.log("yes")  // yes
}

3.4 更多常用类型

▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰数学对象▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰

数学对象Math没有构造函数,他是静态的。Math有8个数学属性:

javascript 复制代码
Math.E      // 欧拉数
Math.PI     // 圆周率
Math.SQRT2  //2的平方根
Math.SQRT1_2  // 1/2的平方根
Math.LN2    // 2的自然对数
Math.LN10   // 10的自然对数
Math.LOG2E  // 2为底E的对数
Math.LOG10E  // 10为底E的对数

常用方法一览:

随机数的常用方法:

javascript 复制代码
// 返回随机整数 0-9
Math.floor(Math.random() * 10)

// 返回最小值和最大值之间的随机数,不包括最大值
function getRndInteger(min,max){
  return Math.floor(Math.random() * (max - min) ) + min
}

// 返回最小值和最大值之间的随机数
function getRndInteger(min,max){
  return Math.floor(Math.random() * (max - min + 1) ) + min
}

▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰日期对象▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰

Date 对象的范围是相对距离 UTC 1970 年 1 月 1 日 的前后 100,000,000 天

javascript 复制代码
// 创建日期对象
var dateObjectName = new Date([parameters]);

不使用关键词new会返回当前时间和日期的字符串,参数parameters有多种选择:

Date对象方法可以分为以下几种:

方法 描述
set 设置日期和时间
get 获取日期和时间
to 返回字符串格式
parse和UTC 解析Date字符串

获取日期的方法:

时间戳获取:

javascript 复制代码
// 使用getTime方法
const date = new Date()
console.log(date.getTime())
// +new Date()
console.log(+new Date())
// Date.now():只能获取当前时间戳
console.log(Date.now())

四、流程控制

4.1 条件语句

JavaScript支持两种条件语句:if...elseswitch

condition 可以是任何能求值为truefalse的表达式,false值包括:falseundefinednull0NaN、空字符串;其他则为true

javascript 复制代码
if (condition1) 
{
  statement1;
} 
else if (condition2)
{
  statement2;
}
else {
  statement3;
}

switch语句:

javascript 复制代码
switch (expression) {
  case label1:
    statements1;
    break;
  case label2:
    statements2;
    break;
  // ...
  default:
    statementsDefault;
}

4.2 异常处理

通常使用throw抛出异常,并用try...catch来处理异常

throw可以抛出任意表达式

javascript 复制代码
throw "错误 2"; // 字符串类型
throw 42; // 数字类型
throw true; // 布尔类型
throw {
  toString() {
    return "我是一个对象";
  },
};

try...catch语句:使用try来执行可能会有异常的操作,catch来捕获异常,无论是否出错都要执行finallyfinally语句可不写。

javascript 复制代码
openMyFile();
try {
  writeMyFile(theData); // 这可能会抛出错误
} catch (e) {
  handleError(e); // 如果错误出现了,处理它
} finally {
  closeMyFile(); // 总是关闭资源
}

可以使用namemessage属性来获取error对象详细信息:

javascript 复制代码
function doSomethingErrorProne() {
  if (ourCodeMakesAMistake()) {
    throw new Error("消息");
  } else {
    doSomethingToGetAJavaScriptError();
  }
}

try {
  doSomethingErrorProne();
} catch (e) {
  // 现在,实际使用 `console.error()`
  console.error(e.name); // 'Error'
  console.error(e.message); // "消息",或者一个 JavaScript 错误消息
}

有六种错误类型:

错误 描述
EvalError eval()函数发生错误
RangeError 数字超出范围
ReferenceError 非法引用(未声明的变量或对象属性/方法)
SyntaxError 语法错误
TypeError 类型错误
URIError encodeURI()发生错误

五、循环迭代

5.1 常用语句

💫for语句:基本格式如下所示,与C的for循环很相似:

javascript 复制代码
for ([initialExpression]; [condition]; [incrementExpression])
  statement

💫while语句:每次执行前会检查是否满足条件

javascript 复制代码
while (condition)
  statement

💫do while:在检查条件时会先执行一次,基本格式如下所示:

javascript 复制代码
do
  statement
while (condition);

💫label语句:可以标记语句(块)

javascript 复制代码
label :
   statement

label的值可以是任何非保留字的标识符,举个栗子:

javascript 复制代码
var num = 0;
outPoint: for (var i = 0; i < 10; i++) {
  for (var j = 0; j < 10; j++) {
    if (i == 5 && j == 5) {
      break outPoint; // 在 i = 5,j = 5 时,跳出所有循环,
      // 返回到整个 outPoint 下方,继续执行
    }
    num++;
  }
}

alert(num); // 输出 55

💫break:终止循环、switch语句或者链接label语句,

  • 如果不带label,会终止当前循环
  • 如果带label,会终止指定的带标记的语句
javascript 复制代码
break [label];

💫continue:继续执行下一个循环、switch语句或者label语句,

  • 如果不带label,会跳过当前循环
  • 如果带label,会执行带标记的语句
javascript 复制代码
continue [label];

5.2 其他用法

💫for...in:循环一个指定的对象来循环一个对象所有可枚举的属性

javascript 复制代码
for (variable in object) {
  statements
}

💫for...of:循环一个可迭代对象,例如数组

javascript 复制代码
for (variable of object) {
  statement
}

用代码来展示两者之间的区别:

javascript 复制代码
let arr = [3, 5, 7];
arr.foo = "hello";

for (let i in arr) {
  console.log(i); // 输出 "0", "1", "2", "foo"
}

for (let i of arr) {
  console.log(i); // 输出 "3", "5", "7"
}

// 注意 for...of 的输出没有出现 "hello"

六、函数

6.1 函数定义

▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰函数定义▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰

一般函数 :通过function关键词来声明函数;name函数名、param参数、statements声明语句。如果函数没有return,则默认返回undefined

javascript 复制代码
function name([param[, param[, ... param]]]) { 
  statements 
}

函数表达式 :与函数声明非常相似,区别在于name可以省略,省略后就成了匿名函数;

|-----------------------------------------------|
| 一些注意点:不能在函数定义之前调用;如果函数命名了,堆栈跟踪时会显示函数名,容易找到错误。 |

javascript 复制代码
var myFunction = function name([param[, param[, ... param]]]) { 
  statements 
}

IIFE:函数只使用一次

javascript 复制代码
(function () {
  statements;
})();

函数生成器:创建一个绑定到给定名称的新生成器函数,生成器函数可以退出,并在稍后重新进入,其上下文(变量绑定)会在重新进入时保存。

javascript 复制代码
function* name([param[, param[, ...param]]]) { 
  statements 
}

举个栗子:

javascript 复制代码
function* generator(i) {
  yield i;
  yield i + 10;
}

const gen = generator(10);

console.log(gen.next().value);
// 10

console.log(gen.next().value);
// 20

箭头函数表达式 :比传统的函数表达式更简洁,但不能用作构造函数,也不能使用yield,且没有this、arguments等,具体参考:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Functions/Arrow_functions

javascript 复制代码
([param] [, param]) => { statements } 

一些注意点:

javascript 复制代码
// 只有当函数只有一个简单参数时,才能省略括号
const bob1 = (a) => a + 100;
console.log(bob1(12)); // 输出: 112

const bob2 = a => a + 100;
console.log(bob2(12)); // 输出: 112

// 只有当函数直接返回表达式时,才可以省略大括号;
const bob3 = (a, b) => a + b + 100;
console.log(bob3(1, 2)); // 输出: 103

const bob4 = (a, b) => {
  const chuck = 42;
  return a + b + chuck;
};
console.log(bob4(1, 2)); // 输出: 45

// 只需指定一个表达式,将成为隐式返回值
const func = (x) => x * x;
const func2 = (x, y) => {
  return x + y;
};   // 块体语法,需要明确返回值

// 返回字面量表达式
const fun1 = (uname) => ({ uname: uname }); 
console.log(fun1('Jack')); // 输出: { uname: 'Jack' }

▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰函数构造▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰

可使用new操作符创建function对象:arg1, arg2, ... argN参数;functionBody函数体

javascript 复制代码
new Function (arg1, arg2, ... argN, functionBody)

生成器构造函数:

javascript 复制代码
new GeneratorFunction (arg1, arg2, ... argN, functionBody)

▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰内置函数▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰

常用的有evalparseInt

6.2 函数参数

▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰默认参数▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰

函数默认参数为undefined,也可以自定义。

javascript 复制代码
function [name]([param1[ = defaultValue1 ][, ..., paramN[ = defaultValueN ]]]) {
    statements
}

注意,不能将非默认参数位于默认参数之后,可能会导致未在预期范围的输出:

javascript 复制代码
function f(x = 1, y) {
  return [x, y];
}

f(); // [1, undefined]
f(2); // [2, undefined]

▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰剩余参数▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰

如果函数的最后一个命名参数以...为前缀,则它将成为一个由剩余参数组成的真数组,其中从0(包括)到theArgs.length(排除)的元素由传递给函数的实际参数提供。即剩余参数只包含那些没有对应形参的实参

javascript 复制代码
function(a, b, ...theArgs) {
  // ...
}

举个栗子来更好的理解他:

javascript 复制代码
function fun1(...theArgs) {
  alert(theArgs.length);
}

fun1(); // 弹出 "0", 因为 theArgs 没有元素
fun1(5); // 弹出 "1", 因为 theArgs 只有一个元素
fun1(5, 6, 7); // 弹出 "3", 因为 theArgs 有三个元素

function f(...[a, b, c]) {
  return a + b + c;
}

f(1); // NaN (缺少两个参数b和c)
f(1, 2, 3); // 6
f(1, 2, 3, 4); // 6 (没有第四个元素)

▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰arguments对象▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰

对应于传递给函数的参数的类数组对象,除了length属性和索引元素之外没有其他数组属性。

javascript 复制代码
function func1(a, b, c) {
  console.log(arguments[0]);
  // 1

  console.log(arguments[1]);
  // 2

  console.log(arguments[2]);
  // 3
}

func1(1, 2, 3);

也可以通过索引赋值:

javascript 复制代码
arguments[1]=4

6.3 作用域&函数栈

▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰递归▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰

递归就是函数自己调用自己,有三种方式:

javascript 复制代码
// 函数名
function loop(x) {
  if (x >= 10) {
    return;
  }
  loop(x + 1); 
}

// arguments.callee :不推荐使用
function create() {
  return function (n) {
    if (n <= 1) {
      return 1;
    }
    return n * arguments.callee(n - 1);
  };
}
const result = create()(5); // 返回 120(5 * 4 * 3 * 2 * 1)

// 作用域内一个指向该函数的变量名

▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰闭包▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰

内部函数对外部函数是私有的,内部函数只可以在外部函数中访问,内部函数可以访问外部函数的参数和变量,但是外部函数不能使用内部函数的参数和变量。

javascript 复制代码
function addSquares(a, b) {
  function square(x) {
    return x * x;
  }
  return square(a) + square(b);
}
console.log(addSquares(2, 3)); // 13
console.log(addSquares(3, 4)); // 25

如果内部函数定义了一个和外部的某个变量名称相同的变量,那么这个闭包将无法引用外部作用域中的这个变量。以下程序就是错误的

javascript 复制代码
const createPet = function (name) {
  // 外部函数定义了一个名为"name"的变量。
  return {
    setName(name) {
      // 闭包函数还定义了一个名为"name"的变量。
      name = name; 
    },
  };
};

七、对象

7.1 概述

对象是以key-value键值对的形式存在的集合,与python字典类型相似。key必须是字符串类型或者symbol类型,值可以是任意类型。

对象分为实例成员和静态成员,实例对象是通过构造函数创建的对象,他的属性和方法称为实例成员;静态成员是构造函数的属性和方法。

对象的创建方式:

javascript 复制代码
// 字面量
const person1 = {
  name: "Alice",
  age: 23,
  greet() {
    console.log(`Hello, I'm ${this.name}`);
  }
};

// 构造函数
const person2 = new Object();
person2.name = "Alice";
person2.age=23;
person2.greet = function() { console.log(`Hello, I'm ${this.name}`};

function Car(make, model, year) {
  this.make = make;         
  this.model = model;
  this.year = year;
}
var mycar = new Car("Eagle", "Talon TSi", 1993);
// var mycar.nationality = "English" 报错,不能向现有构造函数添加新属性

// ES6语法
class User{
  constructor(name){
    this.name=name;
  }
  greet(){
    console.log(`Hello, I'm ${this.name}`
  }
}
const person3 = new User("Alice")

对象属性常用操作:

javascript 复制代码
const person = {
  name: "Alice",
  age: 23,
  greet() {
    console.log(`Hello, I'm ${this.name}`);
  }
};
// 访问属性
person.name
person["name"]

// 修改属性
person.job = "Engineer"  //添加属性
person.age = 26;  //修改属性

// 删除属性
delete person.job;  //成功则返回true

// 检查属性是否存在
"name" in person;  //true(包括原型链)
person.hasOwnProperty("name");  //true(仅自身属性)

// 遍历属性
for (const property in person){
  console.log(person[property])
}
console.log(Object.getOwnPropertyNames(person))

常用静态方法,只有Object可以调用

方法 描述
keys(obj) 获取对象中所有属性(键),返回的是数组
values(obj) 获取对象中的所有属性值
assign(target,source) 常用于对象拷贝
entries(obj) 返回键值对数组
fromEntries(obj) 根据键值对列表创建一个对象

7.2 this

默认情况下this指向全局对象,如window;

javascript 复制代码
let x = this;

在函数中this引用全局对象;但是在严格模式下,this是undefined

javascript 复制代码
function myFunction() {
  return this;
}

在对象方法中,this引用该对象;

javascript 复制代码
const person = {
  firstName  : "John",
  lastName   : "Doe",
  id         : 5566,
  myFunction : function() {
    return this;
  }
};

在事件中,this指接收事件的元素

javascript 复制代码
<button onclick="this.style.display='none'">
  Click to Remove Me!
</button>

除此之外,可以通过callapplybind指定this

call方法是预定义的JavaScript方法,可以用于对象作为参数来调用方法

javascript 复制代码
const person = {
  fullName: function(city, country) {
    return this.firstName + " " + this.lastName + "," + city + "," + country;
  }
}

const person1 = {
  firstName:"John",
  lastName: "Doe"
}

person.fullName.call(person1, "Oslo", "Norway"); //

apply方法与call方法类似,区别在于apply以数组的形式接收参数

javascript 复制代码
const person = {
  fullName: function(city, country) {
    return this.firstName + " " + this.lastName + "," + city + "," + country;
  }
}

const person1 = {
  firstName:"John",
  lastName: "Doe"
}

person.fullName.apply(person1, ["Oslo", "Norway"]);

bind方法可以让一个对象从另一个对象中借用方法

javascript 复制代码
const person = {
  firstName:"John",
  lastName: "Doe",
  fullName: function () {
    return this.firstName + " " + this.lastName;
  }
}

const member = {
  firstName:"Hege",
  lastName: "Nilsen",
}

let fullName = person.fullName.bind(member);

7.3 原型

▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰原型▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰

所有JavaScript对象都从原型继承属性和方法,例如Data对象继承自Date.prototype、Array对象继承自Array.prototype Object.prototype位于原型继承链的顶端

可以使用prototype属性来向对象构造函数添加新属性或者新方法:

javascript 复制代码
function Person(first, last, age, eyecolor) {
  this.firstName = first;
  this.lastName = last;
  this.age = age;
  this.eyeColor = eyecolor;
}

Person.prototype.nationality = "English";
Person.prototype.name = function() {
  return this.firstName + " " + this.lastName;
};

▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰原型链▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰

访问一个对象的属性时会先在自身属性中查找,如果没有找到会沿着__proto__这条链向上查找,还是没找到则返回undefined,这就是原型链,又称隐式原型链,它的作用就是查找对象的属性(方法)。

javascript 复制代码
const parent = { a: 1 };
const child = Object.create(parent);
child.b = 2;
console.log(child.a); // 1(通过原型链访问)

7.4 更多用法

▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰属性描述符▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰

属性描述符可以用来控制行为

控制属性行为有:writable可写、enumerable可枚举、configurable可配置

javascript 复制代码
const obj = {};
Object.defineProperty(obj, "id", {
  value: 123,
  writable: false,    // 不可修改
  enumerable: true,   // 可枚举(出现在 for-in 循环中)
  configurable: false // 不可删除或重新配置
});

// 获取描述符
const descriptor = Object.getOwnPropertyDescriptor(obj, "id");

访问器属性可通过getset定义属性的读写逻辑

javascript 复制代码
const obj = {counter : 0};

Object.defineProperty(obj, "reset", {
  get : function () {this.counter = 0;}
});
Object.defineProperty(obj, "increment", {
  get : function () {this.counter++;}
});
Object.defineProperty(obj, "decrement", {
  get : function () {this.counter--;}
});
Object.defineProperty(obj, "add", {
  set : function (value) {this.counter += value;}
});
Object.defineProperty(obj, "subtract", {
  set : function (value) {this.counter -= value;}
});

obj.reset;
obj.add = 5;
obj.subtract = 1;
obj.increment;
obj.decrement;

▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰访问器▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰

JavaScript使用GettersSetters来定义对象访问器,它们可以确保更好的数据质量

javascript 复制代码
const person = {
  firstName: "John",
  lastName: "Doe",
  language: "en",
  get lang() {
    return this.language;
  }
  set lang(lang) {
    this.language = lang;
  }
};

person.lang = "en";
document.getElementById("demo").innerHTML = person.lang;

▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰对象保护▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰

Object.preventExtensions()方法可防止向对象添加属性,可使用Object.isExtensible()来检查对象是否可扩展。

javascript 复制代码
const person = {firstName:"John", lastName:"Doe"};

Object.preventExtensions(person);

person.nationality = "English";  // 会报错
let answer = Object.isExtensible(person); // false

object.seal()方法可防止添加或删除属性,可使用Object.isSealed()来检查对象是否被密封。

javascript 复制代码
"use strict"
const person = {
  firstName: "John",
  lastName: "Doe",
  age: 50,
  eyeColor: "blue"
};

Object.seal(person)

delete person.age;  // 报错
let answer = Object.isSealed(person)  // true

object.freeze()方法可防止对对象进行修改,可使用Object.isFrozen()来检查对象是否被冻结。

javascript 复制代码
"use strict"
const person = {
  firstName: "John",
  lastName: "Doe",
  age: 50,
  eyeColor: "blue"
};

Object.freeze(person)

person.age = 51;   // 报错
let answer = Object.isFrozen(person)  //true

▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰对象拷贝▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰

对象的拷贝分为深浅拷贝

浅拷贝:只复制对象内存地址,类似指针,例如obj2=obj1

深拷贝:完全克隆,生成一个新对象obj3=JSON.parse(JSON.stringify(obj))

八、类

|------------------------|
| 类不是对象,是JavaScript对象的模板 |

创建类:总是添加constructor方法,类似于python中的__init__方法

javascript 复制代码
class Car {
  constructor(name, year) {
    this.name = name;
    this.year = year;
  }
}

类继承:使用extends关键词,会继承父类的所有方法,super方法引用父类

javascript 复制代码
class Car {
  constructor(brand) {
    this.carname = brand;
  }
  present() {
    return 'I have a ' + this.carname;
  }
}

class Model extends Car {
  constructor(brand, mod) {
    super(brand);
    this.model = mod;
  }
  show() {
    return this.present() + ', it is a ' + this.model;
  }
}

let myCar = new Model("Ford", "Mustang");
document.getElementById("demo").innerHTML = myCar.show();

类也可以使用getterssetters,注意getter/setter方法的名称不能与属性的名称相同,可以在属性名前使用下划线

javascript 复制代码
class Car {
  constructor(brand) {
    this.carname = brand;
  }
  get cnam() {
    return this.carname;
  }
  set cnam(x) {
    this.carname = x;
  }
}

const myCar = new Car("Ford");

document.getElementById("demo").innerHTML = myCar.cnam;

静态类方法属于类本身,而不是类的实例,必须通过类名来调用,而不能通过实例来调用。

javascript 复制代码
class Car {
  constructor(name) {
    this.name = name;
  }
  static hello() {
    return "Hello!!";
  }
}

const myCar = new Car("Ford");

document.getElementById("demo").innerHTML = Car.hello();

// document.getElementById("demo").innerHTML = myCar.hello();
// 报错

九、DOM

9.1 概述

DOM是用来呈现以及与任意 HTML 或 XML文档交互的API。当网页加载时,浏览器会创建页面的DOM树:

基本对象类型:

数据类型 描述
document 任何在浏览器中载入的网页,并作为网页内容的入口
node 文档中的每个对象
element 一个元素或由dom api成员返回的element类型的节点
nodelist 元素组成的节点列表
attr 元素的属性
namednodemap

document对象常用方法:https://developer.mozilla.org/zh-CN/docs/Web/API/Document#方法

方法 描述
querySelector(selectors) 返回文档中与指定选择器或选择器组匹配的第一个element对象
querySelectorAll(selectors) 返回与指定的选择器组匹配的文档中的元素列表对象NodeList
createElement(tagName[,options]) 创建一个由标签名称tagName指定的HTML元素;options参数可选,是包含一个属性名为is的对象
getElementById(id) 返回匹配id属性的element对象

element常用属性:

属性 描述
innerText 文字内容,不解析标签
innerHTML 文本内容,解析标签
href 链接
title 标题
src 图片链接
style.样式属性 CSS样式
className 类名,修改类名时会覆盖先前的值
classList 类名,修改类名时不会覆盖先前的值

在html5中有专门的data-自定义属性,在DOM对象上一律以dataset对象方式获取:

javascript 复制代码
<body>
  <div class="box" data-id="10">1</div>
  <script>
    const box=document.querySelector('.box')
    console.log(box.dataset.id)
  </script>
</body>

9.2 事件

▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰事件监听▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰

事件监听三要素:事件源(谁)、事件类型(方式)、事件调用的函数(做什么);

语法:元素对象.addEventListener('事件类型',要执行的函数)

事件监听版本:区别在于on方式会被覆盖,而addEventListener可绑定多次,推荐使用。

  1. DOM L0:事件源.on事件=function(){}
  2. DOM L2:事件源.addEventListener(事件,事件处理函数)

事件类型:

鼠标事件:click、mouseenter、mouseleave、mouseover、mouseout

💡mouseover、mouseout有冒泡效果;而mouseenter、mouseleave没有

焦点事件:focus、blur

键盘事件:keydown、keyup

剪切板事件:copy、cut、paste

页面加载事件:load、DOMContentLoaded

💡load:页面所有资源(外部资源,比如图片、视频)加载完毕;DOMContentLoaded:页面DOM加载完毕

事件对象:事件触发时的相关信息;一般命名为eventeve

示例:元素.addEventListener('click',function(e){})

常用属性 描述
type 事件类型
clientX/clientY 获取光标相对于浏览器可见窗口左上角的位置
offsetX/offsetY 获取光标相对于当前DOM元素左上角的位置
key 用户按下的键盘键的值,不推荐使用keyCode
target 触发事件的元素
currentTarget 绑定事件的元素

▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰事件流▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰

事件流是指事件完整执行过程中的流动路径,有两个阶段:捕获阶段、冒泡阶段(实际工作都是使用事件冒泡为主)

1️⃣事件捕获:从DOM根元素开始执行对应的事件,较少使用捕获机制;L0事件监听则只有冒泡阶段;

示例:DOM.addEventListener(事件类型,事件处理函数,是否使用捕获机制)

2️⃣事件冒泡:依次向上调用所有父级元素;默认存在

3️⃣阻止冒泡:把 事件限制在当前元素内,就需要阻止事件冒泡

javascript 复制代码
事件对象.stopPropagation(),此方法对捕获阶段也有效
事件对象.preventDefault(),阻止元素默认行为,比如阻止链接的跳转

4️⃣解绑事件:

javascript 复制代码
// on事件方式直接使用null覆盖
事件对象.onclick=null

// addEventListener方式
// 注意:匿名函数无法被解绑
removeEventListener(事件类型,事件处理函数,[获取捕获或者冒泡阶段])

▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰事件委托▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰

事件委托是利用事件流的特征解决一些开发需求的知识技巧,利用事件冒泡的特点给父元素注册事件。

语法:事件对象.target.tagName

javascript 复制代码
const ul = document.querySelector('ul')
ul.addEventListener('click',function(e){
  if (e.target.tagName === 'LI'){
    this.style.color = 'pink'
  }
})

十、BOM

10.1 概述

浏览器对象模型BOM是浏览器提供的与当前窗口或标签页交互的对象集合,用于操作浏览器窗口本身的行为(如导航、窗口尺寸、历史记录等)。

10.2 核心对象

window对象是BOM的顶层对象,所有全局变量和函数都是window的属性和方法

窗口控制:

javascript 复制代码
window.open("https://example.com");   // 打开新窗口
window.close();                       // 关闭当前窗口(需用户允许)
window.resizeTo(800, 600);           // 调整窗口尺寸

弹出框:

javascript 复制代码
window.alert("sometext")   // 警告框
window.confirm("sometext")  // 确认框
window.prompt("sometext","defaultText")   // 提示框

延时器: setTimeout可以用来让代码延迟执行,仅执行一次;格式:setTimeout(回调函数,等待的毫秒数)

定时器 :能够重复执行代码;开启定时器let 变量名 = setInterval(函数,间隔的时间),单位是毫秒;关闭定时器clearInterval(变量名),满足一定时间后停止

javascript 复制代码
const timeoutId = setTimeout(() => {}, 1000); // 单次定时
const intervalId = setInterval(() => {}, 1000); // 循环定时
clearTimeout(timeoutId);              // 清除定时器

location对象拆分并保存了URL地址的各个组成部分

属性/方法 描述
href 用于地址的跳转
search 获取地址中携带的参数,?后的参数
hash 获取地址中的哈希值,#后的参数
reload() 刷新当前页面,传入true表示强制刷新

navigator对象记录了浏览器自身的相关信息

属性/方法 描述
userAgent 浏览器版本及平台
platform 操作系统
language 浏览器语言
cookieEnabled 是否启用cookie

screen对象记录了浏览器屏幕信息

属性/方法 描述
width 屏幕宽度(像素)
height 屏幕高度
availWidth 可用宽度(扣除任务栏等)

history对象记录了浏览器历史记录操作

属性/方法 描述
back(step) 后退step步
forward(step) 前进step步
go(参数) 前进后退,参数为正前进;参数为负后退

10.3 本地存储

特点:

  1. 数据存储在用户浏览器中
  2. 设置、读取方便、甚至页面刷新不丢失数据
  3. 容量较大,sessionStorage和localStorage约5M左右

分类:本地存储可以分为localStoragesessionStorage

💫localStorage:可以将数据永久存储在本地(用户的电脑),除非手动删除;可以多页面共享,以键值对的形式使用

方法 描述
setItem(key,value) 存储数据
getItem(key) 获取数据
removeItem(key) 删除数据

💫sessionStorage:生命周期为关闭浏览器窗口;同一界面下可以共享;键值对存储,用法跟localStorage基本相同。

补充:由于本地只能存储字符串,就引出了存储复杂数据类型的问题

解决:JSON.stringify(复杂数据类型)

但是又会有一个问题,无法直接修改对应的数据

解决:JSON.parse(JSON字符串)

十一、异步编程

11.1 回调

回调是作为参数传递给另一个函数的函数,myDisplayer就是回调函数,函数作为参数传递时,不要使用括号。

javascript 复制代码
function myDisplayer(some) {
  document.getElementById("demo").innerHTML = some;
}

function myCalculator(num1, num2, myCallback) {
  let sum = num1 + num2;
  myCallback(sum);
}

myCalculator(5, 5, myDisplayer);

11.2 异步

▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰概述▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰

回调通常与异步一起使用;通过回调函数实现异步,异步任务会添加到任务队列中;异步任务有三种类型:

任务 描述
普通事件 如click、resize
资源加载 如load、error
定时器 如setInterval、setTimeout

▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰Promise对象▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰

可以用Promise对象来实现异步编程,Promise对象有两种属性:state和result,注意它们是无法访问的,必须使用Promise方法来处理promise

Promise使用示例:异步操作成功时会传回value,异步操作失败时会传回error

javascript 复制代码
let myPromise = new Promise(function(myResolve, myReject) {
  myResolve(); // 操作成功时执行
  myReject();  // 操作失败时执行
});

myPromise.then(
  function(value) { /* 状态为fulfilled时执行 */ },
  function(error) { /* 状态为rejected时执行 */ }
);

▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰async▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰

async通常与await结合使用,async使函数返回一个Promise,await使函数等待Promise

javascript 复制代码
async function myFunction() {
  return "Hello";
}
myFunction().then(
  function(value) {myDisplayer(value);}
);

await关键字只能在async函数内部使用,他会让函数暂停执行,直到资源准备完毕。

javascript 复制代码
async function myDisplay() {
  let myPromise = new Promise(function(resolve) {
    setTimeout(function() {resolve("I love You !!");}, 3000);
  });
  document.getElementById("demo").innerHTML = await myPromise;
}

myDisplay();
相关推荐
Mintopia几秒前
Three.js高效几何体创建指南:BufferGeometry深度解析
前端·javascript·three.js
Mintopia8 分钟前
vue3 element-plus 二次封装Drawer抽屉,关闭时添加二次对话,开箱即用
前端·javascript·vue.js
stanny10 分钟前
Terminal里的ChatGPT:用80行代码实现带记忆的智能对话流
javascript
东京老树根12 分钟前
SAP 学习笔记 - 系统移行业务 - MALSY(由Excel 移行到SAP 的收费工具)
笔记·学习
Lazy_zheng13 分钟前
前端文件下载全攻略:从单文件到批量下载,哪种方法最优?
前端·javascript
专业抄代码选手22 分钟前
ES5中的继承实现
前端·javascript
来自星星的坤29 分钟前
如何解决 Vue.js 导航栏下拉菜单“闪现“问题 ! ! !
前端·javascript·vue.js
irises1 小时前
tabby-vscode代码补全的一些阅读笔记
前端·javascript
千野竹之卫1 小时前
2025最新云渲染网渲100渲染农场使用方法,渲染100邀请码1a12
开发语言·前端·javascript·数码相机·3d·3dsmax
__不想说话__1 小时前
面试官问我React Router原理,我掏出了平底锅…
前端·javascript·react.js