1.作用域链
<script>
// 什么是作用域链: 变量的查找机制
// 大白话: 里面的函数能够看见外面的变量 ---外面看不见里面
// 官方: 变量查找的时候: 从内往外, 就近查找
// 全局变量a
let a = 1; // 全局变量 任何作用域都可以看见
function fn() {
// 局部变量 a ---- 在局部作用域里面声明的变量外面无法访问
let a = 10
function g() {
a = 20 // 这个a 是17行 还是 14行的a
console.log(a);
}
g()
}
// 问题: a是全局变量还是局部变量, a的值等于多少?
fn()
</script>
1. 局部作用域: 函数作用域 + 块级作用域
2. 全局作用域变量访问机制: 在任何局部作用域里面都可以看见
3. 局部作用域变量的访问机制:在局部作用域里面定义的变量外面看不见
4. 作用域链: 什么是作用域链: 变量的查找机制
具体是什么机制: 从内向外, 就近查找
闭包的作用
<script>
// 面试会问
// 什么是闭包: 闭包就是函数, 内层函数 + 访问了外层函数的变量
// 闭包的作用: 可以让函数外面访问函数内部的变量 (不能直接访问,需要通过函数调用的形式)
// 闭包的应用: 数据私有化
// 闭包的问题: 内存泄露 --- 一直保存在内存里面,不被销毁
function fn() {
let num = 10 // 只能在函数里面使用,外面看不到---- 数据私有化
return function g() {
num++
console.log(num);
}
}
const res = fn() // res就是一个函数
res() // 11 通过闭包,我们可以用函数调用的形式,去访问函数内部的变量
res() // 12
res() // 13
// num += 100 直接报错,因为它是私有变量,外面看不见,只能通过函数调用去访问
// console.log(num); // 我们之前学习的,在函数外面不能访问函数内部的变量,
// 通过全局变量的方式,实现调用一次函数,让变量值累加
let count = 10; // 这个变量是全局变量
function fn2() {
count++
console.log(count);
}
// 下面两行的打印分别是多少
fn2() // 第一次函数调用结束以后,全局变量count的值已经变为了 11
fn2() // // 第二次函数调用的时候,就是11开始
count += 100
console.log(count);
</script>
3.变量的声明和提升
<script>
// 整个函数体提升上来
// function fn() {
// console.log('我是一个函数');
// }
// 面试题: 变量的声明提升(var): 提升变量的声明,不提升变量的赋值
// 在工作里面,我们不会写这样的代码, 纯是为了面试官的考点
// 我们自己写代码, 一定是先声明,再使用
var str
console.log(str);
str = "hello" // 变量的初始化 === 变量的声明 var str + 变量的赋值 str = "hello"
// 正式因为这种写法很奇怪,但是js又不报错,所有es6 发明了 let/const去声明变量
// console.log(count);
// let count = 100 现在用let const 声明变量使用 不规范的时候,直接报错
// count = 10;
// console.log(count);
// let count;
// 对于函数来说,使用function声明一个函数,会把声明提升到当前作用域的顶部
// 自己写代码,不要先使用在定义, 习惯不好,看起来别扭
// 任何时候,一定是先声明再使用
fn()
function fn() {
console.log('我是一个函数');
}
4.函数的动态参数
<script>
// js给我们函数里面 自动添加了一个变量 动态参数 arguments
// arguments 伪数组,
function getSum() { // 形式化的参数: 形参
let sum = 0;
// 如果一个程序,不报错,也没有正常结果,那么一定是隐藏的语法写错了
// i < arguments 这个写法是错误的,但是浏览器不报错,所以不好查找,需要慢慢回忆for循环的基本结构
for(let i = 0; i < arguments.length; i++) {
sum += arguments[i]
}
console.log(sum);
// return sum
}
// 王瑞蕾, 周明亮, 刘刚强
const res = getSum(1) // 一个函数如果没有返回值,打印的结果就是undeifned
console.log(res); //
// 需求: 给函数传递任意个数参数,然后对他们求和
getSum(1) // 实参
getSum(1, 2, 3)
getSum(1, 2,3,4,5)
</script>
5.函数的剩余参数
<script>
// 剩余参数: es6的新语法, 语法就是 ...
// 动态参数:是伪数组 --- 只有length属性,可以通过索引号访问, 不能使用各种push等方法
// 剩余参数:真数组 ----- 工作里面一般使用 剩余参数来解决 这种任意参数的问题
// 如果不使用动态参数,怎么样对这些任意个数的参数求和
// function getSum(...args){
// console.log(args);
// console.log(arguments);
// // 自己利用 剩余参数,去写一个求和的函数,使用return的写法
// }
// getSum(1)
// getSum(1, 2)
// getSum(1, 2, 3, 4, 5)
function getSum(...args) { // 形式化的参数: 形参
let sum = 0;
for(let i = 0; i < args.length; i++) {
sum += arguments[i]
}
// return sum
}
// 函数一定要有return 才会有返回值, 如果没有return,就是undefined
const res = getSum(1,2)
console.log(res); // undefined
console.log(getSum(1,2)); // undefined
</script>
6.函数的剩余参数高级应用
function getNum(x, z, ...y){
console.log(x,z, y);
}
// 我想吧第一个参数单独拿出来,剩下的放到剩余参数里面去
getNum('我是最厉害的', 'b', 'c', 'd')
7.展开运算符
<script>
// 函数动态参数,剩余参数(函数里面) --- (展开运算符--数组前面)
// 展开运算符: 求最大最小值, 合并数组
const arr = [1,2,3,4,5]
const arr2 = [6,7,8,9]
// console.log(arr);
// console.log(...arr);
// 求最大值 1,2,3,4,5
// console.log(Math.max(1,2,3,4,5));
console.log(Math.max(...arr));
console.log(Math.min(...arr));
// const arr3 = [arr, arr2]
const arr3 = [...arr, ...arr2]
console.log(arr3);
8.箭头函数
<button class="btn">我是按钮</button>
<script>
// 谁来调用这个函数,函数内部的this就指向谁
// 箭头函数里面, 没有this值, 如果我们访问的话,会去上一层作用域里面找this
// (this就是一个局部变量,系统自动创建,箭头函数里面没有,他就会顺着作用域链往上找,就近原则)
// 全局环境下面的this值
console.log(this);
const obj = {
name: '小猪佩奇',
getName() {
// 函数内部的this值,是函数调用的使用,由系统自动创建的一个变量
// 谁来调用这个函数,函数内部的this就指向谁
console.log(this === obj);
}
}
obj.getName()
// 1. dom事件
const btnDom = document.querySelector('.btn')
// 后面的匿名函数, 当用户点击按钮的时候,由按钮去调用这个回调函数,所有函数内部的this就指向btn
// btnDom.addEventListener('click', function() {
// console.log(this);
// })
btnDom.addEventListener('click', () => {
console.log(this); // 为什么是window?1. 箭头函数内部没有this, 2. 去上一层作用域里面找
})
// 2. 对象里面的方法调用
const obj2 = {
name: '123',
getName: function() {
console.log(this); // 谁调用这个函数,this
const fn = () => {
console.log(this); // 没有this, 上一层作用域里面
}
fn()
}
}
obj2.getName()
const obj3 = {
name: '123',
getName: () => {
console.log(this);
const fn = () => {
console.log(this);
}
fn()
}
}
obj3.getName()