JavaScript
理解 js 的作用域,作用域链,闭包
作用域 作用域就是执行上下文,在执行上下文中会有内存分配与执行两个阶段。变量的的生命周期:声明,初始化,赋值 变量提升 在全局作用域或者函数作用域 var 声明变量允许在声明之前使用,值为 undefined,这个就是变量提升 块级作用域中声明的变量会提升到该作用域的头部,即允许在实际声明前使用 暂时性死区 在全局作用域或者函数作用域 let 或 const 声明变量,只允许在声明之后访问,在作用…
作用域 作用域就是执行上下文,在执行上下文中会有内存分配与执行两个阶段。变量的的生命周期:声明,初始化,赋值 变量提升 在全局作用域或者函数作用域 var 声明变量允许在声明之前使用,值为 undefined,这个就是变量提升 块级作用域中声明的变量会提升到该作用域的头部,即允许在实际声明前使用 暂时性死区 在全局作用域或者函数作用域 let 或 const 声明变量,只允许在声明之后访问,在作用…
作用域就是执行上下文,在执行上下文中会有内存分配与执行两个阶段。变量的的生命周期:声明,初始化,赋值
变量提升
在全局作用域或者函数作用域 var 声明变量允许在声明之前使用,值为 undefined,这个就是变量提升
块级作用域中声明的变量会提升到该作用域的头部,即允许在实际声明前使用
暂时性死区
在全局作用域或者函数作用域 let 或 const 声明变量,只允许在声明之后访问,在作用域头部到声明变量处就叫暂时性死区,暂时性死区不能访问变量
var name = 'koa';
普通函数作用域
function koa() {
var name2 = 'koa';
}
i 被提升到了当前函数作用域头部
var callbacks = [];
for (var i = 0; i < 2; i++) {
// 这里面的i为全局作用域
callbacks[i] = function() {
return i;
};
}
console.log(callbacks[0]());
console.log(callbacks[1]());
// 输出
// 2
// 2
解决访问:用闭包,把 i 以参数的形式传给内层函数
var callbacks2 = [];
for (var i = 0; i < 2; i++) {
(function(i) {
// 这里面的i为函数作用域
callbacks2[i] = function() {
return i;
};
})(i);
}
console.log(callbacks2[0]());
console.log(callbacks2[1]());
// 输出
// 0
// 1
用块级作用域解决变量提升问题
let callbacks3 = [];
// let让for循环变成块级作用域
// 块级作用域又把声明的变量提升到作用域顶部
for (let i = 0; i <= 2; i++) {
// 这里的 i 属于当前块作用域
callbacks3[i] = function() {
return i;
};
}
console.log(callbacks3[0]());
console.log(callbacks3[1]());
// 输出
// 0
// 1
function fn() {
console.log(a);
}
function fn2() {
var a = 3;
fn();
}
var a = 2;
fn2();
// 输出
// 2
fn 函数定义在作用域链中,scope 一定是局部变量,不管如何执行 fn,访问的永远是局部变量
var scope = 'global scope';
function checkscope() {
var scope = 'local scope';
function f() {
return scope;
}
return f();
}
console.log(checkscope());
// 输出
// local scope
fn 函数定义在作用域链中,scope 一定是局部变量,不管如何执行 fn,访问的永远是局部变量
var scope = 'global scope';
function checkscope2() {
var scope = 'local scope';
function f() {
return scope;
}
return f;
}
console.log(checkscope2()());
// 输出
// local scope
当访问一个变量的时候,解释器先会在当前作用域查找该变量标识符,如果没找到就去父作用域找,直到找到该变量的标识符
有权访问-另一个函数-作用域中的-变量的-函数
function bar() {
var date = '进阶';
function foo(str) {
console.log(str + date);
}
return foo('前端-');
}
bar();
// 输出
// 前端-进阶
function bar2() {
var date = '进阶';
function foo2(str) {
console.log(str + date);
}
return foo2;
}
bar2()('前端-');
bar2()('前端再-');
// 输出
// 前端-进阶
// 前端再-进阶
function bar3() {
var count = '进阶';
function foo3(val) {
count = val;
console.log('前端-' + count);
}
return foo3;
}
bar3()('学习');
// 输出
// 前端-学习
优点
缺点
// 普通方法防抖
window.onresize = debounce(function() {
console.log('普通方法防抖');
}, 1000);
var time = '';
function debounce(fn, timeLong) {
if (time) {
clearTimeout(time);
time = '';
}
time = setTimeout(function() {
fn();
}, timeLong);
}
// 闭包方法防抖
window.onresize = debounce2(function() {
console.log('闭包方法防抖');
}, 1000);
function debounce2(fn) {
var timer = null;
return function() {
if (timer) {
//timer第一次执行后会保存在内存里 永远都是执行器 直到最后被触发
clearTimeout(timer);
timer = null;
}
timer = setTimeout(function() {
fn();
}, 1000);
};
}
// 普通方法设置私有变量
class Private {
constructor(s) {
this.myname = s;
}
foo() {
console.log(this.myname);
}
}
var p = new Private('he');
p.foo();
// 闭包方法设置私有变量
let sque = (function() {
class Squery {
constructor(s) {
this.myname = s;
}
foo() {
console.log(this.myname);
}
}
return Squery;
})();
let ss = new sque('jian');
ss.foo();
// 普通方法没有拿到i
var callbacks = [];
for (var i = 0; i < 2; i++) {
// 这里面的i为全局作用域
callbacks[i] = function() {
return i;
};
}
console.log(callbacks[0]());
console.log(callbacks[1]());
// 输出
// 2
// 2
// 使用闭包可以
var callbacks2 = [];
for (var i = 0; i < 2; i++) {
(function(i) {
// 这里面的i为函数作用域
callbacks2[i] = function() {
return i;
};
})(i);
}
console.log(callbacks2[0]());
console.log(callbacks2[1]());
// 输出
// 0
// 1
上面的例子是用数组,在真实业务中,有可能是一个 dom 点击事件,比如下面例子
// 比如dom点击事件
var ps = document.getElementsByTagName('p');
for (var i = 0; i < ps.length; i++) {
ps[i].onclick = function() {
alert(i);
};
}
用闭包解决
var ps = document.getElementsByTagName('p');
for (var i = 0; i < ps.length; i++) {
(function(i) {
ps[i].onclick = function() {
alert(i);
};
})(i);
}
用块级作用域解决
let ps = document.getElementsByTagName('p');
for (let i = 0; i < ps.length; i++) {
ps[i].onclick = function() {
alert(i);
};
}
暂无评论
确认操作
请再次确认编辑图片
待上传图片 (剩余 0 张)
项目详情
确认评论邮箱
邀请制评论