编写于2025年06月03日 修订于2025年06月17日
作用域是变量能够被访问的范围,分为局部作用域、全局作用域。
局部作用域分为函数作用域(函数内部声明,外部无法访问)、块作用域(“{}”包含的代码称为一个块,如for循环,外边有可能无法访问,var声明的外边可以访问,var没有块作用域)。
全局作用域变量定义在最外层,可以在其他作用域中访问,尽量不要用全局变量。
作用域链本质上是底层的变量查找机制,函数执行时,优先查找当前的作用域,然后依次逐级查找父级作用域,直到全局作用域。
JS中内存的分配和回收都是自动完成的,内存在不使用时会被垃圾回收器自动回收。
内存生命周期:
全局变量一般不会回收(关闭页面回收),局部变量的值在使用完成以后就会被回收。
闭包 = 内层函数 + 外层函数的变量。
// 闭包示例 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'}};
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入门到精通全套视频教程》。
更多信息可参考权威网站。