一、 作用域
- 作用域(scope) = 全局作用域(Global) + 局部作用域(Local);
- 局部作用域 = 函数作用域 + 块作用域;
- 作用域: 规定了变量 能够 被访问 的 范围,离开了这个范围,变量便不能被访问;
1.1 局部作用域
Local
- 局部作用域 = 函数作用域 + 块作用域;
1.1.1 函数作用域
- ⚠ 注意:
- 在 函数内部 声明的 变量 只能在 函数内部 被 访问,外部 无法直接访问(可以利用闭包来访问);
- 函数 的 参数 也是 函数内部 的 局部变量;
- 不同函数 内部声明 的 变量 无法 互相访问;
- ⚠ 函数执行完毕后,函数内部的变量实际被清空了(JS垃圾回收机制);
1.1.2 块作用域
- 在JavaScript中使用
{} 包裹的 代码 称为 代码块,代码块内部 声明的变量 外部【有可能:var声明的可以】无法访问;
- ⚠ 注意:
- ⚠
let 和 const 声明的变量 会产生 块作用域;
- ⚠
var 🔺不会产生🔻 块作用域:
- 不同代码块之间 的 变量 无法 互相访问;
- 推荐使用
let 或 const;
1.2 全局作用域
Global
- ⚠ 注意:
- 为
window 对象 动态添加的 属性 默认 是 全局变量,不推荐!;
- 函数中 未使用 任何关键字 声明的 变量 是 全局变量,不推荐!!!;
- 尽可能减少声明全局变量,防止变量污染;
1.3 作用域链
1.4 JS垃圾回收机制 - GC
- JS中 内存的分配 和 回收 都是 自动完成 的,内存 不使用 的时候 会被 垃圾回收器 自动回收;
- 内存的生命周期:
- 1️⃣ 内存分配: 声明 变量、函数、对象的时候,系统会 自动 为它们 分配内存;
- 2️⃣ 内存使用: 既 读写内存,也就是 使用 变量、函数等;
- 3️⃣ 内存回收: 使用完毕,由垃圾回收器 自动回收 不再使用的内存;
- ⚠ 注意:
- 全局变量 一般 不会回收(关闭页面回收)
- ⚠ 一般情况下 局部变量 的值,不用了,就会被自动回收
- 垃圾回收算法说明:
- 1️⃣❌ 引用计数法
- 致命缺陷:嵌套引用
- 如果两个对象相互引用,尽管他们不再使用,垃圾回收器不会进行回收,导致内存泄漏
-
- 2️⃣ 标记清除法
1.5 ❗❗ 闭包
- 闭包:
Closure
- 概念: 一个函数 对 周围状态的引用 捆绑在一起,内层函数 能够访问到 其外层函数 的 作用域;
- 闭包是一种使用过程;
- 闭包 = 内层函数 + 外层函数的变量;
- 代码展示:
function fn() {
let b = 9;
function outer() {
const a = 1;
console.log(b);
function f() {
console.log(a);
console.log(b);
}
f();
}
outer();
}
fn();
- 函数套函数 不一定会 产生 闭包
- 如果 内层函数 用到 外层函数 的 变量 这种情况就 会产生闭包
-
- ⚠ 闭包使用注意: 闭包使用的时候,内部的变量因为被外部引用了,所以代码执行完毕不会释放内存 - 内存泄漏(引用计数法)
- ❗ 闭包作用:
- 实现数据的私有化
- 外部 可以 访问 函数内部 的 变量
- 允许将 函数 与其所操作的 某些数据(环境)关联起来
- 应用场景:
- 基本格式:
function fn() {
let b = 9;
function outer() {
const a = 1;
console.log(b);
function f() {
let c = 6;
console.log(a);
console.log(b);
}
return f;
}
return outer;
}
const fun = fn();
fun();
const fun1 = fun();
fun1();
- 闭包应用: 实现 数据 的 私有化;
- ❗❗ 闭包面试:怎么理解闭包 -> 闭包的作用 -> 闭包可能引起的问题
1.6 ❌ 变量提升
二、函数进阶
2.1 函数提升
2.2 函数参数
2.2.1 动态参数
- arguments: 函数内部 内置 的 伪数组变量,包含了 调用 函数时 传入 的 所有实参
- 只能在普通函数里使用
- 作用: 动态获取函数的实参
- ⚠ 注意:
- 表示 所有实参 的 集合
- arguments 是一个 伪数组, 只存在于 函数内部
- 箭头函数 🔺没有🔺 arguments
- 🔺 可读写
- 代码展示:
function getSum() {
let sum = 0;
for (let i = 0; i < arguments.length; i++) {
sum += arguments[i];
}
return sum;
}
console.log(getSum(1, 2, 3, 4, 5, 6, 7, 8, 9, 10));
2.2.2 ✔ 剩余参数
- 允许将一个 不定数量 的 参数 表示为一个 数组
- ... 是语法符号,置于 最末 函数形参 之前,用于获取 剩余(多于) 的实参
- ⚠ 注意:
- 借助 ... 获取的 剩余实参,是个真数组
- 剩余参数放在 最末位
- 如果 没有剩余的参数,得到的就是一个 空数组
- 代码展示:
function getSum(...arr) {
console.log(arr);
}
getSum(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
----------------------------------------------------------------------
function getSum(a, b, c, ...arr) {
console.log(arr);
}
getSum(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
- 动态参数 和 剩余参数 的区别:
- 拓展:
- 展开运算符:(...)
- 展开运算符将一个 数组、对象 展开
- 当你在 函数的实参 或者 数组 或者 对象 里面使用的时候是 展开运算符
- 展开运算符写在数组前面
- 应用场景:
- 用于获取数组的最大值
- 合并数组
- 解构赋值(部分场景)
- 解构赋值 中 展开运算符 只能写在 最后一个元素 的 前面
- 展开运算符 or 剩余参数
- 展开运算符: 数组 中使用,数组展开,在 数组内部 使用
- 剩余参数: 函数参数 使用,得到真数组,在 函数内部 使用
- 代码展示:
const arr = [3, 45, 2, 89, 54];
console.log(...arr);
console.log(Math.max(...arr));
const arr1 = [1, 2, 4];
const arr2 = [...arr, ...arr1];
console.log(arr2);
const [n1, n2, ...n3] = [1, 2, 3, 4, 5];
console.log(n1, n2, n3);
---------------------------------------------------------------
const [n1, ...n2, n3] = [1, 2, 3, 4, 5];
2.3 ❗❗❗ 箭头函数
- ⚠🔺 注意:
- 箭头函数 没有 arguments,但是 有 剩余参数
- 箭头函数 没有 this
- 箭头函数 替代原本需要 匿名函数 的地方
- 函数表达式 的 简写方式 (匿名函数)
- 声明式函数 不能写
2.3.1 基本语法
2.3.2 箭头函数参数
2.3.3 箭头函数 this
- 函数 才有this
- 以前的this指向:
console.log(this);
function fn() {
console.log(this);
}
fn();
const obj = {
uname: '迪迦奥特曼',
sayHi: function () {
console.log(this);
}
}
obj.sayHi();
- window 是JS中的全局对象,我们 声明 的 变量 或 函数 实际上是给 window 添加 属性 或 方法
- 箭头函数 不会创建 自己的this,它只会 沿用 自己所在这条作用域链 的 上一层作用域 的 this
- 箭头函数的 this指向被创建的时候上下文中的this(出生的时候,所在的作用域中的this是谁,以后就都指向谁)
- 箭头函数里面的 this 任何方法都改变不了
- 因为箭头函数没有 this (它用的是上一层作用域链的 this )
- call / apply / bind 不能改变
- 代码展示:
const fn = () => console.log(this);
fn();
const obj = {
uname: '迪迦奥特曼',
sayHi: () => console.log(this)
}
obj.sayHi();
const obj1 = {
uname: '迪迦奥特曼',
sayHi: function () {
let i = 10;
const count = () => console.log(this);
count();
}
}
obj1.sayHi();
三、❗❗ 解构赋值
3.1 数组解构
3.1.1 基本语法
- 数组解构: 是 将数组的 单元值(数组元素) 快速 批量赋值 给 一系列变量 的 简介语法
- 基本语法:
- 赋值运算符 = 左侧 的
[] 用于 批量 声明变量,右侧数组 的 单元值 将被 赋值给左侧的变量
- 变量的顺序 对应 数组单元值的位置 依次 进行 赋值操作
- ⚠🔺 注意: 数组解构 赋值 是按照 索引 赋值 的
- 代码展示:
const [a, b, c] = [1, 2, 3];
console.log(a);
console.log(b);
console.log(c);
- 利用数组解构交换两个变量的值
let a = 11;
let b = 22;
[b, a] = [a, b];
console.log(a)
console.log(b)
----------------------------------------------------------------------
let a = 11
let b = 22
[b, a] = [a, b]
console.log(a)
console.log(b)
3.1.2 特殊情况
- 1️⃣ 变量多 单元值少
- 右侧的单元值按顺序对左侧的变量进行赋值,没有赋值的变量则是 undefined
- 代码展示:
const [hr, lx, mi, fz, hw] = ['海尔', '联想', '小米', '方正'];
console.log(hr, lx, mi, fz, hw);
- 2️⃣ 变量少 单元值多
- 右侧的单元值按顺序对左侧的变量进行赋值,剩余的单元值丢弃不用
- 代码展示:
const [hr, lx, mi] = ['海尔', '联想', '小米', '方正'];
console.log(hr, lx, mi);
- 3️⃣ 利用 剩余参数 解决 变量少 的问题
- ⚠ 注意:
- 剩余参数 返回的是一个真数组
- 剩余参数 放在 最末位
- 代码展示:
const [hr, lx, ...mi] = ['海尔', '联想', '小米', '方正'];
console.log(hr, lx, mi);
- 4️⃣ 防止 undefined 传递
- 设置默认值
- 代码展示:
const [hr, lx, mi, fz, hw = '华为'] = ['海尔', '联想', '小米', '方正'];
console.log(hr, lx, mi, fz, hw);
- 5️⃣ 按需导入,忽略某些值
- ⚠ 变量可以忽略,但是位置还是要留的
- 代码展示:
const [hr, lx, mi, , hw = '华为'] = ['海尔', '联想', '小米', '方正'];
console.log(hr, lx, mi, hw);
- 6️⃣ 多维数组解构
- 代码展示:
const [a, [b, [c, d, [e]]], f] = [1, [2, [3, 4, [5]]], 6];
console.log(a, b, c, d, e, f);
3.2 对象解构
- 对象解构: 是 将对象 属性 和 方法 快速 批量赋值 给一些列 变量 的 简介语法
3.2.1 基本语法
3.2.2 特殊情况
- 1️⃣ 对象解构的变量名 可以重新声明
- ⚠语法: 旧变量名: 新变量名
- 代码展示:
const uname = '赛罗奥特曼';
const { uname: username, age } = { uname: '迪迦奥特曼', age: 22 };
console.log(username, age);
- 2️⃣ 解构数组对象
- 代码展示:
const obj = [
{
uname: '迪迦奥特曼',
age: 22
},
{
uname: '赛罗奥特曼',
age: 23
}
];
const [{ uname, age }, { uname: userName, age: userAge }] = obj;
console.log(uname, age, userName, userAge);
- 3️⃣ 多级对象解构
- ⚠ 解构的时候必须写 🔺对象名🔺,不能打印
- 代码展示:
const pig = {
name: '佩奇',
family: {
mother: '猪妈妈',
father: '朱爸爸',
sister: '乔治'
},
age: 6
};
const { name, family: { mother, father, sister }, age } = pig;
console.log(name, mother, father, sister, age);
const person = [
{
name: '佩奇',
family: {
mother: '猪妈妈',
father: '朱爸爸',
sister: '乔治'
},
age: 6
}
];
const [{ name, family: { mother, father, sister }, age }] = person;
console.log(name, mother, father, sister, age);
✔✔
const msg = {
"code": 200,
"msg": "获取新闻列表成功",
"data": [
{
"id": 1,
"title": "5G商用自己,三大运用商收入下降",
"count": 58
},
{
"id": 2,
"title": "国际媒体头条速览",
"count": 56
},
{
"id": 3,
"title": "乌克兰和俄罗斯持续冲突",
"count": 1669
},
]
};
const { data } = msg;
console.log(data);
function render({ data }) {
console.log(data);
}
render(msg);
function render({ data: myData }) {
console.log(myData);
}
render(msg);
- 今日案例拓展:
:active 伪类选择器
draggable 可拖拽的
draggable ="false" 禁止拖拽
draggable ="true" 可以拖拽
四、对象进阶
4.1 创建对象的三种方式
4.2 构造函数(自封装)
- 是一种 特殊的函数,主要用来 初始化对象
- 可以用构造函数 创建多个 类似 对象(对公共的部分进行抽取并封装)
- 规范:
- 命名以 大写字母 开头
- ⚠🔺 只能由 new 操作符来执行
- ⚠🔺 注意:
- 使用 new 关键字调用函数的行为被称为 实例化
- 构造函数内部 无需写return,返回值 即为 新创建的对象
- 构造函数内部的 return 返回的值 无效,所以不要写 return
- ❗❗ 实例化执行的过程: (面试)
- 1️⃣ 创建新的 空对象
- 2️⃣ 构造函数 this 指向 新对象
- 3️⃣ 执行构造函数代码,修改this,添加新属性
- 4️⃣ 返回新对象
- 代码展示:

4.3 实例成员 & 静态成员
4.3.1 实例成员
- 构造函数 创建的 对象 称为 实例对象
- 🔺 实例对象 的 属性 和 方法 称为 实例成员
- ⚠ 注意:
- 为 构造函数 传入 参数,动态创建 结构相同 但 值不同 的 对象
- 构造函数 创建 的 实例对象 彼此独立 互不影响
4.3.2 静态成员
- 🔺 构造函数 的 属性 和 方法 被称为 静态成员
- ⚠🔺 静态成员方法 中的 this 指向 构造函数
- 一般 公共特征 的属性或方法 静态成员设置为静态成员

五、内置构造函数 - Object
- 字符串、数值、布尔等基本数据类型也都有专门的构造函数,称为 基本包装类型
- 引用类型: Object、Array、RegExp、Date 等
- 包装类型: String、Number、Boolean 等
5.1 ❌用内置构造函数创建对象
const obj = new Object({uname: '迪迦', age: 22});
5.2 常用的 静态方法
- 静态方法: 只有 构造函数 Object 才可以 调用 (写在构造函数身上的方法)
5.2.1 Object.keys()
- 作用:
- 语法:
Object.keys(对象名)
- ⚠ 返回值:
- 代码展示:⬇
5.2.2 Object.values()
- 作用:
- 语法:
Object.values(对象名)
- ⚠ 返回值:
- 代码展示:⬇
5.2.3 Object.assign()
5.2.4 代码展示
const obj = { uname: '迪迦', age: 22 };
const arr = Object.keys(obj);
console.log(arr);
const arr1 = Object.values(obj);
console.log(arr1);
const obj1 = {};
Object.assign(obj1, obj);
console.log(obj1);
Object.assign(obj1, {gender: '男'});
console.log(obj1);
六、内置构造函数 - Array
6.1 ❌使用Array内置构造函数创建数组
const arr = new Array();
const arr = new Array(5);
const arr = new Array(1, 2, 3, 4, 5);
6.2 数组方法总结 - 改变原始数组 (7)
6.2.1 push()
- 作用:
- 将 一个或多个元素 追加到 数组的末尾 ,并返回 追加元素之后 数组的 length
- 语法:
arr.push(val1, ..., valN);
- 返回值:
- 代码展示:
const arr = [1, 2, 3];
const length = arr.push(4, 5);
console.log(arr);
console.log(length);
6.2.2 unshift()
- 作用:
- 将 一个或多个元素 插入到 数组的开头 ,并返回 插入元素之后 数组的 length
- 语法:
arr.unshift(val1, ..., valN);
- 返回值:
- 代码展示:
const arr = [3, 4, 5];
const length = arr.unshift(1, 2);
console.log(arr);
console.log(length);
6.2.3 pop()
6.2.4 shift()
6.2.5 splice()
- 作用:
- 通过 删除 或 替换 现有元素 或 原地添加新元素 来 修改数组,并以 数组的形式返回被修改的内容
- 语法:
array.splice(startIndex[, deleteCount[, items]])
- 返回值:
- ⚠ 注意:
- 删除/替换 的时候,包括 开始索引 的 位置
- 添加 的时候,是添加在 开始索引位置之前
- 添加 的时候返回的是 空数组
- 代码展示:
const arr = [1, 2, 3];
const Value = arr.splice(1, 1);
console.log(arr);
console.log(Value);
const arr = [1, 2, 3];
const Value = arr.splice(1, 1, 6);
console.log(arr);
console.log(Value);
const arr = [1, 2, 3];
const Value = arr.splice(1, 0, 8);
console.log(arr);
console.log(Value);
6.2.6 sort() - 数组排序
- 作用:
- 语法:
arr.sort() 可以省略参数,升序
arr.sort(function (a, b) { return a - b } ) 升序排列
arr.sort(function (a, b) { return b - a } ) 降序排列
- 返回值:
- 代码展示:
const arr = [23, 45, 78, 10];
arr.sort();
console.log(arr);
arr.sort(function (a, b) {return a - b});
console.log(arr);
arr.sort(function (a, b) {return b - a});
console.log(arr);
6.2.7 reverse() - 反转数组
- 作用:
- 语法:
arr.reverse();
- 返回值:
- 代码展示:
const arr = [1, 2, 3, 4, 5];
arr.reverse();
console.log(arr);
6.3 数组方法总结 - 不改变原始数组
6.3.1 forEach - 遍历数组
- 作用:
- 语法:
Array.forEach(function (item[, index[, Array]]) { } )
- 返回值:
- 代码展示:
const arr = ['red', 'purple', 'pink'];
arr.forEach((item, index) => {
console.log(item);
console.log(index);
});
6.3.2 map() - 迭代数组(映射数组)
- 作用:
- 遍历原数组,把原数组中的每一个数据加工改造,形成一个新数组返回
-
- 语法:
Array.map(function (item[, index[, Array]]) { } )
- 返回值:
- 注意:
- 将原始数组里面的元素进行处理之后添加到新数组里
- 新数组length = 旧数组length
- 代码展示:
const arr = ['red', 'blue', 'green'];
const newArr = arr.map(function (item, index, arr) {
return item + '老师';
});
console.lgo(newArr);
const arr1 = [10, 20, 30];
const newArr1 = arr1.map(function (item, index, arr) {
return item + 10;
});
console.log(newArr1);
6.3.3 filter() - 筛选数组
- 作用:
- 过滤 原始数组中的数据,把 满足条件 的数据放在一个新数组中
-
- 语法:
Array.filter(function (item[, index[, Array]]) {} )
- 返回值:
- 是一个新数组,里面是所有原始数组中满足条件的数据
注意:
- 在执行函数返回true的情况下,留下该数据,返回为false 去除该数据;
- 代码展示:
const arr = [20, 1, 34, 60, 49, 90, 200, 288];
const newArr = arr.filter(item => {
return item > 100;
});
console.log(newArr);
-------------------------------------------------------------------
const arr = [23, 4, 19, 22, 56, 77];
const newArr = arr.filter(item => {
if (item % 2 === 0) {
return true;
} else {
return false;
}
});
console.log(newArr);
const newArr = arr.filter(item => item % 2 === 0);
console.log(newArr);
6.3.4 reduce() - 累计器(求和)
- 作用:
- 每一次运行 reduce 会将先前元素的计算结果作为参数传入,最后将其结果汇总为单个返回值
-
- 语法:
Array.reduce(function () {}, 起始值)
Array.reduce(function (累计值, 当前元素[, 索引号][, 原数组]) {}[, 起始值])
- 参数:
- 起始值可以省略
- 如果写就作为第一次累计的起始值
- 如果没有,就取第一个元素作为起始值(累加的时候从第二个元素开始)
- 有起始值,则以起始值为准开始累计,累计值 = 起始值
- 没有起始值,则累计值以数组的第一个元素作为起始值开始累计
- 后面每次遍历就会用后面的数组元素 累计 到 累计值 里面
- 返回值:
- 代码展示:
const arr = [1, 2, 3, 4, 5];
const sum = arr.reduce((prev, item) => prev + item, 0);
console.log(sum);
const sum = arr.reduce((prev, item) => prev + item);
console.log(sum);
6.3.5 join()
6.3.6 find() - 返回数组中满足条件的 第一个元素
- 作用:
-
- 语法:
Array.find(function (item, index, arr) {} [, thisArg])
- 返回值 :
- 有 满足条件 元素: 返回 第一个 元素
- 没有 这个元素: undefined
- 代码展示:
const arr = [5, 12, 8, 130, 44];
const found = arr.find(item => item > 10);
console.log(found);
6.3.7 some()
- 作用:
-
- 语法:
Array.some(function (item, index[, arr]) {})
- 返回值:
- 布尔值(true / false)
- 有 一个 满足 - true
- 都不 满足 - false
- 代码展示:
const arr = [1, 2, 3, 4, 5];
const value = arr.some(item => item >= 3);
console.log(value);
6.3.8 every()
- 描述: 判断 数组 里面的 每一个元素 是不是都 满足条件
-
- 语法:
Array.every(function (item, index[, arr]) {})
- 返回值: 布尔值(true / false)
- 都满足 - true
- 有 一个 不满足 - false
- 代码展示:
const arr = [2, 26, 56, 34, 67];
let flag = arr.every(item => item > 30);
console.log(flag);
6.3.9 concat() - 合并数组
- 作用:
- 合并 两个或多个数组。此方法不会更改现有数组,而是返回一个 新数组
- 语法:
const new_array = oldArr.concat(value1[, value2[, ...[, valueN]]])
- 参数:
- 返回值:
- 代码展示:
const arr = [1, 2, 3];
const arr1 = [4, 5, 6];
const new_array = arr.concat(arr1);
console.log(new_array);
const num = 8;
const new_array = arr.concat(num);
console.log(new_array);
const obj = {uname: '奥特曼', age: 22};
const new_array = arr.concat(obj);
console.log(new_array);
6.3.10 slice() - 提取元素
- 作用:
- 语法:
Array.slice(开始索引, 结束索引)
- ⚠ 参数 :
- 包前不包后
- 第一个参数不写: 头 ➡ 指定位置
- 第二个参数不写: 指定位置 ➡ 尾
- 参数可以是一个负数 -> length + 负数
- 返回值:
- 代码展示:
const arr = [1, 2, 3, 4, 5, 6];
const newArr = arr.slice(2, 4);
const newArr = arr.slice(4);
const newArr = arr.slice(2);
const newArr = arr.slice(2, -2);
const newArr = arr.slice();
console.log(newArr);
6.3.11 flat() - 数组降维(数组扁平化)
arr.flat(几维数组);
arr.flat(Infinity);
6.3.12 indexOf() - 正向 查看数组里面 指定数据 的 索引
Array.indexOf(数据)
Array.indexOf(数据, 开始索引) 从哪个索引开始向后查找
返回值: 如果有这个数据,是第一个满足条件的数据的索引
如果没有这个数据,就是 -1
6.3.13 lastIndexOf() - 反向 查看数组里面 指定数据 的 索引
Array.lastIndexOf(数据)
Array.lastIndexOf(数据, 开始索引)
注意: 虽然是反向查找,但是索引还是正常索引
6.3.14 copyWithin() - 使用 数组里面的内容 替换 数组里面的内容
Array.copyWithin(目标位置, 开始索引, 结束索引)
->目标位置:当你替换内容的时候,从哪一个索引位置开始替换
->开始索引:数组哪一个索引位置开始当作替换内容,默认是 0
->结束索引:数组哪一个索引位置结束当作替换内容,默认是 结尾
返回值: 是一个新数组(替换后的数组)
6.3.15 fill() - 使用 指定数据区 填充 数组
Array.fill(要填充的数据, 开始索引, 结束索引)
前提: 数组要有 length
返回值:
填充好的数组
6.3.16 includes() - 查看 数组中是不是有 某一个数据
Array.includes(数据)
返回值: 一个布尔值
有这个数据就是 true
没有这个数据就是 false
6.3.17 findIndex() - 根据条件找到数组里面满足条件的数据的索引
Array.findIndex(function (item) {} )
返回值:
找到满足条件的第一个元素的索引
6.4 伪数组 ➡ 真数组
七、 内置构造函数 - String
7.1 ❌字符串的创建
let str = 'hello world'
let str = new String('hello world')
7.2 字符串方法
- 都是 实例方法
-
- ⚠ 注意:
7.2.1 substring() - 截取字符串
- 语法:
str.substring(indexStart[, indexEnd])
- 参数:
- indexStart = indexEnd ➡ 返回一个 空字符串
- 省略indexEnd ➡ 提取字符 开始索引 一直 到 字符串末尾
- 如果任一 参数小于0或为NaN,则被 当作 0
- 如果任一 参数大与 stringName.length,则被当作 stringName.length
- 如果 indexStart 大与 indexEnd,则substring 的执行结果就像两个参数调换了一样。
- 返回值:
- ⚠ 注意:
- 包前 不包后;
- 能取到开始索引位置的字符,取不到结束索引位置的字符;
- 代码展示:
const str = '迪迦奥特曼,塞罗奥特曼,银河奥特曼,艾克斯奥特曼';
const newStr = str.substring(4, 9);
const newStr = str.substring(6);
const newStr = str.substring(6, 6);
const newStr = str.substring(-9);
const newStr = str.substring(NaN);
const newStr = str.substring(100);
const newStr = str.substring(9, 4);
console.log(newStr);
- ❌ 拓展:也是截取字符串的方法
7.2.2 split() - 将 字符串 拆分成 数组 (分割)
- 语法:
str.split(分隔符)
- 参数:
- 字符串里面用的什么分隔符参数就是什么
- 没有参数 / 别的字符: 数组里面的 元素 就是 字符串本身
- 空字符串: 将字符串的每一个 字母 或 数组 或 文字 或 标点符号 都作为一个 数组元素
- 返回值: 数组
- 注意: 和 数组的join方法 相反
- 代码展示:
const str = '迪迦奥特曼,塞罗奥特曼,银河奥特曼,艾克斯奥特曼';
const arr = str.split(',');
console.log(arr);
const str1 = '2022-8-16';
const arr1 = str1.split('-');
console.log(arr1);
7.2.3 startsWith() - 检测是否以某个(某段)字符开头
- 语法:
string.startsWith(检测字符串[, 检测位置索引号])
- 参数:
- 返回值: 布尔值(true / false)
- ⚠ 注意:
- 代码展示:
const str = '迪迦奥特曼,赛罗奥特曼,银河奥特曼,艾克斯奥特曼';
const flag = str.startsWith('赛罗奥特曼', 6);
console.log(flag);
7.2.4 includes() - 判断一个字符串是否包含在另一个字符串中(返回true / false)(includes - 包含)
- 语法:
str.includes(搜索的字符串[, 检测索引位置])
- 返回值:
true / false
- 代码展示:
const str = '迪迦奥特曼,赛罗奥特曼,银河奥特曼,艾克斯奥特曼';
const flag = str.includes('赛罗奥特曼');
console.log(flag);
7.2.5 replace() - 替换字符串中指定的字符
- 语法:
字符串.replace(要替换的旧字符, 替换的新字符)
- 返回值: 替换之后 的字符串
- 注意:
- 不改变 原始字符串
- 默认 只替换 匹配到的 第一个字符串
- 可以 配合 正则表达式(g 和 i) 来 全局匹配 并且 不区分大小写
- 代码展示:
let str = '赛文奥特曼真好看,并且赛文奥特曼真厉害!';
const newStr = str.replace(/赛文/g, '迪迦');
console.log(newStr);
八、内置构造函数 - Number
九、编程思想
9.1 面向过程变成
- 面向过程: 就是分析出解决问题所需要的步骤,然后用函数把这些步骤一步一步实现,使用的时候再一个一个的依次调用就可以了
- 优点:
- 性能 比面向对象 高,适合跟硬件联系很紧密的东西,例如单片机
- 缺点:
9.2 面向对象编程 (oop)
- 面向对象: 是把事务分解成为一个个对象,然后由对象之间分工与合作。
- 特性:
- 优点:
- 易维护、易复用、易扩展,基于面向对象封装、继承、多态性的特性,可以设计出低耦合的系统,使系统 更加灵活、更加易于维护
- 缺点:
十、构造函数
- 构造函数 体现了 面向对象 的 封装特性
- 构造函数 实例创建 的 对象 彼此独立、互不影响
- 构造函数存在的问题:浪费内存(可以用原型解决)
- 代码展示:
function Star(uname, age, gender) {
this.uname = uname;
this.age = age;
this.gender = gender;
this.sing = function () { console.log('构造函数'); }
}
const dj = new Star('迪迦', 22, '男');
const sl = new Star('赛罗', 23, '女');
console.log(dj === sl);
console.log(dj.sing === sl.sing);
十一、❗❗❗ 原型
11.1 原型
- 原型
- 是一个 对象,我们称 prototype 为 原型对象
- 跟随函数一起创建的对象
- 构造函数 通过 原型 分配的 方法 是 所有对象 所 共享的
- js规定,每一个 构造函数 都有一个 prototype 属性,指向 另一个对象,所以我们称为 原型对象
- 这个原型对象可以挂载函数,对象实例化不会多次创建原型上函数,节约内存
- 可以把那些不变的方法,直接定义在prototype对象上,这样所有对象的实例就可以共享这些方法
- 作用: 为当前函数创建的实例添加公共的属性和方法(把那些不变的方法挂载在prototype上)
- ⚠🔺 构造函数 和 原型对象 中的 this 都指向 实例对象
- 原型上的方法,谁调用就指向谁(实例对象 + 原型自己)
- 有函数 就有 原型对象
- 代码展示:
function Star(uname, age, gender) {
this.uname = uname;
this.age = age;
this.gender = gender;
}
const Dj = new Star('迪迦', 22, '男');
const Sl = new Star('赛罗', 23, '女');
Star.prototype.sing = function () { console.log('原型-prototype'); }
console.log(Dj.sing === Sl.sing);
Star.prototype.sing();
const arr = [6, 3, 8, 2, 9, 0];
Array.prototypeGgetValue = function () {
return [Math.max(...this), Math.min(...this), this.reduce((prev, item) => prev + item)]
}
console.log(arr.GetValue());
11.2 constructor属性
- 每个 原型对象 里面都有 constructor 属性(constructor ➡ 构造函数)
- 作用: 该属性 指向 该原型对象 的 构造函数
- ⚠🔺 每个 构造函数 都有 prototype属性 ,每个 prototype属性 都有 constructor属性
- 使用场景:
- 如果有 多个对象 的 方法,我们可以 给 原型对象 采用 对象形式 赋值 (单个方法是追加)
- 但是这样就会 覆盖 构造函数 原型对象 原来 的 内容,这样 修改后 的 原型对象 的constructor属性 就 不再 指向 当前 构造函数
- 此时,我们可以在 修改后 的 原型对象 中,添加一个 constructor属性 指向 原来的构造函数
- 代码展示:
- 原来的prototype:

-
11.3 对象原型
- 对象 都会有一个
__proto__ 指向 构造函数 的 prototype 原型对象,之所以我们对象可以使用构造函数 prototype 原型对象的属性和方法,就是因为对象有 __proto__ 原型的存在
- ⚠ 注意:
__proto__ 是一个 🔺只读属性🔺 (前后两个杠)
- Chrome 中 [[prototype]] 和
__proto__ 意义相同
- 用来表示当前实例对象指向哪个原型对象prototype
__proto__ 对象原型 里面也有一个 constructor属性,指向 创建 该实例对象 的 构造函数
-
-
- ⚠🔺🔺 注意: (混淆点)
- 每个 构造函数 都有 prototype(原型对象)
- 每个 prototype(原型对象) 都有 constructor,指向 该原型对象 的 构造函数
- 每个 对象 都有
__proto__(对象原型)(属性),指向 构造函数 的 原型对象
- 每个 对象原型 都有
constructor 属性,指向 创建 该实例 的 构造函数

- 对象都会有一个属性
__proto__ 指向构造函数的prototype原型对象,之所以对象可以使用构造函数prototype原型对象的属性和方法,就是因为对象有___proto__
- 🔺🔺⚠⚠总结:
- 1️⃣ prototype 是什么?哪里来的
- 2️⃣ constructor属性 在哪里?作用是啥?
- prototype原型 和 对象原型
__proto__ 里面 都有
- 都 ➡ 创建 原型 / 实例对象 的 构造函数
- 3️⃣
__proto__ 属性在哪里?指向谁?
- 在 实例对象 里面
- ➡ 原型对象
prototype
11.4 原型继承
- JS中大多是 借助 原型对象 实现 继承的特性
- 父构造函数(父类)
- 子构造函数(子类)
- 子类的原型 = new 父类
- 使用构造函数实现继承:
- 类:创建一类对象的模板
- 原型链继承:利用原型链的关系,实现继承的效果
- 在ES6之前,没有继承的语法,可以使用call和原型链来完成继承的效果,子构造函数继承父构造函数
- 1、子构造函数 创建的实例 拥有 父构造函数 创建的实例 相同 属性结构(call借用父构造函数的代码,修改其中this指向为子构造函数的实例)
- 2、子构造函数 创建的实例 可以调用 父构造函数 原型对象 的 公共成员(把 子构造函数 的原型对象 的 原型对象 变成,父构造函数的原型对象)
11.5 ❗❗ 原型链
- 基于 原型对象 的 继承 使得 不同构造函数 的 原型对象 联系在一起,并且这种 关联关系 是一种 链状结构,我们将 原型对象 的 链状结构关系 称为 原型链
- 从实例出发,以原型对象为连接,形成的一个链式的结构
- 由原型对象的关系相连,形成的链式结构
- 实例成员调用的时候,优先调用自身的成员,如果自身没有,继续调用原型对象的成员,如果原型对象也没有,就调用原型对象的原型对象的成员
- 原型链的作用: 实例调用成员的查找顺序
- 原型链主要指的是
__proto__
-
-
- 🔺🔺⚠⚠总结:
- 只要是 对象 就有
__proto__ ,指向 原型对象
- 只要是 原型对象 里面就有 constructor,指向 创建 该原型对象 的 构造函数
- 实例对象 和 原型对象本身 可以 访问 定义在原型身上的方法或属性
- 构造函数不行(中间隔着prototype)
- 构造函数访问不了原型身上的属性或方法,因为中间隔着 prototype
- 实例对象可以访问原型对象的原型对象身上的属性和方法,中间虽然隔着东西,但能直接访问,因为这是规则
- 原型链-查找规则
- 当访问一个对象的属性(包括方法)时,首先查找这个对象自身有没有该属性
- 如果没有就查找它的原型(也就是
__proto__指向的prototype原型对象)
- 如果还没有就查找原型对象的原型(Object的原型对象)
- 依此类推一直找到Object为止(如果
Object.prototype 也没有得到的就是 )
__proto__对象原型的意义在于为对象成员查找机制提供一个方向,或者说一条路线
- 可以使用
instanceof 运算符用于检测构造函数的 prototype 属性是否出现在某个实例对象的原型链上

11.6 instanceof
instanceof 运算符用于检测构造函数的 prototype 属性是否出现在某个实例对象的原型链上。
- 简单理解:
- 判断 当前构造函数的原型对象 是否出现在 实例的原型链上
- 检测 实例对象 是否 由 该构造函数 创建 出来的
- 描述:
instanceof 运算符用来检测 constructor.prototype 是否存在于参数 object 的原型链上
- 语法:
object instanceof constructor
- 参数:
object - 实例对象
constructor - 构造函数
- 代码展示:
function C(){}
function D(){}
var o = new C();
o instanceof C;
o instanceof D;
o instanceof Object;
C.prototype instanceof Object
C.prototype = {};
var o2 = new C();
o2 instanceof C;
o instanceof C;
D.prototype = new C();
var o3 = new D();
o3 instanceof D;
o3 instanceof C;