//------------------題目------------------------->
1.說一下對變量提升的理解
針對兩個場景一個script、一個是構(gòu)造函數(shù)中俄删,它的變量的聲明和定義
以及函數(shù)的聲明都會被提前,放在前面过咬,所以會導(dǎo)致我們有變量提升主觀上的理解壳猜。(執(zhí)行上下文的知識)
*1虹曙、變量定義
*2谷誓、函數(shù)聲明(注意和函數(shù)表達式的區(qū)別)
2.說明this集中不同使用場景
*1绒障、作為構(gòu)造函數(shù)執(zhí)行
*2、作為對象屬性執(zhí)行
*3捍歪、作為普通函數(shù)執(zhí)行
*4户辱、call apply bind
3.創(chuàng)建10個<a>標簽,點擊時候彈出來對應(yīng)的序號
var i ;
for(i=0;i<10;i++){
//自執(zhí)行函數(shù)糙臼,就是不用調(diào)用庐镐,只要定義完成,立即執(zhí)行的函數(shù)
(function(i){
// 函數(shù)作用域
var a = document.createElement('a');
a.innerHTML = i+'<br>';
a.addEventListener('click',function(e){
e.preventDefault();
alert(i);//自由變量变逃,要去父級作用域獲取值
});
document.body.appendChild(a);
})(i);
}
//閉包或者作用域使用的問題
4.如何理解作用域
*自由變量
*作用域鏈必逆,即自由變量的查找
*閉包的兩個場景
5.實際開發(fā)中閉包的應(yīng)用
//閉包是作用域知識點的實際應(yīng)用
//閉包實際應(yīng)用中主要用于封裝變量,收斂權(quán)限\
// 判斷用戶是不是第一次加載
function isFirstLoad(){
//把存儲數(shù)據(jù)的數(shù)據(jù)源存起來,其他外邊拿不到
var _list = [];//變量前面有下劃線名眉,說明這個是私有變量
return function(id){
if(_list.indexOf(id) >=0){
return false;
}else{
//_list這里是自由變量粟矿,要去它定義的父作用域去找
_list.push(id);
return true;
}
}
}
//使用
var firstLoad = isFirstLoad();
firstLoad(10); //true
firstLoad(10); //false
firstLoad(20); //true
firstLoad(20); // false
//在isFirstLoad函數(shù)外邊,根本不可能修改掉_list的值
//*******************知識點*******************************
一璧针、執(zhí)行上下文
范圍:一段<script>或者一個函數(shù)
全局:變量定義、函數(shù)聲明
【一段<script>會生成一個全局的執(zhí)行上下文渊啰,執(zhí)行之前先去
把變量定義探橱、函數(shù)聲明拿出來】
函數(shù):變量定義、函數(shù)聲明绘证、this隧膏、arguments
**【針對一個函數(shù),會出現(xiàn)一個函數(shù)執(zhí)行上下文嚷那,函數(shù)執(zhí)行之前
先把函數(shù)中的變量定義胞枕、函數(shù)聲明、this魏宽、arguments(函數(shù)
中所有參數(shù)的集合)拿出來】**
PS:注意‘函數(shù)聲明’和‘函數(shù)表達式’的區(qū)別:
【函數(shù)聲明】:
//如果這里執(zhí)行fn();不會報錯;
/*這段程序執(zhí)行之前會把聲明的
函數(shù)提到前面去腐泻,先聲明出來,執(zhí)行不會報錯*/
function fn(name){
age = 20;
console.log(name,age);
var age;
}
【函數(shù)表達式】:
(本質(zhì)上執(zhí)行的只是這個變量队询,并不是把函數(shù)聲明提前了)
//在這里執(zhí)行fn1();會報錯派桩;
/*所有var fn1,在執(zhí)行之前不是個函數(shù)蚌斩,在執(zhí)行之前會把var fn1
提到前面去,并且賦值成undefined,var fn1并沒有去執(zhí)行*/
var fn1 =function(){};
/*在執(zhí)行第一行之前铆惑,會把所有的變量的聲明和函數(shù)聲明都拿出來*/
// 寫程序先定義會執(zhí)行(增加代碼可讀性))
eg. 1.
/*
全局函數(shù)作用域(會把變量的聲明,和函數(shù)的聲明挪到前面去送膳,
先聲明了员魏;函數(shù)的聲明是把函數(shù)挪前面去了,變量的聲明把變量挪
前面去了叠聋,并且賦值undefined撕阎,占位)
*/
console.log(a);//undefined
var a = 100;
eg.2.
fn('zhangsan');//'zhangsan' 20
function fn(name){
/*都會把變量提前,都會把函數(shù)提前*/
/*在函數(shù)執(zhí)行之前碌补,this闻书、arguments已經(jīng)確定了值*/
console.log(this);//window
/*["zhangsan",callee:function,
symbol{symbol.iteareator}:function]*/
console.log(arguments);
age = 20;
console.log(name,age);
var age;
}
二、this
1.this要在執(zhí)行時才能確認值脑慧,定義時無法確認
1.作為構(gòu)造函數(shù)執(zhí)行
function Foo(name){
//this = {};
this.name = name;
//return this;
}
var f = new Foo("zhangsan");
2.作為對象屬性執(zhí)行
var obj = {
name:"A",
printName:function(){
console.log(this.name);
}
};
obj.printName();
3.作為普通函數(shù)執(zhí)行(this應(yīng)該是window)
function fn(){
console.log(this);// this === window
}
fn();
4.call apply bind
/**call apply **/
function fn1(name,age){
alert(name);
console.log(this);//this就是第一個參數(shù)
};
/*執(zhí)行fn1這個函數(shù)魄眉,用{X:100}當this,"zhangsan"
當?shù)谝粋€參數(shù)*/
fn1.call({X:100},"zhangsan",20);
//會把后面的參數(shù)當數(shù)組來傳遞
fn1.apply({X:100},['zhangsan',20]);
/**bind**/
var fn2 = function (name,age){
alert(name);
console.log(this);
}.bind({Y:200});
//沒bind之前this是window闷袒;bind之后this是{Y:100}
fn2('zhangsan',20);
eg:
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;
// this === window; this.name是undefined或者其他值
fn1();
三坑律、作用域
1.JS沒有塊級作用域
2.只有函數(shù)和全局作用域
//------ 無塊級作用域--------------
if(true){
var name = 'zhangsan';
}
console.log(name); //zhangsan
// 和把name在外邊定義然后再if中賦值是一樣的
// 推薦寫法:在外邊定義然后再下面賦值
var name;
if(true){
name = 'zhangsan';
}
console.log(name);
//---------- 函數(shù)和全局作用域--------------
//這個a是全局的,誰都可以獲取,誰都可以改(不安全)
var a =100;
function fn(){
/*函數(shù)中定義晃择,和外邊是隔絕的冀值,外邊是改不了的;
從外邊得不到宫屠,也改不了列疗,只能從函數(shù)里去用;
防止自己的變量被污染浪蹂,把所有變量都定義在一個大的函數(shù)里
*/
var a =200;
console.log('fn',a);//在函數(shù)范圍內(nèi)獲取
}
console.log('global',a);
fn(); // global: 100; fn :200
四抵栈、作用域鏈
(一個自由變量一直不斷的往父級作用域去找,形成一個鏈式結(jié)構(gòu))
-- 哪個作用域定義了這個函數(shù)坤次,這個函數(shù)父級作用域就是誰古劲,和函數(shù)執(zhí)行沒有關(guān)系
//作用域完整的使用形式、場景
1.eg:
var a =100;
function fn(){
var b =200;
//當前作用域沒有定義的變量缰猴,即“自由變量”
/*函數(shù)體內(nèi)沒規(guī)定a是誰产艾,但是打印a,就要向父級作用域
找a滑绒,父級作用域是全局作用域闷堡,所以a就找到var a =100;
函數(shù)父級作用域是什么疑故,是函數(shù)定義的時候的父級作用域
缚窿,不是函數(shù)執(zhí)行時候的作用域*/
console.log(a);
console.log(b);
}
fn();
2.eg:
var a =100;
function F1(){
var b =200;
function F2(){
var c = 300;
console.log(a); //100 a是自由變量
console.log(b); //200 b是自用變量
console.log(c); //300
}
F2();
}
F1();
五、閉包(作用域鏈的具體應(yīng)用)
閉包的使用場景:
1.函數(shù)作為返回值
2.函數(shù)作為參數(shù)傳遞(把函數(shù)傳遞到另一個函數(shù)中執(zhí)行)
eg:1.函數(shù)作為返回值
//F1 這個函數(shù)最終返回的是一個函數(shù)
function F1(){
/*F1作用域里面的a*/
var a =100;
/*
返回一個函數(shù)焰扳;
*/
return function(){
/*
a是自由變量倦零,自由變量去父級作用域(F1)找;
一個函數(shù)的父級作用域吨悍,是它定義時候的作用域扫茅,
而不是執(zhí)行時候的作用域
*/
console.log(a);
}
}
//把F1()賦值給f1,f1就是一個函數(shù)了
var f1 = F1();
/*是全局作用域里面的a*/
var a =200;
f1(); //100
eg:2.函數(shù)作為參數(shù)傳遞
function F1(){
var a =100;
//F1返回一個函數(shù)
return function(){
console.log(a);
}
}
//把F1()賦值給f1育瓜,f1就是一個函數(shù)了
var f1 = F1();
function F2(fn){
var a =200;
fn();
}
F2(f1);//100