一、 全局作用域与局部作用域
-
全局的对象和函数都能被调用
-
局部的对象和函数只能在局部作用域中使用
- 局部变量仅在函数的执行期间可用,函数执行完,局部变量将不能被访问
能够调用上一级的对象和函数,作用域链
var val = 12;
function fun1(){
console. log(val); //12
var a = 20;
console.log(a); //20
}
fun1();
二、使用函数内的变量与函数,涉及到闭包
普通的函数嵌套:
function init() {
var name = "Mozilla"; // name 是一个被 init 创建的局部变量
function displayName() { // displayName() 是内部函数,一个闭包
console.log(name); // 使用了父函数中声明的变量
}
displayName();//Mozilla
}
init();
闭包:函数嵌套函数,里面的函数就是闭包 内部的函数需要返回 。闭包里面有变量有函数
function fn() {
var name = "Mozilla"; // name 是一个被 fn创建的局部变量
function displayName() { // displayName() 是内部函数,一个闭包
alert(name); // 使用了父函数中声明的变量
}
return displayName;
}
fn();
内部displayName函数在执行前被外部函数返回
简单用法
function fn() {
var max = 10;
return function (x) {
if (x > max) {
console.log(x);
}
};
}
var aa = fn();
aa(12)
作用:
闭包封装一段代码实现隐藏变量,但不会造成内存泄露(变量没有用,占据内存)
但是因为闭包一直存在与内存中,所以会造成性能的降低,需要手动将不需要的闭包解除掉,可以用(=null)来处理
三、闭包的经典用法,防抖与节流
1、防抖
用户操作次数过多,只要最后一次的操作
例如,搜索某关键字,输入完成页面就能出现响应内容,设置0.5秒后用户不再输入,视为输入结束。此时做出回应,向服务器请求命令。
let inp = document.querySelector("input");
inp.oninput = debounce(function () {
// console.log(this, "window对象"); //为什么没改之前 这里是window对象
console.log(this.value);
}, 500)
function debounce(fn, delay) {
let t = null;
return function () {
if (t !== null) {
clearTimeout(t);
}
t = setTimeout(() => {
// console.log("this指向input", this);
fn.call(this);//调用的时候改变指向对象 input调用
}, delay)
}
}
2.节流
用户滚动侧边栏时,加载次数过多,我们通过节流,减少加载次数
window.onscroll = throttle(function () {
console.log("hello world");
}, 500)
function throttle(fn, delay) {
let flag = true;
return function () {
if (flag) {
setTimeout(() => {
fn.call(this);
flag = true;
}, delay)
}
flag = false;
}
}