1. *****作用域和作用域鏈
2. *****閉包
1. *****作用域和作用域鏈
作用域scope:
什麼是: 一個變量的使用範圍——使用
本質上作用域是一個對象——存儲
作用域中的變量都是對象的成員
程序/函數的執行過程:
1. 開始執行程序前:
創建ECS(執行環境棧):
依次保存每個調用的函數的執行環境
在ECS中壓入第一個全局執行環境(全局EC)
創建window對象,全局EC引用window對象
window就是全局作用域對象
2. 開始執行程序:
所有全局變量都保存在全局作用域對象window中
3. 定義函數時:
在全局添加函數名變量
創建函數對象封裝函數定義
函數名變量引用函數對象
函數對象中有一個scope屬性,引用回創建函數時的作用域對象。通常都是window。
4. 調用函數時:
在ECS中壓入一個新的EC
爲本次函數調用創建專門的活動對象(AO)
在AO中創建所有函數定義中規定的局部變量
其實AO就是函數作用域對象
所有局部變量都是AO的成員
新的EC引用活動對象AO
AO的parent指向window
變量的使用順序:
先用AO(函數作用域)中的局部變量
如果AO中沒有,纔去window(全局作用域)中找
5. 函數調用後:
本次函數調用的EC出棧
導致函數作用域對象AO釋放
導致局部變量一同釋放
作用域鏈(scope chain): 由多個作用域對象連續引用形成的鏈式結構。
順序: 先函數作用域對象AO->全局作用域對象window
所有的變量都保存在作用域鏈上的對象中
局部變量都保存在函數作用域對象AO中
全局變量都保存在全局作用域對象window中
控制了: 變量的使用順序
先用AO(函數作用域)中的局部變量
如果AO中沒有,纔去window(全局作用域)中找
閉包:
什麼是: 即重用變量,又防止變量被污染的一種機制
爲什麼: 全局變量: 優: 可重用 缺: 易被全局污染
局部變量: 優: 不會被污染 缺: 不可重用
何時: 即重用變量,又防止變量被污染
如何: 3步:
1. 用外層函數包裹住受保護的變量和操作變量的內層函數
2. 外層函數將內層函數返回到外部,被外部的變量保存
3. 通過外部變量調用內層函數,訪問受保護的變量
缺: 1. 佔用更多內存: 外層函數的AO
2. 容易造成內存泄漏
三特點: 1. 函數嵌套:
2. 外層函數包含一個受保護的局部變量
3. 外層函數將內層函數對象返回
1. *****面向對象OOP:
什麼是: 程序中都是先用對象來定義數據和功能,再按照邏輯的需要,訪問對象中的數據和功能。
爲什麼: 和現實中人的想法非常接近。
什麼是對象: 內存中同時存儲多個數據和功能的存儲空間
描述現實中一個具體事物的屬性和功能的程序結構
事物的屬性,會成爲對象中的屬性
事物的功能,會成爲對象中的方法
何時: 今後開始寫程序前,都要先用對象,描述好要操作的事物的屬性和功能,再按需使用對象的功能,訪問對象的屬性
如何: 面向對象三大特點: 封裝,繼承,多態
封裝: 將一個具體事物的屬性和功能集中定義在一個對象中
創建自定義對象: ——封裝 3種:
1. 使用對象直接量:
var obj={
屬性名: 屬性值,
... : ... ,
方法名: function(){... this.屬性名 ...},
... : ... ,
}
強調: 對象自己的方法,要訪問自己的屬性,必須用this.屬性名.
this->正在調用函數的當前對象自己
2. 使用new: 2步:
var obj=new Object(); //創建一個空對象
//向空對象中添加屬性和方法
obj.屬性名=屬性值;
obj.方法名=function(){...this.屬性名...};
對象的本質: js中一切對象的底層都是關聯數組
每個屬性/方法都是關聯數組中的元素
屬性名/方法名是key,屬性值/函數對象是value
問題: 一次只能創建一個對象
3. 解決: 用構造函數:
什麼是構造函數: 專門描述一類對象統一結構的函數
何時: 今後只要反覆創建多個相同結構的對象時,都要先定義構造函數
爲什麼: 複用對象的結構代碼
如何: 2步:
1. 定義構造函數
function 類型名(屬性參數列表){
this.屬性名=屬性參數值;
...=...;
this.方法名=function(){ ... this.屬性名 ... }
}
2. 用new調用構造函數,創建並裝修新對象
var obj=new 類型名(屬性值列表);
創建一個指定“類型”的對象
用new調用指定"類型"的構造函數來創建對象
new: 4件事:
1. 創建新的空對象
2. 讓新對象繼承構造函數的原型對象
3. 用新對象去調用構造函數
向新對象中添加構造函數規定的屬性
將屬性參數的值,保存到新對象的新屬性中
向新對象中添加構造函數規定的方法
4. 將新對象的地址保存在變量
按需訪問對象的屬性,調用對象的方法:
訪問對象的屬性: obj.屬性名 用法和普通的變量完全一樣
屬性就是保存在對象中的一個變量
調用對象的方法: obj.方法名() 用法和普通的函數完全一樣
強調: 方法中的this,默認指.前的對象
構造函數的問題: 只能複用代碼,不能節約內存
繼承: 父對象的成員,子對象不用重複創建,也可直接使用
爲什麼: 即節約內存,又代碼重用
何時: 只要一類子對象,需要相同的屬性或功能時,都要將相同的屬性和功能僅在父對象中定義一次即可
如何:
原型對象: 集中存儲同一類型的子對象所需的所有共有屬性和方法的父對象