中文字幕在线观看,亚洲а∨天堂久久精品9966,亚洲成a人片在线观看你懂的,亚洲av成人片无码网站,亚洲国产精品无码久久久五月天

提升代碼的可讀性系列--基礎(chǔ)篇

2018-07-20    來源:編程學(xué)習(xí)網(wǎng)

容器云強勢上線!快速搭建集群,上萬Linux鏡像隨意使用

編程是一門藝術(shù)活,好的代碼應(yīng)該就像住的房子一樣,有整體的框架,有門,有窗戶,相互獨立又完美組合。你覺得門不夠結(jié)實,就拆下來換個實心的;你覺得窗戶不夠明亮就換個全玻璃的,總之對房子的其他部位沒有任何影響。所以說每一個程序員都應(yīng)該有一顆設(shè)計師的心。本文主要從編碼變量、處理錯誤對象等基礎(chǔ)方面進行簡單的探討,希望能對大家的工作有所幫助~~

1 編碼風(fēng)格

老生常談,我們先從最基礎(chǔ)的編碼說起吧!好的編碼規(guī)范不僅僅能夠提升代碼的可讀性與可維護性,提高團隊的工作效率,也能夠避開一些低級的錯誤,減少bug的隱患,提升程序員的自我修養(yǎng)。編碼雖小,但卻是萬丈高樓的基礎(chǔ),對于編寫清晰連貫的代碼來說,每一個字符都是非常重要的。以下部分編碼規(guī)范參考自凹凸實驗室。

1.1 縮進

通常使用四個空格進行代碼縮進,有些也用tab來縮進,這主要根據(jù)團隊的風(fēng)格跟個人喜好

1.2 空格

  • 左括號與類名之間一個空格
  • 冒號與屬性值之間一個空格
  • 操作符前后
  • 匿名函數(shù)表達式之后等

1.3 空行

這是一個容易被大家忽略的點,但它所帶來的效果是毋庸置疑的!通常一段代碼的語義和另一段代碼不相關(guān),就應(yīng)該用空行隔開,避免一大段的代碼揉在一起,比如

  • 在方法之間;
  • 方法中的局部變量和第一條語句之間;
  • 注釋之前
  • 方法內(nèi)的邏輯片段之間

1.4 命名約定

有一位大師曾說過,計算機科學(xué)只存在兩個難題:緩存命名。由此可見命名不僅是一門科學(xué),也是一門技術(shù)。
通常情況下,變量與函數(shù)一般使用駝峰大小寫命名法,其中為了區(qū)分變量與函數(shù),變量命名前綴應(yīng)當(dāng)是名詞,函數(shù)前綴應(yīng)當(dāng)是動詞,也就是說我們應(yīng)當(dāng)讓命名承載一定的含義,因此要避免使用沒有意義的命名。

1.4 注釋

通常我們在編寫完一段代碼的短時間內(nèi),會清楚這段代碼的工作原理。但是當(dāng)過一段時間再次回到代碼中,可能會花很長的時間才能讀懂。這種情況下,編寫注釋就變得尤為重要了。

2 變量

首先說一說全局變量存在哪些的問題吧!命名沖突、測試難度大深耦合等等。在創(chuàng)建變量的時候,我們應(yīng)該注意以下幾個方面

2.1 避免隱性的創(chuàng)建全局變量

什么是隱性的全局變量呢?官方的回答是:任何變量,如果未經(jīng)聲明,就為全局對象所有。啥意思呢?其實就是沒有加var聲明的,請看下面的例子

function obj() {  name = "aotu";  return name; } 

另外一種容易創(chuàng)建隱形全局變量的情況就是var聲明的鏈式賦值,如下代碼所示

function person() {  var a = b = 1; } 


以上這段代碼的執(zhí)行結(jié)果是:a是局部變量,b是全局變量,主要原因是從右至左的操作符優(yōu)先級,它實際執(zhí)行的結(jié)果等同于

var a = ( b = 0 ); 


綜上所述,隱式全局變量并不是我們平時用var聲明的變量,而是全局對象的屬性,既然是屬性,那么它可以通過delete操作符刪除,但變量不可以,且在ES5 strict以上會拋出錯誤。

2.2 在函數(shù)頂部聲明變量

在javascript中,聲明變量有一個“提升”的概念,即無論在函數(shù)哪里聲明,效果都等同于在函數(shù)頂部進行聲明。所以我們統(tǒng)一把變量在函數(shù)頂部聲明,既有利于可讀性與可維護行,也不易出錯。

2.3 使用單一var模式

var a = 1,  b = 1,  c = 1; 

這樣聲明的變量不僅可讀性好,而且可以防止變量在定義前就被使用的邏輯錯誤,且編碼更少。

2.4 單全局變量方式

雖然全局變量的容易污染命名空間,但有些功能的需要,難以避免使用,關(guān)鍵是我們應(yīng)該做到避免全局變量超出我們的掌控,最佳的方法是依賴盡可能少的全局變量。我們可以使用單全局變量的方式來開啟我們的項目,這種方式在許多的javascript類庫中都有這樣使用。如jQuery,它定義了兩個全局變量$和jQuery。

3 UI松耦合

什么是松耦合?當(dāng)修改一個組件的邏輯,而對另一個組件沒有影響,就說這叫松耦合。通常一個大型的web應(yīng)用,都是由多人共同開發(fā)維護,這時候松耦合顯得至關(guān)重要,假如你修改了某一處的代碼而影響了團隊其他人的功能,這是非常不友好的。通常我們主要注意以下幾點

  • 將javascript從css中抽離,如避免使用css表達式
  • 將csst從javascrip中抽離,如避免使用javascript直接修改css,最佳的方法是操作css的className;
  • 將javascript從HTML中抽離,如避免將函數(shù)直接嵌入到html執(zhí)行,我們應(yīng)該盡量做到將所有的js代碼都放入外置文件中,確保
    html中不會有內(nèi)聯(lián)的js代碼。
  • 將html從javascript中抽離,如避免在js中拼接html結(jié)構(gòu),我們可以用模板引擎,也可以使用Vue、React等。

4 錯誤處理

4.1 為什么要拋出錯誤?

在javascript開發(fā)中,總是會悄無聲息的出現(xiàn)一些超出我們預(yù)期的,攜帶的信息稀少的,隱晦含糊的bug,讓我們措手不及,大大增加了我們調(diào)試錯誤、定位錯誤的難度,影響開發(fā)效率。假設(shè)錯誤中包含這樣的信息:“由于某某情況,導(dǎo)致某某函數(shù)執(zhí)行錯誤”,那么是不是馬上就可以開始調(diào)試而不用花大量的時候去定位錯誤?

4.2 何時拋出錯誤?

主要是辨識代碼中哪些部分在特定的情況下最后可能導(dǎo)致錯誤,這里的錯誤通常都是我們在思考的過程中的一些可預(yù)期的錯誤。

4.3 怎樣拋出錯誤?

4.3.1 使用try-catch

將可能引發(fā)錯誤的代碼放在try塊中,處理錯誤的代碼放在catch中,如


try {  someMethod(); } catch (ex) {  catchError(ex); } 


也可以增加一個finally塊,這里需注意的是finally塊中的代碼塊不管是否有錯誤發(fā)生,最后都會被執(zhí)行。

4.3.2 throw

當(dāng)我們能清晰的捕捉到錯誤的時候,最好的做法就是拋出這個錯誤,避免在不經(jīng)意的時候又遇到它,讓大家尷尬。這里需注意的是當(dāng)遇到throw操作符時,代碼會立即停止執(zhí)行

 
throw new Error("method(): descdescdesc"); 


也可以自定義一個錯誤類型,總之就是盡可能用最短的字符描述清楚

throw {   name: "myErrorType",  message: "arguments must be a DOM element",  errorMethod: errorMethod } 


5 創(chuàng)建對象

5.1 對象字面量

所謂的對象字面量其實就是我們通常所說的鍵值對哈希表,這種方式不僅富有表現(xiàn)力,可讀性好,且字符更短,沒有作用域解析。它的語法規(guī)則如下

  • 對象包裝在大括號中
  • 逗號分隔屬性和方法
  • 用冒號分隔屬性名稱和屬性的值
    var obj = {  name: "aotu",  job: "farmer",  getName: function () {  return this.name;  } }  //調(diào)用方式 obj.getName(); 
實現(xiàn)私有屬性

以上例子的name、job屬性都是可直接訪問的。有些時候我們可能想實現(xiàn)一些私有的屬性,然后提供一個公有的接口來對外訪問。雖然javascript并沒有特殊的語法來表示私有、公共屬性和方法,但是可以通過匿名閉包來實現(xiàn),內(nèi)部的任意變量都不會暴露,來看以下代碼


var obj;   (function () {  //這樣就能實現(xiàn)私有成員  var name = "aotu",  job = "farmer";    obj = {  getName: function () {  return name;  }  } }()) 


更優(yōu)雅的寫法

var obj = (function () {  var name = "aotu",  job = "farmer";   return {  getName: function () {  return name;  }  } }()); 


這種寫法也是模塊模式的基礎(chǔ)框架,后續(xù)會有詳細介紹。

熟悉了這種模式之后它還有很多種玩法,比如可以像jQuery這樣鏈式調(diào)用:“$(‘#id’).siblings(‘ul’).find(“l(fā)i”).addClass();


var obj = {  num: 0,  add: function (arg) {  this.num += arg;  return this;  },  red: function (arg) {  this.num -= arg;  return this;  },  setTotal: function () {  console.log(this.num);  } };  //調(diào)用方式 obj.add(5).red(2).setTotal(); //3 


5.2 構(gòu)造函數(shù)

我們先來看看構(gòu)造函數(shù)的基礎(chǔ)框架

function Obj() {  //公有屬性  this.name = "aotu";  this.job = "farmer";    //公有方法  this.getName = function () {  console.log(this.name);  }  }  //調(diào)用方式 var obj = new Obj(); obj.getName(); 


在使用new方式實例化構(gòu)造函數(shù)通常會經(jīng)歷以下幾個步驟

  • 創(chuàng)建一個對象并且this變量引用了該對象,且繼承了該對象的原型
  • 屬性和方法被加入到this引用的對象中
  • 隱式的返回新對象
忘記使用NEW的情況

當(dāng)然我們有時候會忘記使用new操作符的實例化的情況,然而這并不會導(dǎo)致語法錯誤,但構(gòu)造函數(shù)的this指向了全局對象,可能會發(fā)生邏輯錯誤或者意外,來看下面執(zhí)行的結(jié)果


var obj = Obj(); obj.getName(); //Cannot read property 'getInfo' of undefined 


為了避免這種意外發(fā)生,我們也可以在構(gòu)造函數(shù)中檢查this是否為構(gòu)造函數(shù)的一個實例,強制使用new操作符,繼續(xù)看下面的例子


function Obj() {  if(!(this instanceof Obj)){  return new Obj();  }   this.name = "aotu";  this.age = 25;   this.getName = function () {  console.log(this.name);  }  } 

再看執(zhí)行的結(jié)果

var obj = Obj(); obj.getName(); //"aotu" 


靜態(tài)成員

在javascript中,并沒有特殊的語法來表示靜態(tài)成員,但我們可以為構(gòu)造函數(shù)添加屬性這種方式來實現(xiàn)這種語法,請看下面的例子

//構(gòu)造函數(shù) function Obj() {}  
//添加靜態(tài)方法 Obj.getAge = function () {  console.log(25);  }  
//注意這里的調(diào)用方式 Obj.getAge(); //25  //如果使用實例對象調(diào)用 obj.getAge();
 //Object #<Obj> has no method 'getAge' 


這里大家需要注意調(diào)用靜態(tài)方法的方式,若以實例對象調(diào)用一個靜態(tài)方法是無法正常運行的,反之同理。

私有屬性與方法

在以上例子中構(gòu)造函數(shù)的屬性與方法都屬于公有方法,我們也可以給構(gòu)造函數(shù)添加私有方法與私有屬性

function Obj() {
    this.name = "auto";
    this.age = 25;
     
    //私有屬性
    var address = "sz",
        that = this;
      
    //私有方法
    function getAddress() {
        console.log(that.address);
    }
       
    this.getName = function () {
        console.log(this.name);
    } 
}

構(gòu)造函數(shù)存在的問題

構(gòu)造函數(shù)的主要問題就是當(dāng)多次實例化這個構(gòu)造函數(shù)的時候,每個方法都會重新創(chuàng)建一遍,這樣就等于在內(nèi)存中的拷貝。解決問題的第一種思路就是將函數(shù)中的方法通過函數(shù)定義轉(zhuǎn)移到函數(shù)外面,并將指針傳遞給構(gòu)造函數(shù),來看下面的例子

function Obj() {
    this.name = "aotu";
    this.age = 25;

    //將指針賦給getName
    this.getName = getName;
}
  
function getName () {
    console.log(this.name);
}   

var obj1 = new Obj();
var obj2 = new Obj()

雖然也解決了以上的問題,但并沒有達到封裝的效果。接下來我們引入原型prototype的概念。

5.3 原型模式

每一個構(gòu)造函數(shù)都有一個原型prototype,原型對象包含一個指向構(gòu)造函數(shù)的指針,這個指針指向一個可以由特定類型的所有實例共享的屬性和方法,所以使用原型對象可以讓所有對象實例共享它的屬性和方法,來看下面的例子

function Obj() {}

Obj.prototype.name = "aotu";
Obj.prototype.age = 25;
Obj.prototype.getName = function () {
    console.log(this.name);
}

//調(diào)用方式

var obj1 = new Obj();
obj1.getName() //"aotu"

var obj2 = new Obj();
obj2.getName() //"aotu"

alert(obj1.getName == obj2.getName); //true

由此可見obj1 和 obj2 訪問的是同一個getName函數(shù)

更好的寫法

我們可以將所有的原型都寫在一個對象字面量里,這樣整個代碼看起來更加簡潔清晰,繼續(xù)往下看

function Obj() {}  Obj.prototype = {  name: "aotu",  age: 25,  getName: function () {  return this.name;  } } 


使用字面量的方式需注意的問題

在使用這種字面量的方式的時候需注意以下兩點

1.將prototype設(shè)置為等于一個對象字面量形式創(chuàng)建的對象,它本質(zhì)上已經(jīng)完全重寫了默認的prototype對象,最終結(jié)果雖然相同但是其constructor屬性不再指向該對象。

constructor是個什么鬼?在默認情況下,所有原型對象都會自動獲得一個constructor,它指向prototype屬性所在函數(shù)的指針,換句話說這個constructor就是指這個構(gòu)造函數(shù)。以上代碼執(zhí)行結(jié)果如下所示

 
var obj= new Obj(); alert(obj.cnstructor == Obj) //false; 


我們可以在重寫prototype的時候給constructor指定構(gòu)造函數(shù),接著往下看

function Obj(){}

Obj.prototype = {
    constructor: Obj,
    name: "aotu",
    age: 25,
    getName: function () {
        return this.name;
    }
}

var obj= new Obj();
alert(obj.cnstructor == Obj) //true;

2.當(dāng)我們重寫整個原型的時候如果先創(chuàng)建了實例,就會切斷構(gòu)造函數(shù)與原型之間的聯(lián)系,因為實例的指針僅僅指向原型,而不是構(gòu)造函數(shù),在實際的操作過程中,應(yīng)該盡量避免這種錯誤

function Obj() { }

var obj = new Obj();

Obj.prototype = {
    constructor: Obj,
    name: "aotu",
    age: 25,
    getName: function () {
        return this.name;
    }
}

obj.getName();  //error

組合使用二者

在我們的具體應(yīng)用中,通常比較多的是組合使用構(gòu)造函數(shù)模式與原型模式。構(gòu)造函數(shù)用于定義實例屬性,原型用于定于共享的屬性和方法,這樣能夠最大限度的節(jié)省內(nèi)存。以下是一個基本的組合使用構(gòu)造函數(shù)與原型的例子

function Obj(){
    if(!(this instanceof Obj)){
        return new Obj();
    }

    this.name = "aotu";
    this.age = 25;
}

Obj.prototype = {
    constructor: Obj,
    getName: function () {
        return this.name;
    }
}

var obj = Obj();
obj.getName();

5.4 模塊模式

模塊模式是一種非常通用的模式,也是使用頻率比較高的模式,它具有以下幾個特點

  • 模塊化
  • 可復(fù)用
  • 松耦合
  • 區(qū)分了私有方法與公共方法

我們先看看模塊模式的基礎(chǔ)框架

var testModule = function () {
    //私有成員
    var testNode = document.getElementById("test");

    //也可在此定義私有方法
    function privateMethod() {
        console.log("this is Private method!");
    }

    return {
        //對外公開的方法
        setHtml: function (txt) {
            testNode.innerHTML = txt;
        }
    }
}

//調(diào)用方式
var testModule = new testModule();
testModule.setHtml("Hello");

這種方式看起來比較清晰、簡潔,但就是每次調(diào)用的時候都需要用new來實例化,我們知道每個實例在內(nèi)存里都是一份拷貝。如何解決這個問題呢?…我們可以采用一個匿名閉包來完美的解決這個問題。

(function () {  //將所有的變量和function放在這里聲明,其作用域也只能在這個匿名閉包里面,既達到了封裝的目的,也能防止命名沖突 }()) 


接下來我們將它應(yīng)用到具體的實例中,以下就是一個基本的Module模式

var testModule =(function () {
    var my = {},
        testNode = document.getElementById("test");
     
    my.setHtml = function(txt) {
        testNode.innerHTML = txt;
    }
    
    return my;
} ())

//調(diào)用方式
testModule.setHtml("Hello");

通常在一個大型的項目中,會有多人共同開發(fā)一個功能的情況,這個時候我們可以運用這種模式將全局變量當(dāng)作參數(shù)傳遞,然后通過變量返回,從而達到多人協(xié)作的目的。

var testModule =(function (my) {
    var testNode = document.getElementById("test");
     
    my.setHtml = function(txt) {
        testNode.innerHTML = txt;
    }
    
    return my;
} (testModule || {}))

我們也可以通過這個模式將私有的對象或者屬性保護起來,然后設(shè)置一些公共接口對外訪問,繼續(xù)來看下面的代碼

var testModule =(function () {
    var testNode = document.getElementById("test"),
     
        setHtml = function(txt) {
            testNode.innerHTML = txt;
        };

        //設(shè)置公共調(diào)用方法
        return {
            setHtml: setHtml
        }
    } ())

以上幾種方式僅僅只是一些創(chuàng)建對象的基礎(chǔ),通過靈活運用這些基礎(chǔ),可以變換出傳說中各種各樣的模式,如迭代器模式、工廠模式、裝飾者模式等,對于后續(xù)學(xué)習(xí)其他的技術(shù)也是極有幫助的,

React:

var MyTitle = React.createClass({
    getDefaultProps : function () {
        return {
            title : 'Hello World'
        };
    },

    render: function() {
        return <h1> {this.props.title} </h1>;
    }
});

Vue:

new Vue({
    el: '#app',
    data: {
        message: 'Hello Vue.js!'
    },
    methods: {
        reverseMessage: function () {
            this.message = this.message.split('').reverse().join('')
        }
    }
})

以上就是本期的所有內(nèi)容,如有錯漏,懇請指正,大家共同進步!在下一期中,會繼續(xù)跟大家探討更多好玩的東西,敬請期待~~~

6 參考資料

《編寫可維護的JavaScript》[美] Nicholas C. Zakas 著
《JavaScript設(shè)計模式》[美] Addy Osmani 著
《JavaScript高級程序設(shè)計(第3版)》
博文:深入理解JavaScript系列

原文:凹凸實驗室(http://aotu.io/notes/2016/03/31/readable/)

標簽: 代碼

版權(quán)申明:本站文章部分自網(wǎng)絡(luò),如有侵權(quán),請聯(lián)系:west999com@outlook.com
特別注意:本站所有轉(zhuǎn)載文章言論不代表本站觀點!
本站所提供的圖片等素材,版權(quán)歸原作者所有,如需使用,請與原作者聯(lián)系。

上一篇:成為Java高手的25個學(xué)習(xí)要點

下一篇:Android從按下開機鍵到啟動發(fā)生了什么