js高级day01
2. 执行环境和其关联的变量对象 (了解: 能和别人聊这个)
执行环境: js运行的环境叫执行环境
所有js运行都有一个默认的全局执行环境, 在浏览器中, 这个执行环境是 window 对象
变量对象: 隐藏的 (开发的人,看不到, 只有js引擎才能看得到), 存着当前执行环境的标识符
什么是标识符?
变量名,函数名, 对象key , 形参
2.1 执行环境有哪些?
- 全局执行环境
- 函数执行环境(局部执行环境)
2.2 执行环境-栈
栈: 栈是一种数据结构(类似圆柱体), 栈的规则是先入后出
入栈: 在函数 调用 的时候, 会把当前函数执行环境 放入 执行栈中 , 这个叫入栈
出栈: 在一个js中, 所有的函数全部进入 栈 后, 没有新的函数入栈, 继续执行 就会出栈, 函数出栈会被销毁
3 作用域链(掌握: 你除了能和别人说之外,还需要会用)
3.1 作用域
概念: 作用域可以理解为 标识符 以及 标识符所能访问的范围
什么是标识符?
变量名,函数名, 对象key , 形参
3.2 作用域链
概念: 标识符 所查找的规则, 从里往外, 一层一层向上找, 找到全局作用域截止, 如果没找到, 就会报错
作用: 确保对执行环境中的变量和函数的有序访问
3.3 作用域的分类
- es5
- 全局作用域
- 函数作用域(局部作用域)
- 没有块级作用域
- es6
- 新增了块级作用域( es6中, 使用 let 和 const 新增了块级作用域 )
什么块级作用域? 一个花括号 { 开始, 另一个 } 结束, 两个花括号之间的内容叫做代码块, 在es6中, 代码块也叫块级作用域
块级作用域作用: 主要是为了解决变量的全局污染问题
4 函数进阶(精通: 可以和比人聊, 可以使用,并且使用的是滚瓜乱熟)
4.1 箭头函数
语法:
// 使用函数表达式才能创建
const add = (num1, num2) => {
return num1 + num 2
}
// 1. 简化写法, 如果只有一行代码 可以省略 花括号, 有return的话也可省略return
const add1 = (num1, num2) => num1 + num2
// 2. 简化写法, 如果只有一个形参的话, 可以省略小括号
const add2 = num => num + 2
注意(箭头函数特别需要注意的事项):
- 箭头函数内, 没有自己this (后面的课程中会讲, 先记住这句话)
- 箭头函数不可以当作构造函数使用 , 箭头函数 不能 new 调用 (后面的课程也会将)
- 箭头函数没有 arguments (马上会讲)
4.2 函数的参数
形参: 定义函数时的列举的变量
实参: 调用函数时所传的值
4.3 函数的默认值
语法:
// es5 的写法, 函数可以不传参调用, 但是不传参 就要写一个默认值
function add(num) {
num = num || 5 // || 前面是true就用前面的, 是false就用后面的
return num + 1
}
// es6 默认值
function add(num = 5) {
return num + 1
}
4.4 arguments
- arguments 是伪数组, 获取函数所传入的所有参数
- arguments 只有es5的写法才有, es6的箭头函数没有
4.5 rest 剩余参数
语法:
// 剩余参数需要注意的点是: 剩余参数一定要放到最后面
const add = (num1, num2, ...nums) => {
console.log(nums) // 会是真正的数组
// 拿到的剩余参数
// 1. 去做循环计算
// 2. 去做判断
// 3. 防止改需求, 要加参数的情况
// ...
}
add(1, 2, 3) // 一三五传 1,2,3
4.6 函数的返回值
return 是函数返回的核心, 如果一个函数, 没有return, 那么肯定没有返回值, 就是 undefined, 有了retrun 那么renturn什么 ,返回值就是什么
4.7 函数对的调用
-
作为一般函数调用
function add() {} add()
-
作为对象函数调用
const obj = { show: function() {} } obj.show()
-
回调函数调用
setTimeout(() => {}, 1000) // 第一个函数的实参是回调函数, 1s之后调用
-
构造函数调用
-
bind(),call(),apply()调用
-
作为立即执行函数调用
4.8 立即执行函数表达式
语法:
;(function() {
console.log('修仙之调用')
})()
作用: 实现模块化
// 1. 在js中使用立即执行函数
// 2. 出口放在window上
5 闭包
概念: 函数跨作用域访问变量, 那么这个函数以及它所访问的变量就形成了闭包
闭包的作用: 变量私有化
5.1 闭包常见的使用场景
-
在嵌套函数中使用
// 一个函数,嵌套着一个函数 叫做嵌套函数 function mom() { var money = 500 function spendMoney() { console.log(money) money -= 100 } return spendMoney } var spend = mom() spend()
-
闭包解决计数器的问题
function add() { var num = 100 return function () { return num++ } } var nums = add() console.log(nums()) console.log(nums()) console.log(nums())
-
闭包解决定时器的问题
for (var i = 0; i < 5; i++) { ; (function (k) { setTimeout(() => { console.log(k) // 0.1.2.3.4 }, 0) })(i) }
-
闭包解决事件绑定的问题
for (var i = 0; i < lis.length; i++) { ; (function (k) { lis[k].addEventListener('click', function () { // 事件绑定是异步的, 放到最后执行, 输出就是全局的i alert(k) }) })(i) }
-
闭包结合IIFE实现模块化(非常经典 --> 现在不用)
作业: 滴滴真题
var b = 'B'
function fun(a, b) {
console.log(b)
return {
fun: function(c) {
return fun(c, a)
}
}
}
var a = fun(0);
a.fun(1);
a.fun(2);
a.fun(3); // 输出什么?
var b = fun(0).fun(1).fun(2).fun(3); // 输出什么? //
var c = fun(0).fun(1);
c.fun(2);
c.fun(3); // 输出什么?
提示:
- 核心输出的是b
- 链式调用, 有返回值才能链式调用
- 最里面return 是函数的调用, 调用就会返回新的返回值
- 最后调用 a 哪里形成了闭包, a就不会被销毁