JS基础--作用域

96 阅读3分钟

先抛出几个问题:

  • 说一下对变量提升的理解
  • 说明this的几种不同使用场景
  • 如何理解作用域?
  • 实际开发中闭包的应用?
  • 用JS创建10个<a>标签,点击的时候弹出对应的序号?

作用域

  • JS没有块级作用域
  • 只有函数和全局作用域
//无块级作用域
if(true){
    var name = 'zhangshan'
}
console.log(name)  //'zhangshan'

//函数和全局作用域
var a = 100
function fn () {
    var a = 200
    console.log('fn',a)
}
console.log('global',a) // 'global', 100
fn()  // 'fn', 200

作用域链

var a = 100
function F1 () {
    var b = 200
    function F2() {
        var c = 300
        // 当前作用域没有定义的变量,即“自由变量”
        console.log(a)  // a 是自由变量 
        console.log(b)  // c 是自由变量 
        console.log(c)
    }
    F2()
}
F1()

执行上下文

  • 范围:一段
  • 全局:变量定义、函数声明 (一段
  • 函数:变量定义、函数声明、this、arguments (函数)
console.log(a) //undefined (变量提升)
var a = 100

fn('zhangshan') //'zhangshan'  20
function fn(name) {
    age = 20
    console.log(name, age)
    var age
}

PS: 注意函数声明函数表达式的区别

fn() // undefined
function fn() {
    // 函数声明
}

fn1() // Uncaught TypeError: fn1 is not a function
var fn1 = function() {
    // 函数表达式
}

this

  • 在执行时才能确认值,定义时无法确认
var a = {
    name: 'A',
    fn: function () {
        console.log(this.name)
    }
}
a.fn(); // A
a.fn.call({name: 'B'}) // B
var fn1 = a.fn
fn1() // undefined
  • 作为构造函数执行
  • 作为对象属性执行
  • 作为普通函数执行
  • call apply bind
// 作为构造函数执行
function Foo (name) {
    // this = {}
    this.name = name
    // return this
}
var f = new Foo('zhangshan')

//作为对象执行
var obj = {
    name: 'A',
    printName: function () {
        console.log(this.name)
    }
}
obj.printName()  // 'A';  this 指向 obj

//作为普通函数执行
function fun () {
    console.log(this) 
}
fun()   // this === window

// call
function fn1(name,age) {
    alert(name) // zhangshan
    console.log(this) // {x:100};
}
fn1.call({x:100,},'zhangshan',20) // this === {x:100}

// apply
function fn2(name,age) {
    alert(name)
    console.log(this) // {x:100};
}
fn2.apply({x:100,},['zhangshan',20]) // this === {x:100}

// bind
var fn3 = function (name,age) {
    alert(name) 
    console.log(this) // {y:200};
}.bind({y:200})

fn3('zhangshan',20)   // this === {y:200}

闭包

先看一个例子

function F1 () {
    var a = 100
    // 返回一个函数(函数作为返回值)
    return function() {
        console.log(a)
    }
}
// f1 得到一个函数
var f1 = F1()
var a = 200
f1()

闭包的应用

  • 函数作为返回值
  • 函数作为参数传递
// 函数作为返回值
function F1() {
    var a = 100
    //返回一个函数(函数作为返回值)
    return function() {
        console.log(a) //a作为自由变量,去父作用域寻找
    }
}
var f1 = F1() //f1得到一个函数
var a = 200
f1() // 100
  
//函数作为参数传递
function F1() {
    var a = 100
    return function() {
        console.log(a)
    }
}
var f1 = F1()
function F2(fn) {
    var a = 200
    fn()
}
F2(f1) //100

如何理解作用域

  • 自由变量
  • 作用域链,即自由变量的查找
  • 闭包的2个场景 闭包在实际开发中的应用
// 闭包在实际应用中主要用于封装变量,收敛权限
function isFisrtLoad() {
    var _list = []
    return function (id){
        if(_list.indexOf(id) >=0 ){
            return false
        } else {
            _list.push(id)
            return true
        }
    }
}

// 使用
var firstLoad = isFisrtLoad()
firstLoad(10) // true
firstLoad(10) // false
firstLoad(20) // true

创建10个<a>标签 点击的时候弹出对应的序号

//错误写法
var i, a
for (i = 0; i < 10; i++) {
    a = document.createElement('a')
    a.innerHTML = i + '<br>'
    a.addEventListener('click', function(e) {
        e.preventDefault()
        alert(i)
    })
    document.body.appendChild(a)
}

//正确写法
var i
for (i = 0; i < 10; i++) {
    (function(i) {
        var a = document.createElement('a')
        a.innerHTML = i + '<br>'
        a.addEventListener('click', function(e) {
            e.preventDefault()
            alert(i)
        })
        document.body.appendChild(a)
    })(i)
}