下面的知識點都是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 window
例2:
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