背就完事了
理解小帮手
关于作用域,作用域链,以及变量提升和var,let,const和闭包的相关知识
下面通过代码分析来加深认识
注: 建议将复制到浏览器控制台,或者node环境下执行,手机的话建议横屏~
var count = 0 // 用来标识打印的序号
console.log(++count, song) // 输出:1 undefined 解析:变量提升
// console.log(++count, artist) // 报错:'artist'不能在变量声明前使用 解析:let没有变量提升
var song = '说好不哭'
let artist = '奶茶伦'
const favorite = '奶茶'
const girlfriend = {
name : '蔡依林'
}
console.log(++count, window.song) // 输出:2 说好不哭 解析:最外层用var声明会挂载到window上
console.log(++count, window.artist) // 输出:3 undefined 解析:let声明不会挂载到window
for(var i = 0; i < 10; i++ ) {} // 在for中用var声明变量i
for(let j = 0; j < 10; j++ ) {} // 在for中用let声明变量j
console.log(++count, i) // 输出:4 10 解析:var没有块作用域
// console.log(++count, j) // 报错:j没有被定义 解析:let有块作用域
// favorite = '咖啡' // 报错:常量被赋值 解析:const声明的变量不能被重新赋值
girlfriend.name = '昆凌'
console.log(++count, girlfriend) // 输出:5 {name:'昆凌'} 解析:const声明的引用类型可以被改变
function cooperate () {
console.log(++count, song) // 输出:6 说好不哭 解析:作用域链,往上层作用域找song
var feat = undefined
function getFeat (artistName) { // 闭包 - 函数嵌套
feat = artistName
return feat
}
return getFeat // 将闭包暴露出来
}
// console.log(++count, feat) // 报错:feat没有被定义 解析:feat在函数cooperate的作用域中,属于局部变量
var getFeat = cooperate() // 创建一个闭包
console.log(++count, getFeat('阿信')) // 输出:7 阿信 解析:通过闭包成功打印cooperate函数中的feat属性
getFeat = null // 闭包使用后需要手动释放,不然会造成内存泄漏
相关笔试题思考
前端面试的笔试题或多或少会有一至两道考核作用域的题目,如以下经典例子
function p1() {
console.log(1);
}
function p2() {
console.log(2);
}
(function () {
if (false) {
function p1() {
console.log(3);
}
}else{
function p2(){
console.log(4)
}
}
p2();
p1()
})();
解决这类问题的关键在于
- 将所有变量,在纸上手动提升了再说,脑补容易有疏漏
- 通过function 声明的函数,也别忘了进行变量提升(function p1(){} 等同于 var p1 = function () {})
- 分析作用域,一般会拿var没有块作用域来整事
var p1; // p1 = undefined 解析:变量提升
var p2; // p2 = undefined - 变量提升
function p1() { // p1 = function () { 1 }
console.log(1);
}
function p2() { // p2 = function () { 2 }
console.log(2);
}
(function () { // 匿名函数作用域
var p1; // p1 = undefined 解析:变量提升,function p1(){} 等同于 var p1 = function () {},var没有块作用域
var p2; // p2 = undefined 解析:变量提升
if (false) {
function p1() { // p1 = undefined 解析:因为if(false),这块代码不会执行
console.log(3);
}
}else{
function p2(){ // p2 = funtcion() { 4 }
console.log(4)
}
}
p2(); // 在当前作用域找到了p2,打印4
p1() // 在当前作用域找到了p1,报错:p1 is not a function
})();
以上!
Kane -- 一切都是命运石之门的选择