《JavaScript設計模式》Stoyan Stefanov-讀書筆記

第一章  簡介

1、三種類型模式javascript

  設計模式、編碼模式、反模式java

 

2、JavaScript基本概念設計模式

一、面向對象瀏覽器

  五種基本類型:數字、字符串、布爾、undefine、null緩存

  函數也是對象,也有屬性和方法安全

 

  對象有兩種類型:一、原生的 ECMAScript  二、主機的,在主機環境中定義,如瀏覽器閉包

  原生包括:內置對象和用戶自定義對象app

  主機包括:window對象和全部DOM對象函數

 

二、原型工具

  原型是個對象,每一個都會自動獲取一個Prototypes屬性,該屬性指向一個新的空對象

  

三、JSLint

  javascript是一門解析語言沒有靜態編譯時檢查,JSLint是檢查JavaScript代碼質量的工具

 

第二章  基本技巧

  本章討論一些高質量代碼的核心方法、模式和習慣,如避免全局變量、使用單個變量var的聲明、循環中緩存長度變量length和符合代碼的約定.

 

1、編寫可維護代碼

一、減小全局變量

  全局對象能夠在函數外部使用this訪問

  mylobal = "hello";    // 全局變量

  console.log(mylobal);

  console.log(window.mylobal);

  console.log(window["mylobal"]);

 

  全局變量的問題:一、第三方Javascript庫  二、廣告合做夥伴的腳本 

  釋放變量:使用var 建立的變量不能刪除,不使用var建立的隱含全局變量能夠刪除,隱含變量不是真正的變量,而是全局對象的屬性,能夠經過delete刪除

  // 定義三個全局變量

  var global_var = 1;

  global_noar = 2;

  (function(){

    global_fromfunc = 3;

  })

  delete  global_var;  // false

  delete  global_noar;  // true

  delete  global_fromfunc;   // true

 

二、單一的var模式 

  用一個var在函數頂部進行變量的聲明

  var a = 0,

      b = 1;

 

三、for循環

  當遍歷時存儲長度,

  var oLi = document.getElementsByTagName("li");

  for(var i=0, len=oLi.length; i< len; i++){    ...   } 

 

四、不在增長內置的原型

  就是別在內置的構造函數內增長新功能,

 

五、switch模式

  提升switch的可讀性和健壯性

  var inspect = 0, result = "";

  swith(inspect){

    case 0:

      result = "zero"; break;

    case 1:

      result = "one"; break;

    default:

      retult = "unknown";

  }

  若是不寫break語句會接着向下執行

 

6 、parseInt()的數值約定

  parseInt()從一個字符串中獲取數值,第二個參數爲進制,但若是字符串爲0開頭就必須寫進制,如"08",parseInt("08", 10);不然在ie下會輸出

  另外一種寫法能夠:

  +"08";  或者   Number("08")    

 

 

第三章  字面量和構造函數

1、對象字面量

  // 定義一個空對象

  var dog = {};

 

  // 向對象加一個屬性和方法

  dog.name = "benji";

  dog.getName = function(){

    return dog.name;

  }

 

2、構造函靈敏

1 var Person = function(name){
2     this.name = name;
3     this.say = function(){
4         return this.name;
5     }
6 }

 

  構造函數原型prototyp的做用

  將say方法添加到this中,若是在任什麼時候間調用new Person()時都會在內存中建立一個新的函數,會使效率低下,由於建立多個person實例時也會建立多個say方法,解決方法是將他們添加到原型中prototype

 

第四章  函數

  函數的兩個特色:一、函數是一類對象     二、函數能夠提供一個做用域

 

一、全局做用域:function foo(){}

二、局部做用域:

function local(){

  // 局部做用域

  function bar(){};

  return bar;

}

三、函數表達式  var bar = function(){  ...  }

四、匿名函數  function(){ ... };  沒有名稱,在自動函數或賦給一個變量時使用

五、即時執行函數  (function(){ ...  })();  

  即時函數的參數:

  (function(who, when){

    console.log("i met" + who);

  })("joe black", new Date())

 

  即時函數的返回值:

  var result = (function(){

    return 2 + 3;

  })();

 

 

第五章  對象建立模式

1、命名空間模式

  命名空間有助於減小全局變量的數量,而且避免合名衝突或過長的名字前綴

 1 <script>
 2     // 不安全代碼,好比兩個js文件中都有這會MYAPP的建立,這樣第二個會覆蓋掉第一個對象
 3     var MYAPP = {};
 4     
 5     // 更好的代碼風格
 6     if(typeof MYAPP === "undefined"){
 7         var MYAPP = {};
 8     }
 9     
10     // 或者使用
11     var MYAPP = MYAPP || {};
12 </script>

 

  檢測代碼須要太多的重複工做,若是想定義MYAPP.modeles.module就必須三次檢查,每次都須要檢查一次對象或屬性,可使用namespace()函數

 1 <script>
 2     MYAPP.namespace("MYAPP.modules.getName");
 3 
 4     // 至關於
 5     MYAPP.modules.getName = {}
 6 
 7 
 8     // 定義一個命名空間函數
 9     var MYAPP = MYAPP || {};
10     MYAPP.namespace = function(sName, newObj){
11         var parts = sName.split("."),
12             argLen = arguments.length,
13             parent = MYAPP;
14 
15         // 剝離最前面的全局變量
16         if(parts[0] == "MYAPP"){
17             parts = parts.slice(1);
18         }
19 
20         if(argLen == 2 && (typeof newObj === "object" || typeof newObj === "function")){
21             for(var i= 0,len = parts.length; i<len; i++){
22                 if(i == len-1){
23                     parent[parts[i]] = $.extend(newObj, parent[parts[i]]);  // 須要繼承以前的對象
24                 }
25                 else{
26                     // 若是不存在就建立一個新的屬性
27                     if(typeof parent[parts[i]] === "undefined"){
28                         parent[parts[i]] = {};
29                     }
30                 }
31                 parent = parent[parts[i]];
32             }
33         }
34         else{
35             for(var i= 0,len = parts.length; i<len; i++){
36                 // 若是不存在就建立一個新的屬性
37                 if(typeof parent[parts[i]] === "undefined"){
38                     parent[parts[i]] = {};
39                 }
40                 parent = parent[parts[i]];
41             }
42         }
43 
44         return parent;
45     }
46 
47     // 一、建立一個命名空間,並初始化命名空間的對象
48     var ssq = MYAPP.namespace("MYAPP.storage.getStorage", {
49 
50         init: function(){
51             this.bindEvent();
52         },
53 
54         bindEvent: function(){
55             console.log("bind All");
56         }
57 
58     });
59 
60     // 調用
61     ssq.init();     // 結果 bind All
62 
63     // 二、建立一個命名空間,初始化時爲函數,其實使用對象也徹底能夠作到,MYAPP.namespace("MYAPP.storage", {showFun: function(){ console.log("匿名函數"); }};
64     var dlt = MYAPP.namespace("MYAPP.storage.showFun", function(){
65         console.log("匿名函數");
66     });
67 
68     // 調用
69     dlt();
70 </script>

 

2、私有屬性、方法

  js中沒有私有成員的語法,能夠經過閉包,或內部變量來實現這種功能。

 1 <script>
 2     function Gadget(){
 3         
 4         // 私有成員
 5         var name = "iPad";
 6         
 7         // 公有函數
 8         this.getName = function(){
 9             return name;
10         }
11     }
12     
13     var toy = new Gadget();
14     console.log(toy.name);      // undefined
15     console.log(toy.getName()); // iPad
16 </script>

 

3、特權方法

  就是經過公有方法來訪問私有屬性,這個方法能夠叫作特權方法,上面的例子getName()就是個特權方法.

 

4、模塊模式

 1 <script>
 2     var myObj = (function(){
 3         
 4         // 私有成員
 5         var name = "my, oh my";
 6         
 7         // 實現公有部分
 8         return {
 9             getName: function(){
10                 return name;
11             }
12         }
13     })();
14 </script>

 

一、構造函數的模塊

 1 <script>
 2     var MYAPP = MYAPP || {};
 3 
 4     // 命名空間函數
 5     MYAPP.namespace = function(sName, newObj){
 6         var parts = sName.split("."),
 7                 argLen = arguments.length,
 8                 parent = MYAPP;
 9 
10         // 剝離最前面的全局變量
11         if(parts[0] == "MYAPP"){
12             parts = parts.slice(1);
13         }
14 
15         if(argLen == 2 && (typeof newObj === "object" || typeof newObj === "function")){
16             for(var i= 0,len = parts.length; i<len; i++){
17                 if(i == len-1){
18                     parent[parts[i]] = $.extend(newObj, parent[parts[i]]);  // 須要繼承以前的對象
19                 }
20                 else{
21                     // 若是不存在就建立一個新的屬性
22                     if(typeof parent[parts[i]] === "undefined"){
23                         parent[parts[i]] = {};
24                     }
25                 }
26                 parent = parent[parts[i]];
27             }
28         }
29         else{
30             for(var i= 0,len = parts.length; i<len; i++){
31                 // 若是不存在就建立一個新的屬性
32                 if(typeof parent[parts[i]] === "undefined"){
33                     parent[parts[i]] = {};
34                 }
35                 parent = parent[parts[i]];
36             }
37         }
38 
39         return parent;
40     }
41 
42     MYAPP.namespace("MYAPP.util");      // 建立一個命名空間
43     MYAPP.util =  (function(){
44 
45         // 依賴
46         var oLib = MYAPP.lib;
47         
48         // 建立構造函數
49         function Constr(){
50             this.elements = "siguang";
51         }
52 
53         Constr.prototype.version = "2.0";
54         Constr.prototype.showMessage = function(){
55             console.log(this.version, this.elements);
56         }
57 
58         var oConstr = new Constr();
59 
60         return oConstr;
61     }());
62 
63     console.log(MYAPP);
64 
65     // 調用
66     MYAPP.util.showMessage();        //
67 </script>

 

二、將全局變量導入到模塊中

1 <script>
2     MYAPP.utilities.module = (function(app, global){
3         // 引用全局對象
4         // 能夠轉成局部變量
5         // 全局應用程序命名空間對象
6     })(MYAPP, this)
7 </script>

 

第五章  對象建立

1、包裝對象

  什麼是包裝對象

  var str = "ssssssss";   

  str.charAt(3);

  str.substring(2);

  通常方法是調用的是對象,而str是字符串,這就是用到了包裝對象,基本類型都有本身的包裝對象

 

  例如:字符串包裝類型是String     數字是Number    布爾是Boolean,爲何str能夠調用字符串的方法,看下面的例子

1 <script>
2     var str = new String("haha");   // 將字符串到String對象
3     
4     // String的對象的方法
5     String.prototype.charAt = function(n){
6         // ....
7     }
8 </script>

 

var str = "haha";    // 這句正常定義變量

str.charAt(2);      // 這裏基本類型str會找到對應包裝對象的方法,將屬性及方法賦給基本類型,而後包裝對象消失

 

 

第六章  代碼複用模式

 

1、類式繼承

  類式繼承的幾種寫法:

一、默認模式 

 1 <script>
 2 
 3     // 父構造函數
 4     function Parent(name){
 5         this.name = name || "siguang";
 6         this.age = "30";
 7         this.setGame = function(){
 8             console.log(this.age);
 9         }
10     }
11 
12     // 向該原型添加功能
13     Parent.prototype.say = function(){
14         return this.name;
15     }
16 
17     // 空構造函數
18     function Child(name, age){
19         this.age = age;
20         Parent.call(this, name);        // 改變父類的屬性,不然調用的就是父類的屬性
21     }
22 
23     // 繼承方法,封裝了一個
24     inherit(Child, Parent);
25 
26     function inherit(C, P){
27         C.prototype = new P();    // 繼承方法 28     }
29 
30     var oC = new Child("lulu", 28);   
31     console.log(oC.say());      // lulu
32     oC.setGame();               // 30
33 </script>

  類式繼承繼承父類的屬性和方法,若是改變其屬性須要將改變指針Parent.call(this, name);

  此模式的缺點:同時繼承兩個對象的屬性,將子類傳入age時this.age = age 輸出的並非預期的28而仍是父類的30,這也就是第二種模式

 

二、共享原型

  修改了inherit方法

function inherit(C, P){
  C.prototype = P.prototype;    // 缺點:在繼承鏈的某一個子對象或孫對象修改了原型,會影響到父對象和祖先對象.
}

 

三、臨時構造函數

相關文章
相關標籤/搜索