閉包
閉包的基本概念
閉包(closure)是JavaScript語言的一個(gè)難點(diǎn),也是JavaScript的一個(gè)特色,很多高級(jí)的應(yīng)用都要依靠閉包來實(shí)現(xiàn)。
閉包的概念
在計(jì)算機(jī)科學(xué)中,閉包(英語:Closure),又稱詞法閉包(Lexical Closure)或函數(shù)閉包(function closures),是引用了自由變量的函數(shù)
在JavaScript中,在函數(shù)中可以(嵌套)定義另一個(gè)函數(shù)時(shí),如果內(nèi)部的函數(shù)引用了外部的函數(shù)的變量,則產(chǎn)生閉包。
-
產(chǎn)生閉包的條件
當(dāng)內(nèi)部函數(shù)訪問了外部函數(shù)的變量的時(shí)候,就會(huì)形成閉包。
閉包的作用
保護(hù)私有變量不被修改
計(jì)數(shù)器
需求:統(tǒng)計(jì)一個(gè)函數(shù)的調(diào)用次數(shù)
var count = 0;
function fn(){
count++;
console.log("我被調(diào)用了,調(diào)用次數(shù)是"+count);
}
fn();
fn();
fn();
缺點(diǎn):count是全局變量,不安全。
使用閉包
function outer(){
var count = 0; // 私有變量, 將count保護(hù)起來了
function add(){
count++;
console.log("當(dāng)前count"+count);
}
return add;
}
?
var result = outer();
result();
斐波那契數(shù)列優(yōu)化
緩存(cache):數(shù)據(jù)的緩沖區(qū),當(dāng)要讀取數(shù)據(jù)時(shí),先從緩沖中獲取數(shù)據(jù),如果找到了,直接獲取,如果找不到,重新去請(qǐng)求數(shù)據(jù)。
計(jì)算斐波那契數(shù)列,會(huì)有很大的性能問題,因?yàn)橹貜?fù)的計(jì)算了很多次,因此我們可以使用緩存來解決這個(gè)性能問題。
初級(jí)優(yōu)化:
使用緩存的基本步驟:
如果要獲取數(shù)據(jù),先查詢緩存,如果有就直接使用
如果沒有,就進(jìn)行計(jì)算,并且將計(jì)算后的結(jié)果放到緩存中,方便下次使用。
//緩存
var arr = [];
var fbi = function (n) {
count++;
if (n == 1 || n == 2) {
return 1;
}
if (arr[n]) {
return arr[n];
} else {
var temp = fbi(n - 1) + fbi(n - 2);
arr[n] = temp;//存入緩存
return temp;
}
}
缺點(diǎn):既然使用緩存,就需要保證緩存的數(shù)據(jù)的安全,不能被別人修改,因此,需要使用閉包來實(shí)現(xiàn)緩存的私有化。
function outer() {
//緩存
var arr = [];
?
var fbi = function (n) {
if (n == 1 || n == 2) {
return 1;
}
if (arr[n]) {
return arr[n];
} else {
var temp = fbi(n - 1) + fbi(n - 2);
arr[n] = temp;//存入緩存
return temp;
}
}
return fbi;
}
var fbi = outer();
console.log(fbi(40));
繼承
現(xiàn)實(shí)生活中的繼承,子承父業(yè), 如兒子繼承了父輩的財(cái)產(chǎn),公司等
程序中的繼承,一個(gè)對(duì)象可以使用另一個(gè)對(duì)象中的方法或?qū)傩?/p>
繼承的目的: 方便代碼的復(fù)用
var lw = {
skill: "翻墻",
age: 28
}
?
function Person(){}
var xm = new Person();
// 如何實(shí)現(xiàn)讓xm可以使用到lw對(duì)象上的skill屬性???
xm.skill; // ==> 翻墻</pre>
JS常見的幾種繼承模式
原型鏈繼承
一個(gè)對(duì)象可以訪問構(gòu)造函數(shù)的原型中的屬性和方法,那么如果想要讓一個(gè)對(duì)象增加某些屬性和方法,只需要把這些屬性和方法放到原型對(duì)象中即可。這樣就實(shí)現(xiàn)了繼承, 稱之為原型鏈繼承
直接給原型增加屬性和方法
原型替換(注意:constructor)
借用構(gòu)造函數(shù)繼承
從構(gòu)造函數(shù)中繼承到構(gòu)造函數(shù)中的成員
function Person(name, age, gender){
this.name = name;
this.age = age;
this.gender = gender;
}
?
function Chinese(name, age, gender, skin){
this.name = name;
this.age = age;
this.gender = gender;
// 以上代碼重復(fù),在構(gòu)造函數(shù)Person中已經(jīng)給this添加
this.skin = skin;
}
?
// 重寫構(gòu)造函數(shù)Chinese
function Chinese(name, age, gender, skin){
// 借用Person構(gòu)造函數(shù),繼承到name、age、gender屬性
Person.call(this, name, age, gender);
this.skin = skin;
}
組合繼承
借用構(gòu)造函數(shù) + 原型鏈繼承組合在一起使用
function Person(name, age, gender){
this.name = name;
this.age = age;
this.gender = gender;
}
// Person原型上的sayHi方法
Person.prototype.sayHi = function(){
console.log("hello, 我是" + this.name);
}
function Chinese(name, age, gender, skin){
// 借用Person構(gòu)造函數(shù),繼承到name、age、gender屬性
Person.call(this, name, age, gender);
this.skin = skin;
}
var xm = new Chinese("xm", 20, "male", "黃色");
// xm有name/age/gender屬性從Person構(gòu)造函數(shù)中繼承到的
// 那么如何讓Chinese的實(shí)例對(duì)象xm去繼承到Person原型上的sayHi方法???
xm.sayHi();