- 說一下對變量提升的理解
- 說明this幾種不同的使用場景
- 創(chuàng)建10個
<a>標(biāo)簽,點擊的時候彈出來對應(yīng)的序號 - 如何理解作用域
- 實際開發(fā)中閉包的應(yīng)用
執(zhí)行上下文
//Demo
console.log(a) //undefined
var a = 100
fn('greentea') //'greentea' 20
function fn(name){
age = 20
console.log(name,age)
var age
}
- 范圍:一段<script>或者一個函數(shù)
- 全局:變量定義,函數(shù)聲明
- 函數(shù):變量定義,函數(shù)聲明,this,arguments
執(zhí)行上下文,也就是將變量定義和函數(shù)聲明在代碼執(zhí)行前就提前的拿出來,定義的定義,聲明的聲明,但是變量因為沒賦值,所以a是undefined.fn函數(shù)已經(jīng)聲明過了,因此可以盡管去執(zhí)行它.在它的函數(shù)中,也會執(zhí)行上下文,同理,唯一注意的是,函數(shù)中的參數(shù)也相當(dāng)于定義.
關(guān)于函數(shù)聲明和函數(shù)表達式
fn()
function fn(){
}
fn1() //報錯
var fn1 = function (){
}
兩者最大的區(qū)別是函數(shù)表達式相當(dāng)于變量定義,因此fn1 = undefined,在執(zhí)行fn1()時,肯定會報錯.
this
要在執(zhí)行時才能確認值,定義時無法確認
var a = {
name : 'A',
fn : function(){
console.log(this.name)
}
}
a.fn() //this === a
a.fn.call({name:'B'}) //this === {name:'B'}
var fn1 = a.fn
fn1() //this === window
this的幾種情況
- 作為構(gòu)造函數(shù)執(zhí)行
- 作為對象屬性執(zhí)行
- 作為普通函數(shù)執(zhí)行
- call apply bind
call apply bind的區(qū)別
function fn1(name,age){
alert(name)
console.log(this)
}
fn1.call({x:100},'zhangsan',20)
fn1.apply({x:100},['zhangsan',20])
var fn2 = function (name,age){
console.log(this)
}.bind({y:200})
fn2('greentea',20)
this在函數(shù)中時,指向的是window,但是,當(dāng)用call,apply,bind以后,傳入的對象是this.
作用域和作用域鏈
首先,明確一點,JS無塊級作用域
var a = 100
function fn(){
var b = 200
//當(dāng)前作用域沒有定義的變量,即'自由變量'
console.log(a)
console.log(b)
}
fn()
作用域鏈的概念就是當(dāng)前作用域下沒有這個變量或函數(shù)的時候,那么它會向它的父級作用域查找,如果沒有會向父級的父級的作用域找....還有重要的一點就是,函數(shù)的父級作用域是在這個函數(shù)定義的時候,這個函數(shù)的父級作用域就已經(jīng)確定了,而不是在這個函數(shù)執(zhí)行的時候確定的.
閉包
function F1(){
var a = 100
//返回一個函數(shù)(函數(shù)作為返回值)
return function(){
console.log(a)
}
}
//f1得到一個函數(shù)
var f1 = F1()
var a = 200
f1() //100
在這段代碼中,最后的結(jié)果是100,f1執(zhí)行的函數(shù)是在F1中返回的匿名函數(shù),這個匿名函數(shù)是在F1定義的,因此這個匿名函數(shù)的變量應(yīng)該從它定義的父級中去找.
閉包的使用場景:
1.函數(shù)作為返回值
2.函數(shù)作為參數(shù)傳遞
function F1(){
var a = 100
//返回一個函數(shù)(函數(shù)作為返回值)
return function(){
console.log(a)
}
}
//f1得到一個函數(shù)
var f1 = F1()
function F2(fn){
var a = 200
fn()
}
F2(f1) //和上面同理,關(guān)鍵是找對了函數(shù)定義時的父級作用域
下面是一個例子
//舉一個錯誤的例子
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,a
for (i = 0; i < 10; i++) {
(function(i){
a = document.createElement('a')
a.innerHTML = i + '<br>'
a.addEventListener('click',function(e){
e.preventDefault()
alert(i)
})
document.body.appendChild(a)
})(i)
}
關(guān)于閉包的一個應(yīng)用例子
function isFirstLoad(){
var _list = []
return function(id){
if(_list.indexOf(id) >= 0){
return false
}else{
_list.push(id)
return true
}
}
}
var firstload = isFirstLoad()
firstload(10) //true
firstload(10) //false
firstload(20) //true
firstload(20) //false
你在isFirstLoad函數(shù)外,不能修改掉_list的值