## 1.做用域
<script>
<script>
//做用域
//做用:起做用
//域:範圍
//起做用的範圍
//變量起做用的範圍就是變量的做用域
//1.塊級做用域
//JavaScript中沒有塊級做用域
//若是有塊級做用域下面的代碼的顯示結果爲 undefined undefined
// for(var i=0; i<10;i++){
// var num = i;
// }
// console.log(i);
// console.log(num);
//2.詞法做用域
//就是在代碼寫好的那一刻,變量的做用域就已經肯定了,這種做用域,就是所謂的詞法做用域
//和詞法做用域相對的叫動態做用域 js中是詞法做用域不是動態做用域
// var a = 123;
function f2(){
var a = 456;
function f1(){
console.log(a);
}
}
f2();
//3.在JavaScript中惟一能產生做用域的東西是 函數!
var a = 1;
function test(){
var b = 10;
}
//4.詞法做用域的規則
//函數容許訪問函數外的數據.
//整個代碼結構中只有函數能夠限定做用域.
//做用域規則首先使用提高規則分析
//若是當前做用域中有了該變量, 就不考慮外面的同名變量
</script>
## 2.變量和函數的聲明提高(js代碼的執行過程)
<script>
//js代碼的執行分爲兩個步驟
//1.預解析
//提高(hoisting)
//JavaScript代碼在預解析階段,會對以var聲明的變量名,和function開頭的語句塊,進行提高操做
//2.執行
// func();
// function func(){
// alert("Funciton has been called");
// }
//變量的提高
// alert(a);
// var a = 1;
//提高以後的代碼模擬
// var a;
// alert(a);
// a = 1;
//函數同名,如何提高
//預處理的時候,會將兩個函數所有提高,可是後面的函數會覆蓋掉前面函數
// func1(); //last
// function func1(){
// console.log('This is first func1');
// }
//
// func1(); //last
// function func1(){
// console.log('This is last func1');
// }
// //預解析提高後的代碼
// function func1(){
// console.log('This is first func1');
// }
//
// function func1(){
// console.log('This is last func1');
// }
// func1(); //last
// func1(); //last
//變量和函數同名
//在提高的時候,若是有變量和函數同名,會忽略掉變量,只提高函數
alert(foo); //undefined 函數體
function foo(){}
var foo = 2;
alert(foo); //2
//預解析 提高後的代碼
function foo(){};
alert(foo);
foo=2;
alert(foo);
</script>
## 3.做用域鏈
<script>
//只要是函數就能夠創造做用域
//函數中又能夠再建立函數
//函數內部的做用域能夠訪問函數外部的做用域
//若是有多個函數嵌套,那麼就會構成一個鏈式訪問結構,這就是做用域鏈
//f1--->全局
function f1(){
//f2--->f1--->全局
function f2(){
//f3---->f2--->f1--->全局
function f3(){
}
//f4--->f2--->f1---->全局
function f4(){
}
}
//f5--->f1---->全局
function f5(){
}
}
//變量的搜索原則
//1.在使用變量的時候
//* 首先在所在的做用域中查找
//* 若是找到了 就直接使用
//* 若是沒有找到 就去上級做用域中查找
//2.重複以上步驟
//* 若是直到0級做用域鏈也就是全局做用域尚未找到,報錯
</script>
## 4.閉包(一種現象)
<script>
//一、什麼是閉包
//閉:閉合,關閉,封閉
//包:包裹,包起來
//一個具備封閉的對外不公開的, 包裹結構, 或空間
//二、js中的閉包
//就是函數
//三、閉包的原理就是做用域訪問原則
//上級做用域沒法直接訪問下級做用域中的變量
function f1(){
var num = 123;
function f2(){
console.log(num);
}
f2();
}
//4.閉包要解決什麼問題?
//1.閉包內的數據不容許外界訪問
//2.要解決的問題就是間接訪問該數據
function foo () {
var num = 123;
return num;
}
var x = foo();
console.log(x);
var y = foo();
console.log( x === y );
//用來講明函數的每次調用,返回的對象都是新的 每次都不同
function foo(){
var obj = {
name:"潘文斌",
nickName:"文武寶寶"
}
return obj;
}
var obj1 = foo();
var obj2 = foo();
console.log(obj1 == obj2);
//使用return關鍵字將函數內部的數據返回,這個數據只能被使用一次
function foo(){
var num = 123;
return num;
}
var x = foo();
//1.函數內部的函數中能夠訪問該函數中的變量
//2.可是咱們須要在函數外部去訪問函數中變量
function foo(){
var num = 123;
return function(a){
//1.若是傳參數,這裏的a確定不是Undefined,因此條件判斷爲true
if(a !== undefined){
num = a;
}else{
//若是不傳參,表明要獲取這個值,直接return
return num;
}
};
}
var func = foo();
//設置值
func(789);
//理想狀態下的獲取值
var x = func();
console.log(x);
func(987);
console.log(func());
//1.閉包基本模式
//在外部函數(foo)內建立函數(inner),在這個內部函數(inner)中,能夠操做foo中的數據
//將外部函數的返回值設置爲內部函數
//在外部調用外部函數(foo),就能夠接受到返回值(內部函數)
//使用這個內部函數,就能夠在外部對外部函數裏的變量進行修改
</script>
### 1.使用閉包返回多個值
<script>
function foo() {
var name = "張國榮";
var age = 18;
return [
function(){
return name;
},
function(){
return age;
}
]
}
var getName = foo();
console.log(getName[0]());
console.log(getName[1]());
function foo() {
var name = "張國榮";
var age = 18;
return {
getName:function () {
return name;
},
getAge:function () {
return age;
}
}
}
var obj = foo();
console.log(obj.getName());
console.log(obj.getAge());
2.使用對象返回多個方發法
function foo() {
var name = "高金彪";
var gender = "female";
return {
getName:function () {
return name;
},
setName:function(value){
name = value;
return name;
},
setGender:function(value){
gender = value;
// return gender;
},
getGender:function(){
return gender;
}
};
}
var obj = foo();
console.log(obj.getGender());
console.log(obj.setGender("雄"));
// console.log(obj.getGender());
</script>
### 2.閉包的做用
<script>
function foo(){
var name = "潘明";
var badLevel = -1000000000000000000000000000000000;
return {
getName: function () {
return name;
},
setName: function (value) {
name = value;
return name;
},
getBadLevel:function(){
return badLevel;
},
setBadLevel:function (value) {
//在函數外部想要修改數據
//只能經過函數內部的方法
//咱們能夠在函數內部定義的這個方法裏
//設置安全措施,校驗之類的操做
//能夠保證系統的安全性和穩定性
if(value > 0 ){
throw "你敢說我壞!!!";
}
badLevel = value;
return badLevel;
}
}
}
var obj = foo();
obj.setName("高金彪");
obj.setBadLevel(obj.getBadLevel() * -1 * Math.pow(10,10000000));
console.log(obj.getBadLevel());
//閉包的做用
//最基本的做用:能夠經過閉包返回的函數或者方法,來修改函數內部的數據
//建立一個私有的空間,保護數據
//外部想要訪問數據,只能經過函數提供的方法
//在提供的方法中,咱們能夠設置一些校驗邏輯,讓數據變得更加安全
var name = "";
var age = 19;
//張二狗
name = "二狗";
//隔壁老王
name = "隔壁老王到此一遊";
</script>
### 3.條件式函數聲明
<script>
//條件式函數聲明是否會被提高,取決瀏覽器
//條件式函數聲明不推薦去寫
foo(); //這裏會報錯,由於未被提高
if(true){
function foo(){
console.log("123");
}
}
foo();
</script>
## 5.閉包的總結
### 1.JS中的閉包是什麼
1. 在函數外部訪問不到函數內部的數據
2. 要解決的問題就是須要在外部間接的訪問函數內部的數據
### 2.閉包的做用:
**若是把數據放在全局做用域內,那麼全部人均可以隨意修改,這個數據就再也不可靠。**
**閉包能夠建立一個私有空間,在這個空間內部的數據,外部沒法直接訪問**
**外部空間想要訪問函數內部的數據,只能經過閉包提供的指定的方法,在這個方法內部**
**能夠設置一些校驗規則,讓數據變得更加的安全。**
</script>·