返回首页

JS进阶学习 | 原生JS基础到进阶

日期图标编写于2025年06月03日   修订于2025年06月17日

正文


作用域

作用域是变量能够被访问的范围,分为局部作用域、全局作用域。

局部作用域分为函数作用域(函数内部声明,外部无法访问)、块作用域(“{}”包含的代码称为一个块,如for循环,外边有可能无法访问,var声明的外边可以访问,var没有块作用域)。

全局作用域变量定义在最外层,可以在其他作用域中访问,尽量不要用全局变量。

作用域链本质上是底层的变量查找机制,函数执行时,优先查找当前的作用域,然后依次逐级查找父级作用域,直到全局作用域。

垃圾回收机制(GC)

JS中内存的分配和回收都是自动完成的,内存在不使用时会被垃圾回收器自动回收。

内存生命周期:

1、内存分配:当声明变量、函数、对象时,系统会自动分配内存。
2、内存使用:使用变量、函数时读写内存。
3、内存回收:使用完毕,由垃圾回收器自动回收不再使用的内存。

全局变量一般不会回收(关闭页面回收),局部变量的值在使用完成以后就会被回收。

闭包

闭包 = 内层函数 + 外层函数的变量。

// 闭包示例
function f1() {
    const a = 1;
    function f2() {
        console.log(a);
    }
    return f2;
}

const f3 = f1();
f3();

闭包的作用:封闭数据,提供操作,外部函数可以使用函数内部的变量。

闭包的应用:实现数据私有,不能被篡改,保证安全。

闭包的局部变量不会被回收,因为f3是全局变量,不会回收,f3指向f2,f2不会被回收,f2中用到了a,所以局部变量a不会被回收。

闭包有内存泄漏的风险。

变量提升

变量提升是js的一个现象,即运行变量在声明以前即被访问,仅限于var声明的变量,实际开发中不推荐使用。ES6引入了块级作用域let和const。

console.log(num);
var num = 10;
// 输出结果是undefined

执行过程:当代码在执行之前,首先内部会把所有在当前作用域下var声明的变量提升到当前作用域的最前面,只提升声明,不提升赋值。

函数提升

函数在声明之前被调用,提倡先声明函数,再调用函数。

函数参数

动态参数:arguments是函数内部内置的伪数组变量,包含调用函数时传入的所有实参,括号里边是没有参数的。

function sum() {

    let s = 0;
    for (let i = 0; i < arguments.length; i ++) {
        s += arguments[i];
    }
    console.log(s);
}

sum(1, 2, 3);
sum(1, 2, 3, 4, 5);

剩余参数:将一个不定数量的参数表示为一个数组

function sum(...arr) {
    
    let s = 0;
    for (let i = 0; i < arr.length; i ++) {
        s += arr[i];
    }
    console.log(s);
}

sum(1, 2, 3);
sum(1, 2, 3, 4, 5);

function sum(a, b, ...c) { ...... }

区别:剩余参数“...”是语法符号,置于最末函数形参之前,用于获取多余的实参,开发中提倡使用剩余参数。

展开运算符

展开运算符(...),将一个数组进行展开,不会修改原数组。

const arr = [1, 2, 3, 4, 5];
console.log(...arr);

使用场景:求最大最小值、合并数组等。

const arr = [1, 2, 3, 4, 5];
console.log(Math.max(...arr));
// ...arr === 1,2,3,4,5

const arr2 = [6, 7, 8, 9, 10];
const arr3 = [...arr, ...arr2];

箭头函数

箭头函数使函数表达式更简洁,用于原本就写匿名函数的地方。

// 1、箭头函数写法
const fn = (x) => {
    console.log(x);
}
fn(x);

// 2、只有一个形参的时候可以省略小括号
const fn = x => { console.log(x); }

// 3、只有一行代码的时候,可以省略大括号
const fn = x => console.log(x);

// 4、只有一行return可以省略return
const fn = x => x+x;

// 5、可以直接返回一个对象,但需要用小括号包起来
const fn = (uname) => ({name: name})

箭头函数中没有arguments动态参数,有剩余参数...args。

箭头函数不会创建自己的this,只会从作用域链的上一层沿用this,尽量不要用this。

解构赋值

数组解构

// 数组解构:将数组的单元值快速批量的赋值给一些列变量的简洁语法
const [max, min, avg] = [100, 60, 80]
console.log(max);

// 典型应用——交互两个变量
let a = 1;
let b = 2;
[b, a] = [a, b];
// js必须加分号的情况——1、立即执行函数;2、数组解构;
// 变量多,单元值少时,多出的变量是undefined
// 变量少,单元值多是,可以用剩余变量处理
// 也可以给默认值[a=0, b=0] = []
// 位置忽略[a, b, , c],单元值也对应跳一位

对象解构

// 对象解构将对象属性和方法快速批量赋值给一系列变量的简洁方法
const {uname, age} = {uname: 'aaa', age: 10}
// 变量名和属性名要一致,解构的变量名和外部变量名不冲突。
// 如果必须改名的话,对象解构的变量名可以重新改名:旧变量名: 新变量名
const {uname: username, age} = {uname: 'aaa', age: 10}

// 数组对象解构
const objArr = [{uname: 'aaa'}, {uname: 'bbb'}];
const [{uname}] = objArr;

// 多级对象解构
const {name, info: {father, mather}} = {name: 'aaa', info: {father: 'bbb', mather: 'ccc'}};

遍历数组forEach方法

arr.forEach(function (元素, 元素索引号) {
    ...
});

创建对象的三种方式

// 利用字面量创建对象
const obj = { name: '佩奇' };

// 利用new Object创建对象
const obj = new Object();
obj.name = '佩奇';

const obj = new Object({ name: '佩奇' });  // 也是构造函数

// 利用构造函数创建对象
function Info(name, age) {
    this.name = name;
    this.age = age;
}
const info1 = new Info('aaa', 10);
const info2 = new Info('bbb', 11);
// 构造函数在技术上是常规函数,有两个约定:1、命名以大写字母开头;2、只能由new操作符来执行;
// this指向Object

new关键词创建对象都叫实例化,构造函数无需写return,写了也没用,没有参数可以省略“()”。

new实例化执行过程:只要有new,立马创建一个新的空对象,构造函数中的this指向新对象,再执行构造函数中的代码,修改this,添加新的属性,最后返回新对象。

实例成员和静态成员

通过构造函数创建的对象叫实例对象,对象中的属性和方法叫实例成员。构造函数创建的实例对象彼此独立,互不影响。

构造函数中的属性和成员称为静态成员(静态属性、静态方法),静态成员只能构造函数来访问,静态方法中的this指向构造函数。

function Obj (name) {
    this.name = name;
}
Obj.age = 10;

内置构造函数

基本数据类型:字符串、数值、布尔、undefined、null

引用数据类型:对象

// 基本数据类型包装成了引用数据类型
const str = 'aaa'; <===> const str = new String('aaa');

内置构造函数:Object、Array、String、Number

推荐使用字面量创建对象。

Object的三个常用的静态方法(只有Object才可以调用的):

const obj = {name: 'aaa', age: 10};
Object.keys(obj);  // 获取对象中的所有属性,返回数组。
Object.values(obj);  // 获取对象中的所有值,返回数组。
const obj2 = {};
Object.assign(obj2, obj);  // 拷贝

Array的常用的实例方法

// forEach 遍历数组
// filter 过滤数组,返回新数组
// map 迭代数组,返回处理之后的数组元素,返回新数组
// reduce 累计器,返回累计处理的结果,经常用于求和等
const arr = [1, 5, 8]
const total = arr.reduce(function (prev, current) {
    return prev + current;
});
// join 数组元素拼接为字符串,返回字符串
// find 查找元素,返回符合测试条件的第一个数组元素值,没有返回undefined
// every 检测数组中所有元素都符合指定条件,是返回true,否返回false
// some 检测数组中的元素是否满足指定条件,有返回true,没有返回false
// concat 合并两个数组,返回生成新数组
// sort 对原数组单元值排序
// splice 删除或替换原数组单元
// reverse 反转数组
// findIndex 查找元素索引值

String常用的实例方法

// length 实例属性,获取字符串长度
// split 将字符串分割成数组
// substring 截取字符串
// startsWith 检测是否以某字符开头
// includes 判断一个字符串是否包含在另一个字符串中
// toUpperCase 将字母转成大写
// toLowerCase 将字母转成小写
// indexOf 检测是否包含某字符
// endsWith 检测是否以某字符结尾
// replace 替换字符串,支持正则匹配
// match 查找字符串,支持正则匹配

防抖

function mouseMove () {
    console.log('aaa');
}

// 用lodash提供的防抖来处理
// 鼠标停止500毫秒之后调用mouseMove函数
对象.addEventListener('mousemove', _.debounce(mouseMove, 500));

节流

单位时间内频繁触发事件,只执行一次,如一个事件需要执行3秒,如果在这3秒内频繁触发其他事件,不会再有新的事件执行,直到当前事件执行完成。

// 500毫秒之内只执行一次
对象.addEventListener('mousemove', _throttle(mouseMove, 500));

参考


学习视频是b站《黑马程序员前端JavaScript入门到精通全套视频教程》。

更多信息可参考权威网站

相关文章


前一篇:web APIs学习 | 原生JS基础到进阶