一、閉包
全域變數和區域變數在使用的程序中都各有優點,但它們也都有著自己的不足之處,全域變數的好處是可以被重用,但是極易被污染(注意一般公司中禁止使用一切形式的全域變數),區域變數雖不會被污染,但它無法重用,
為了解決此缺陷,要給一個函式定義一個專屬的且可重用的變數,只有函式自己可用,其他函式不可用時,就用到了閉包!
閉包是既重用變數,又保護變數不被污染的一種編程方法,外層函式呼叫后,外層函式的作用域物件,被內層函式參考著,無法釋放,就形成了閉包物件,閉包的使用分為三步:
(1)用外層函式包裹要保護的變數和使用變數的內層函式
(2)在外層函式內部,回傳內層函式物件,
(3)呼叫外層函式,用變數接住回傳的內層函式物件,
<script>
// 1.用外層函式包裹要保護的變數和內層函式
function mother() {
var total = 1000;
// 2.外層函式回傳內層函式物件
return function (money) {
total -= money;
console.log(`用了${money}元,還剩${total}元`);
}
}
// 3.呼叫外層函式,用變數接住回傳的內層函式
var pay = mother();
pay(100);//剩900
// 此處total的值不會干擾mother函式中定義的值
total = 0;
pay(100);//剩800
pay(100);//剩700
</script>
然而,閉包也存在一定的不足,閉包回傳的記憶體函式,比普通函式多占用一塊記憶體空間(外層函式的函式作用域物件);所以,如果一個閉包不打算再使用了,就應該及時釋放它,
保存內層函式的變數=null,這樣就釋放了內層函式物件,同時也釋放了外層函式的作用域物件,
二、面向物件
程式中將來會保存大量的資料,而大量資料如果零散的隨意管理,極容易出錯!而且用著不方便,所以在今后程式中,都是用面向物件的方式來管理大量資料的,程式中會將描述一個事物的多個屬性和功能集中保存在一個物件結構中,再起一個名字,
面向物件三大特點:封裝、繼承、多型,
1.封裝
封裝是指創建一個物件,集中保存現實其中一個事物的屬性和功能,極其便于大量資料的管理維護,封裝有3種方式:
(1){ },創建一個物件時常用,格式如下
var 物件名={
屬性名: 屬性值,
... : ... ,
方法名: function(){ ... }
}
訪問物件中的屬性或方法時,用--物件.屬性名--或--物件.方法名()--即可,但是直接用{ }進行封裝時,在物件自己的方法內,想使用物件自己的另一個屬性名時,會報錯!說xxx屬性名未定義,解決此問題可用兩種方式:
a:寫死物件名.屬性名,但是一旦物件名發生變化,而物件內寫死的部分物件名,都會報錯!故此方式不推薦,
b:今后,物件中的方法中,只要想使用當前物件自己的屬性或其他方法時,都用加this,this是每個函式內自帶的,不用創建,直接使用專門指向正在呼叫當前函式,
<script>
var lilei = {
sname: "Li Lei",
sage: 11,
intr: function () {
// ----------此處的this指代.前面的物件----------
console.log(`I am ${this.sname},I am ${this.sage}歲`);
}
}
console.log(lilei.sage);
lilei.intr();
lilei.sage++;
console.log(lilei.sage);
lilei.intr();
</script>
(2)new,格式如下
var 物件名=new Object();
提示:function == new Function()
強行給空物件中添加新屬性和新方法,-- 物件名.新屬性=屬性值; --、-- 物件名.新方法=function(){ ... this.屬性名 ... } --,可以看出,js中所有物件底層都是關聯陣列,
在訪問成員時,標準寫法為-- 物件名/陣列名["成員名"] --,簡寫為-- 物件名/陣列名.成員名 --;如果成員名是數字時,只能用-- 物件名/陣列名[數字] --, 如果成員名是變數時,只能用-- 物件名/陣列名[變數] --,不要加引號,
需要注意:強行給不存在的位置賦值,不但不會報錯,而且還會自動添加該屬性;強行訪問不存在的位置的值,都不會報錯,而是回傳undefined,
<script>
var lilei = {};
lilei["sname"] = "lilei";
lilei.sage = 11;
console.log(lilei);
console.log(lilei.className); //undefined 強行訪問不存在的位置的值,都不會報錯,而是回傳undefined
for (var 屬性名key in lilei) {
console.log(`屬性名:${屬性名key},屬性值:${屬性名key}`);
}
var lilei = [];
// js中所有物件底層都是關聯陣列
lilei.sname = "Lilei";
lilei["sage"] = 11;
console.log(lilei);
console.log(lilei["className"]); //undefined
for (var 屬性名key in lilei) {
console.log(`屬性名:${屬性名key},屬性值:${屬性名key}`);
}
</script>
舉例: 克隆一個物件
<script>
var liang = {
sname: "久勝戰神",
sage: 1000,
sex: "男"
}
// 進行克隆
function clone(old) {
// 1.先創建一個空物件等著
var now = {};
// 2.遍歷元物件中的屬性名
for (var oldlist in old) {
// 3.獲取原物件中原屬性值,再添加同名屬性
var oldvalue = old[oldlist];
now[oldlist] = oldvalue;
}
return now;
}
var liang2 = clone(liang);
console.log(liang2);
console.log(liang2 == liang);
</script>
(3)用建構式
用{ }一次只能創建一個物件,如果想創建多個相同結構的物件時,代碼就會很多重復,這樣極其不便于將來的維護,當想反復創建多個相同結構,只是內容不同的物件時,都用建構式,
| 補充:new的四個作用 |
| 1. 創建一個新的空物件等待 |
| 2. 讓子物件繼承建構式的原型物件(繼承專用) |
| 3. 呼叫建構式,將this替換為新物件,通過強行賦值方式為新物件添加規定的屬性 |
| 4. 回傳新物件地址 |
定義建構式:
function 型別名(形參1, 形參2, ...){
//將來要加入到新物件中的規定的屬性
this.屬性名=形參1;
this. xxx = xxx;
this.方法名=function(){ ... this.屬性名 ... }
}
用建構式反復創建多個相同結構的物件:
var 物件名=new 型別名(實參值1, 實參值2, ...)
舉例:定義建構式規定學生型別物件的統一結構
<script>
// 定義建構式
// ---------此處this指代新物件---------
function Student(sname, sage) {
this.sname = sname;
this.sage = sage;
this.intr = function () {
console.log(`我叫${this.sname},我今年${this.sage}歲`);
}
}
// 用建構式反復創建多個相同結構但內容不同的物件
var lilei = new Student("李雷", 45);
var hmm = new Student("韓梅梅", 30);
console.log(lilei);
lilei.intr();
console.log(hmm);
hmm.intr();
</script>
往期JavaScript高級博文鏈接:
JavaScript core(一)
轉載請註明出處,本文鏈接:https://www.uj5u.com/qianduan/298392.html
標籤:其他
上一篇:如使用原生js自定義右鍵選單
