2020-04-04 JavaScript高級(jí)

閉包

閉包的基本概念

閉包(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();
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容