JavaScript中的應知應會

下面的知識點都是JavaScript中常用的特性,掌握這些特性有利於提高對JavaScript使用的熟練程度和提高,網上也有很多資料,以下也是個人的一些總結,我也是初學者,很多知識點還非常欠缺,哪裏理解錯了的,還望有大神不吝賜教,指出……

持續更新中……


1. 閉包

閉包(closure)是Javascript語言的一個難點,也是它的特色,很多高級應用都要依靠閉包實現。

閉包到底是什麼? 閉包有什麼作用,用途? 使用閉包需要注意的點?

問題1:閉包是什麼?

答:我個人的理解是在一個父函數中存在一個或者一組子函數,子函數的相關操作或者返回值中,包含父函數的變量信息,或一些必要的數據,父函數的返回值爲一個子函數,或者一組函數對象。簡單來說就是,閉包就是將函數內部和函數外部連接起來的一座橋樑。

 這裏就是一個簡單的閉包:
 function Func() {
  var name = 'Neo';
  function displayName() {
    alert(name);
  }
  return displayName;
}
var myFunc = Func();
myFunc();

問題2:閉包有什麼作用,用途?

答案:我目前所知道的閉包有兩個重要的用途:
1、如何從函數外部獲取函數內部的變量數據,這時就應用到了閉包。我們知道定義的全局變量可以被函數讀取和使用,但是函數內部的局部變量是不能被函數外部讀取的,這很像面向對象中的封裝特性,把函數內部的字段屬性是私有的,需要讀取這些屬性必須需要暴露一些接口方法(比如:get/set方法), 而在JavaScript中是使用閉包,來讓外部讀取函數內部的變量以進行相關操作。
2、閉包能讓這些變量的值始終保持在內存中。下面代碼解釋了閉包把變量保存在內存中:

function Func1(){
    var n = 999;
    Add = function(){
        n+=1;
    }
    function Func2(){
      alert(n);
    }
    return Func2;
  }
  var result = Func1();
  result(); // 999
  Add(); // Add聲明的是一個全局變量
  result(); // 1000

續上:
(引用阮一峯老師的解釋)
(1)在這段代碼中,result實際上就是閉包Func2函數。它一共運行了兩次,第一次的值是999,第二次的值是1000。這證明了,函數Func1中的局部變量n一直保存在內存中,並沒有在Func1調用後被自動清除。

(2)爲什麼會這樣呢?原因就在於Func1是Func2的父函數,而Func2被賦給了一個全局變量,這導致Func2始終在內存中,而Func2的存在依賴於Func1,因此Func1也始終在內存中,不會在調用結束後,被垃圾回收機制(garbage collection)回收。

(3)這段代碼中另一個值得注意的地方,就是”Add=function(){n+=1}”這一行,首先在Add前面沒有使用var關鍵字,因此Add是一個全局變量,而不是局部變量。其次,Add的值是一個匿名函數(anonymous function),而這個匿名函數本身也是一個閉包,所以這裏Add相當於是一個set方法,可以在函數外部對函數內部的局部變量進行操作。


問題3:使用閉包需要注意的點?
1.慎用閉包,注意內存佔用,因爲它會保存父函數的狀態
2.不要隨便改變父函數內部變量的值

由於閉包會使得函數中的變量都被保存在內存中,內存消耗很大,所以不能濫用閉包,否則會造成網頁的性能問題,在IE中可能導致內存泄露。解決方法是,在退出函數之前,將不使用的局部變量全部刪除。

閉包會在父函數外部,改變父函數內部變量的值。所以,如果你把父函數當作對象(object)使用,把閉包當作它的公用方法(Public Method),把內部變量當作它的私有屬性(private value),這時一定要小心,不要隨便改變父函數內部變量的值。

理解閉包的運行機制:

this 指包含它的函數被執行時所屬的對象

例1:
var name = "The Window"; //在外部若沒有變量定義,則return的值爲undefined

var object = {
    name : "My Object",

  getNameFunc : function(){  
  
      //此時this (這個執行函數)是屬於object對象的,是object對象下的一個屬性的值
      console.log(this == object); //true
      
      return function(){     
       
        //此時this (這個執行函數)是一個匿名函數,從根對象window生成,是屬於window
         console.log(this == window); //true
        return this.name;
        
    };
  }
};
console.log(object.getNameFunc()());  //the window2:
var name = "The Window"; //外部無變量定義,則return的是object內部的My Object

var object = {
    name : "My Object",

    getNameFunc : function(){

        var that = this;    //注意這裏這裏把object對象賦值給一個變量
        console.log(that);  //object{}

      return function(){
          console.log(that == window); //false
          return that.name;  //這裏的that就是object
      };
    }
};
console.log(object.getNameFunc()());   //My Object

2. 原型鏈

原型鏈的概念?
我個人的理解是每個引用類型(對象,數組,函數)都有一個隱式原型,這個隱式原型也是一個對象,每個構造函數都有一個顯式原型,每個實例的隱式原型==該實例構造函數的顯式原型。

例如:
function Foo(name){
    this.name = name; //this == f
}
var f = new Foo('Neo');

//還可用instanceof來判斷屬於什麼類型,順着原型鏈向上搜索
console.log(f.__proto__ == Foo.prototype); //true

一個簡單的原型鏈繼承的例子:
function Car(){
    this.run = function(){
        console.log('Car runs');
    }
}

function Porsche(){
    this.cool = function(){
        console.log('Porsche is cool');
    }
}

console.log(Porsche.prototype); //{constructor : f}

Porsche.prototype = new Car();
console.log(Porsche.prototype); //Car{}
var faker = new Porsche();

faker.run();  //Car runs
faker.cool(); //Porsche is cool

簡單原型鏈圖解如下,手工畫的所以比較醜,見諒(。・ω・。)  ~~

這裏寫圖片描述


3. 跨域

4. 回調

5. 作用域


後面內容待補充~~

參考資料網站:
https://www.cnblogs.com/isdom/p/webclips012.html
http://www.ruanyifeng.com/blog/2009/08/learning_javascript_closures.html
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章