作用域和闭包
题目
● 对变量提升的理解
变量定义
函数声明(注意和函数表达式的区别)
● 说明this集中不同的使用场景
作为构造函数执行
作为对象属性执行
作为普通函数执行
call apply bind
● 创建10个 标签 ,点击的时候但出来对应的序号
//这里就不写用 let 的写法了
var i;
for(i = 0 ; i < 10 ; i++){
(function(i){ //iife
var a = document.createElement('a')
a.innerHTML = i + '<br />'
a.addEventListener('click',function(e){
e.preventDefault()
alert(i)
})
document.body.appendChild(a)
})(i)
}
● 如何理解作用域
自由变量
作用域链,即自由变量的查找
闭包的两个场景
● 实际开发中闭包的应用
//闭包实际应用中主要用于封装变量,收敛权限
function isFirstLoad(){
var _list = []
return function (id) {
_list.push(id)
if(_list.indexOf(id) >= 0){
return false
}else{
return true
}
}
}
//使用
var firstLoad = isFirstLoad()
firstLoad(10) //true
firstLoad(10) //false
firstLoad(20) //true
firstLoad(20) //false
知识点
● 执行上下文
1、 范围 : 一段 script标签 或者一个函数
2、 全局 : 变量定义、函数声明 一段script标签
3、 函数 : 变量定义、函数声明、this、arguments 函数
● this
this 要在执行时才能确认值 , 定义时无法确认
let a = {
name : 'A',
fn : function(){
console.log(this.name)
}
}
let b = {
name:'hong'
}
a.fn() // A
a.fn.call(b) //hong 显示绑定 把this指向b
let fn1 = a.fn
fn1() // 现在的this 指向了 window 所有什么都没有打印
1、作为构造函数执行
function Foo(name){
this = {} //可省略 用 new 关键字自动创建
this.name = name
return this //可省略 用 new 关键字自动返回
}
2、作为对象属性执行
let obj = {
name : 'A',
printName: function(){
console.log(this.name)
}
}
obj.printName() //this 就指向 obj
3、作为普通函数执行
function fn(){
console.log(this) // 如果在浏览器环境下执行 这个this 就是 指向window this === window
}
fn()
4、call apply bind
function fn1(name,age){
console.log(name) //张三
console.log(age) // 20
console.log(this) //{x: 100}
}
fn1.call({x:100},'张三',20) //用第一个参数来当this 后面的参数就是fn1函数的实参
fn1.apply({x:100},['三哥',22]) //apply 也一样,只不过参数变为数组形式
//bind 使用
//错误的示范
// function fn2(name){
// console.log(name)
// console.log(this)
// }.bind({y:200})
//要用函数表达式来使用.bind
let fn2 = function(name){
console.log(name)
console.log(this)
}.bind({y:200})
fn2('zhansan',20)
● 作用域
1、没有块级作用域
if(true){
var name = 'zhangsan'
}
console.log(name)
2、只有函数和全局作用域
var a = 100
function fn() {
var a = 200
console.log('fn',a) //200
}
console.log('global',a) //100 在外面是访问不到函数里面的变量
fn()
● 作用域链
var a = 100
function fn() { //这里处于 fn函数里面的作用域 它的父级作用域是全局作用域
var b = 200
// 当前作用域没有定义的变量,即'自由变量'
console.log(a)
console.log(b) // 这个作用域没有定义变量b ,但是会往上一层作用域去查找 , 一层一层往上找,直到找到或者没找到
//注意:函数父级作用域是函数定义的时候决定的,不是执行的时候决定的
}
fn()
// 例如
var a = 100
function F1(){ // F1的父作用域是全局作用域
var b = 200
function F2() { // F2的父作用域是F1
var c = 300
console.log(a); // a 是自由变量 往上找
console.log(b); // b 是自由变量 往上找
console.log(c);
}
F2()
}
● 闭包
1、函数作为返回值
function F1() {
var a = 100 //2. 找到了a
//返回一个函数(函数作为返回值)
return function () { // 用一个函数作为返回值
console.log(a) //1. a 是自由变量 这个作用域没有定义a 就会往上一级作用域找a
}
}
//f1 得到一个函数
var f1 = F1() // 这样用中文解释就是 用 f1这个变量接收 F1() 函数调用返回的返回值 这个返回值是一个函数
var a = 200 // 全局作用域的 a 并不能影响函数里面的 a
f1() // 因为这个返回值是一个函数 所有可以用() 来调用 虽然是在全局作用域下执行 但是函数的作用域并不是看在哪里执行的 而是看在哪里定义的
2、函数作为参数传递
function F1() {
var a = 100
return function () {
console.log(a) // 自由变量,父作用域寻找
}
}
var f1 = F1()
function F2(fn){ //接收f1函数
var a = 200
fn() //调用函数
}
F2(f1) // 打印100 这里是在F2作用域下执行 f1函数 ,F2的 a 并没有影响到 f1里面的 a ,证明了函数的作用域并不是看在哪里执行的 而是看在哪里定义的