成人无码视频,亚洲精品久久久久av无码,午夜精品久久久久久毛片,亚洲 中文字幕 日韩 无码

資訊專欄INFORMATION COLUMN

《JavaScript 模式》讀書(shū)筆記

teren / 2622人閱讀

摘要:因?yàn)榭赡艽嬖谝粋€(gè)同名的構(gòu)造函數(shù),當(dāng)你調(diào)用的時(shí)候,解析器需要順著作用域鏈從當(dāng)前作用域開(kāi)始查找,直到找到全局構(gòu)造函數(shù)為止。

簡(jiǎn)介

在軟件開(kāi)發(fā)過(guò)程中,模式是指一個(gè)通用問(wèn)題的解決方案。一個(gè)模式不僅僅是一個(gè)可以用來(lái)復(fù)制粘貼的代碼解決方案,更多地是提供了一個(gè)更好的實(shí)踐經(jīng)驗(yàn)、有用的抽象化表示和解決一類(lèi)問(wèn)題的模板。

對(duì)象有兩大類(lèi):

本地對(duì)象(Native):由ECMAScript標(biāo)準(zhǔn)定義的對(duì)象

宿主對(duì)象(Host):由宿主環(huán)境創(chuàng)建的對(duì)象(比如瀏覽器環(huán)境)

本地對(duì)象也可以被歸類(lèi)為內(nèi)置對(duì)象(比如Array、Date)或自定義對(duì)象(var o = {})。
宿主對(duì)象包含window和所有DOM對(duì)象。如果你想知道你是否在使用宿主對(duì)象,將你的代碼遷移到一個(gè)非瀏覽器環(huán)境中運(yùn)行一下,如果正常工作,那么你的代碼就只用到了本地對(duì)象。

“GoF”的書(shū)中提到一條通用規(guī)則,“組合優(yōu)于繼承”。

console 對(duì)象

基本技巧

易維護(hù)的代碼具有如下特性:

可讀的

風(fēng)格一致

可預(yù)測(cè)的

看起來(lái)像一個(gè)人寫(xiě)的

有文檔

盡量少用全局變量 全局變量的問(wèn)題

隱式創(chuàng)建全部變量有兩種情況:

未經(jīng)聲明的變量就為全局對(duì)象所有。

   function sum(x, y){
       result = x + y; // result 是全局變量;
   }

帶有 var 聲明的鏈?zhǔn)劫x值

   function foo(){
       var a = b = 0; // b 是全局變量
   }

由于 = 的運(yùn)算順序是從右到左。即 var a = b = 0; 等價(jià)于 var a = (b = 0)。
因此,對(duì)于鏈?zhǔn)劫x值建議做法如下:

   
   function foo(){
       var a, b;
       a = b = 0;
   }

隱式創(chuàng)建的全局變量與明確定義的全局變量的不同之處在于:是否能被 delete 操作符刪除。

使用 var 創(chuàng)建的全局變量(在函數(shù)外創(chuàng)建)不能刪除

不使用 var 創(chuàng)建的隱式全局變量(就算在函數(shù)內(nèi)創(chuàng)建)可以刪除

var a = 1;
b = 2;
(function(){
    c = 3;
})();

delete a; // false;
delete b; // true;
delete c; // true

typeof a; // number
typeof b; // undefined
typeof c; // undefined

在ES5 strict模式下,為未聲明的變量賦值會(huì)拋出錯(cuò)誤。

單一var模式

在函數(shù)頂部對(duì)所有變量通過(guò)一個(gè) var 進(jìn)行聲明。好處如下:

可以在同一個(gè)位置找到函數(shù)所需的所有變量

避免在變量聲明之前使用這個(gè)變量時(shí)產(chǎn)生的邏輯錯(cuò)誤

提醒你不要忘記聲明變量,順便減少潛在的全局變量

代碼量更少

例子:

function func(){
    var a = 1,
        b = 2,
        sum = a + b,
        myobject = {},
        i,
        j;
    console.log(sum)
    // 函數(shù)體
}
func()

使用逗號(hào)操作符可以在一條語(yǔ)句中執(zhí)行多個(gè)操作。多用于聲明多個(gè)變量,但還可以用于賦值,總會(huì)返回表達(dá)式的最后一項(xiàng)。

(1) 逗號(hào)表達(dá)式的運(yùn)算過(guò)程為:從左往右逐個(gè)計(jì)算表達(dá)式。
(2) 逗號(hào)表達(dá)式作為一個(gè)整體,它的值為最后一個(gè)表達(dá)式的值。var num = (5,4,1,0); // num 為 0。
(3) 逗號(hào)運(yùn)算符的優(yōu)先級(jí)別在所有運(yùn)算符中最低。

避免使用隱式類(lèi)型轉(zhuǎn)換

使用 ===!== 進(jìn)行比較。增強(qiáng)代碼可閱讀性,避免猜測(cè)。
另外,switch 語(yǔ)句的 case 進(jìn)行比較時(shí),使用的是 ===

避免使用 eval()

new Functin() 與 eval()的不同:

第一點(diǎn):
new Function()中的代碼將在局部函數(shù)空間運(yùn)行,因此代碼中任何采用var定義的變量不會(huì)自動(dòng)成為全局變量(即在函數(shù)內(nèi))。
eval()則會(huì)自動(dòng)成為全局變量,但可通過(guò)立即調(diào)用函數(shù)對(duì)其進(jìn)行封裝。

console.log(typeof un);// "undefined"
console.log(typeof deux); // "undefined"
console.log(typeof trois); // "undefined"

var jsstring = "var un = 1; console.log(un);";
eval(jsstring); // 打印出 "1"

jsstring = "var deux = 2; console.log(deux);";
new Function(jsstring)(); // 打印出 "2"

jsstring = "var trois = 3; console.log(trois);";
(function () {
    eval(jsstring);
}()); // 打印出 "3"

console.log(typeof un); // "number"
console.log(typeof deux); // "undefined"
console.log(typeof trois); // "undefined"

第二點(diǎn):
eval()會(huì)影響到作用域鏈,而Function則像一個(gè)沙盒,無(wú)論在哪里執(zhí)行Function,它都僅能看到全局作用域鏈。因此對(duì)局部變量的影響比較小。

(function () {
    var local = 1;
    eval("local = 3; console.log(local)"); // 打印出 3
    console.log(local); // 打印出 3
}());

(function () {
    var local = 1;
    Function("console.log(typeof local);")(); // 打印出 undefined
}());
使用parseInt()進(jìn)行數(shù)字轉(zhuǎn)換

ECMAScript3中以0為前綴的字符串會(huì)被當(dāng)作八進(jìn)制數(shù)處理,這一點(diǎn)在ES5中已經(jīng)有了改變。為了避免轉(zhuǎn)換類(lèi)型不一致而導(dǎo)致的意外結(jié)果,應(yīng)當(dāng)總是指定第二個(gè)參數(shù):

var month = "06",
year = "09";
month = parseInt(month, 10);
year = parseInt(year, 10);

字符串轉(zhuǎn)換為數(shù)字還有兩種方法:

+"08" // 結(jié)果為8,隱式調(diào)用Number()
Number("08") // 結(jié)果為8

這兩種方法要比parseInt()更快一些,因?yàn)轭櫭剂xparseInt()是一種“解析”而不是簡(jiǎn)單的“轉(zhuǎn)換”。但當(dāng)你期望將“08 hello”這類(lèi)字符串轉(zhuǎn)換為數(shù)字,則必須使用parseInt(),其他方法都會(huì)返回NaN。

命名約定

構(gòu)造函數(shù)首字母大寫(xiě)

函數(shù)用小駝峰式(getFirstName),變量用“所有單詞小寫(xiě),并用下劃線分隔各個(gè)單詞”(first_name)。這樣就能區(qū)分函數(shù)和變量了。

常量和全局變量的所有字符大寫(xiě)

私有成員函數(shù)用下劃線(_)前綴命名

當(dāng)然,還要正確編寫(xiě)注釋和更新注釋。最好能編寫(xiě) API 文檔。

字面量與構(gòu)造函數(shù)
// 一種方法,使用字面量
var car = {goes: "far"};

// 另一種方法,使用內(nèi)置構(gòu)造函數(shù)
// 注意:這是一種反模式
var car = new Object();
car.goes = "far";

字面量寫(xiě)法的一個(gè)明顯優(yōu)勢(shì)是,它的代碼更少。“創(chuàng)建對(duì)象的最佳模式是使用字面量”還有一個(gè)原因,它可以強(qiáng)調(diào)對(duì)象就是一個(gè)簡(jiǎn)單的可變的散列表,而不必一定派生自某個(gè)類(lèi)。
另外一個(gè)使用字面量而不是Object()構(gòu)造函數(shù)創(chuàng)建實(shí)例對(duì)象的原因是,對(duì)象字面量不需要“作用域解析”(scope resolution)。因?yàn)榭赡艽嬖谝粋€(gè)同名的構(gòu)造函數(shù)Object(),當(dāng)你調(diào)用Object()的時(shí)候,解析器需要順著作用域鏈從當(dāng)前作用域開(kāi)始查找,直到找到全局Object()構(gòu)造函數(shù)為止。

Object()構(gòu)造函數(shù)僅接受一個(gè)參數(shù),且依賴于傳遞的值,該Object()根據(jù)值委派另一個(gè)內(nèi)置構(gòu)造函數(shù)來(lái)創(chuàng)建對(duì)象,并返回另外一個(gè)對(duì)象實(shí)例,而這往往不是你想要的。

// 空對(duì)象
var o = new Object();
console.log(o.constructor === Object); // true

// 數(shù)值對(duì)象
var o = new Object(1);
console.log(o.constructor === Number); // true
console.log(o.toFixed(2)); // "1.00"

// 字符串對(duì)象
var o = new Object("I am a string");
console.log(o.constructor === String); // true
// 普通對(duì)象沒(méi)有substring()方法,但字符串對(duì)象有
console.log(typeof o.substring); // "function"

// 布爾值對(duì)象
var o = new Object(true);
console.log(o.constructor === Boolean); // true
強(qiáng)制使用new的模式

對(duì)于構(gòu)造函數(shù),若忘記使用 new 操作符,會(huì)導(dǎo)致構(gòu)造函數(shù)中的this指向全局對(duì)象(嚴(yán)格模式下,指向undeinfed)。

為了防止忘記 new,我們使用下面的方法:在構(gòu)造函數(shù)中首先檢查this是否是構(gòu)造函數(shù)的實(shí)例,如果不是,則通過(guò)new再次調(diào)用自己

function Waffle() {

// Waffle 可換成 arguments.callee(指向當(dāng)前執(zhí)行的函數(shù))
if (!(this instanceof Waffle)) { 
    return new Waffle();
}
this.tastes = "yummy";

}
Waffle.prototype.wantAnother = true;

// 測(cè)試
var first = new Waffle(),
    second = Waffle();

console.log(first.tastes); // "yummy"
console.log(second.tastes); // "yummy"

console.log(first.wantAnother); // true
console.log(second.wantAnother); // true

函數(shù) 重定義函數(shù)

函數(shù)可以被動(dòng)態(tài)定義,也可以被賦值給變量。如果將你定義的函數(shù)賦值給已經(jīng)存在的函數(shù)變量的話,則新函數(shù)會(huì)覆蓋舊函數(shù)。這樣做的結(jié)果是,舊函數(shù)的引用被丟棄掉,變量中所存儲(chǔ)的引用值替換成了新的函數(shù)。這樣看起來(lái)這個(gè)變量指代的函數(shù)邏輯就發(fā)生了變化,或者說(shuō)函數(shù)進(jìn)行了“重新定義”或“重寫(xiě)”。

var scareMe = function () {
    alert("Boo!");
    scareMe = function () {
        alert("Double boo!");
    };
};
// 使用重定義函數(shù)
scareMe(); // Boo!
scareMe(); // Double boo!

當(dāng)函數(shù)中包含一些初始化操作,并希望這些初始化操作只執(zhí)行一次,那么這種模式是非常合適的,因?yàn)槲覀円苊庵貜?fù)執(zhí)行不需要的代碼。在這個(gè)場(chǎng)景中,函數(shù)執(zhí)行一次后就被重寫(xiě)為另外一個(gè)函數(shù)了。

使用這種模式可以幫助提高應(yīng)用的執(zhí)行效率,因?yàn)橹匦露x的函數(shù)執(zhí)行的代碼量更少。

這種模式的另外一個(gè)名字是“函數(shù)的懶惰定義”,因?yàn)橹钡胶瘮?shù)執(zhí)行一次后才重新定義,可以說(shuō)它是“某個(gè)時(shí)間點(diǎn)之后才存在”,簡(jiǎn)稱“懶惰定義”。

這種模式有一個(gè)明顯的缺陷,就是之前給原函數(shù)添加的功能在重定義之后都丟失了。同時(shí),如果這個(gè)函數(shù)被重定義為不同的名字,被賦值給不同的變量,或者是作為對(duì)象的方法使用,那么重定義的部分并不會(huì)生效,原來(lái)的函數(shù)依然會(huì)被執(zhí)行。

條件初始化

條件初始化(也叫條件加載)是一種優(yōu)化模式。當(dāng)你知道某種條件在整個(gè)程序生命周期中都不會(huì)變化的時(shí)候,那么對(duì)這個(gè)條件的探測(cè)只做一次就很有意義。瀏覽器探測(cè)(或者特征檢測(cè))是一個(gè)典型的例子。

// 接口
var utils = {
    addListener: null,
    removeListener: null
};

// 實(shí)現(xiàn)
if (typeof window.addEventListener === "function") {
    utils.addListener = function (el, type, fn) {
        el.addEventListener(type, fn, false);
    };
    utils.removeListener = function (el, type, fn) {
        el.removeEventListener(type, fn, false);
    };
} else if (typeof document.attachEvent === "function") { // IE
    utils.addListener = function (el, type, fn) {
        el.attachEvent("on" + type, fn);
    };
    utils.removeListener = function (el, type, fn) {
        el.detachEvent("on" + type, fn);
    };
} else { // older browsers
    utils.addListener = function (el, type, fn) {
        el["on" + type] = fn;
    };
    utils.removeListener = function (el, type, fn) {
        el["on" + type] = null;
    };
}

當(dāng)然,重定義函數(shù)也能實(shí)現(xiàn)這種效果。

函數(shù)屬性——記憶模式(Memoization)

任何時(shí)候都可以給函數(shù)添加自定義屬性。添加自定義屬性的一個(gè)有用場(chǎng)景是緩存函數(shù)的執(zhí)行結(jié)果(返回值),這樣下次同樣的函數(shù)被調(diào)用的時(shí)候就不需要再做一次那些可能很復(fù)雜的計(jì)算。緩存一個(gè)函數(shù)的運(yùn)行結(jié)果也就是為大家所熟知的記憶模式。

var myFunc = function (param) {
    if (!myFunc.cache[param]) {
        var result = {};
        // ……復(fù)雜的計(jì)算……
        myFunc.cache[param] = result;
    }
    return myFunc.cache[param];
};

// 緩存
myFunc.cache = {};

上面的代碼假設(shè)函數(shù)只接受一個(gè)參數(shù)param,并且這個(gè)參數(shù)是原始類(lèi)型(比如字符串)。如果你有更多更復(fù)雜的參數(shù),則通常需要對(duì)它們進(jìn)行序列化。比如,你需要將arguments對(duì)象序列化為JSON字符串,然后使用JSON字符串作為cache對(duì)象的key:

var myFunc = function () {

    var cachekey = JSON.stringify(Array.prototype.slice.call(arguments)),
        result;

    if (!myFunc.cache[cachekey]) {
        result = {};
        // ……復(fù)雜的計(jì)算……
        myFunc.cache[cachekey] = result;
    }
    return myFunc.cache[cachekey];
};

// 緩存
myFunc.cache = {};

前面代碼中的函數(shù)名還可以使用arguments.callee來(lái)替代,這樣就不用將函數(shù)名硬編碼。不過(guò)盡管現(xiàn)階段這個(gè)辦法可行,但是仍然需要注意,arguments.callee在ECMAScript5的嚴(yán)格模式中是不被允許的。

柯里化

是把接受多個(gè)參數(shù)的函數(shù)變換成接受一個(gè)單一參數(shù)(最初函數(shù)的第一個(gè)參數(shù))的函數(shù),并且返回接受余下的參數(shù)而且返回結(jié)果的新函數(shù)的技術(shù)。
下面是通用的柯里化函數(shù):

function cury(fn){
    var slice = Array.prototype.slice;
    var stored_args = slice.call(arguments, 1);

    return function(){
        var new_args = slice.call(arguments),
            args = stored_args.concat(new_args);
        return fn.apply(null, args);
    }
}

// 測(cè)試
function sum(){
    var result = 0;
    for(var i = 0, len = arguments.length; i < len; i++){
        result += arguments[i];
    }
    return result;
}

var newSum = cury(sum, 1,2,3,4,5,6);
console.log(newSum(2,3,5,4)); // 35
什么時(shí)候使用柯里化

當(dāng)你發(fā)現(xiàn)自己在調(diào)用同樣的函數(shù)并且傳入的參數(shù)大部分都相同的時(shí)候,就是考慮柯里化的理想場(chǎng)景了。你可以通過(guò)傳入一部分的參數(shù)動(dòng)態(tài)地創(chuàng)建一個(gè)新的函數(shù)。這個(gè)新函數(shù)會(huì)存儲(chǔ)那些重復(fù)的參數(shù)(所以你不需要再每次都傳入),然后再在調(diào)用原始函數(shù)的時(shí)候?qū)⒄麄€(gè)參數(shù)列表補(bǔ)全。

apply()接受兩個(gè)參數(shù):第一個(gè)是在函數(shù)內(nèi)部綁定到this上的對(duì)象,第二個(gè)是一個(gè)參數(shù)數(shù)組,參數(shù)數(shù)組會(huì)在函數(shù)內(nèi)部變成一個(gè)類(lèi)似數(shù)組的arguments對(duì)象。如果第一個(gè)參數(shù)為 null,那么this將指向全局對(duì)象,這正是當(dāng)你調(diào)用一個(gè)函數(shù)(且這個(gè)函數(shù)不是某個(gè)對(duì)象的方法)時(shí)發(fā)生的事情。

小結(jié)

在介紹完背景和函數(shù)的語(yǔ)法后,介紹了一些有用的模式,按分類(lèi)列出:

API模式,它們幫助我們?yōu)楹瘮?shù)給出更干凈的接口,包括:

回調(diào)模式

  傳入一個(gè)函數(shù)作為參數(shù)

配置對(duì)象

   幫助保持函數(shù)的參數(shù)數(shù)量可控

返回函數(shù)

   函數(shù)的返回值是另一個(gè)函數(shù)

柯里化

   新函數(shù)在已有函數(shù)的基礎(chǔ)上再加上一部分參數(shù)構(gòu)成

初始化模式,這些模式幫助我們用一種干凈的、結(jié)構(gòu)化的方法來(lái)做一些初始化工作(在web頁(yè)面和應(yīng)用中非常常見(jiàn)),通過(guò)一些臨時(shí)變量來(lái)保證不污染全局命名空間。這些模式包括:

即時(shí)函數(shù)

   當(dāng)它們被定義后立即執(zhí)行

對(duì)象即時(shí)初始化

   初始化工作被放入一個(gè)匿名對(duì)象,這個(gè)對(duì)象提供一個(gè)可以立即被執(zhí)行的方法

條件初始化

   使分支代碼只在初始化的時(shí)候執(zhí)行一次,而不是在整個(gè)程序生命周期中反復(fù)執(zhí)行

性能模式,這些模式幫助提高代碼的執(zhí)行速度,包括:

記憶模式

   利用函數(shù)的屬性,使已經(jīng)計(jì)算過(guò)的值不用再次計(jì)算

自定義函數(shù)

   重寫(xiě)自身的函數(shù)體,使第二次及后續(xù)的調(diào)用做更少的工作
   

對(duì)象創(chuàng)建模式

JavaScript語(yǔ)言本身很簡(jiǎn)單、直觀,也沒(méi)有其他語(yǔ)言的一些語(yǔ)言特性:命名空間、模塊、包、私有屬性以及靜態(tài)成員。本章將介紹一些常用的模式,以此實(shí)現(xiàn)這些語(yǔ)言特性。

我們將對(duì)命名空間、依賴聲明、模塊模式以及沙箱模式進(jìn)行初探——它們可以幫助我們更好地組織應(yīng)用程序的代碼,有效地減少全局污染的問(wèn)題。除此之外,還會(huì)討論私有和特權(quán)成員、靜態(tài)和私有靜態(tài)成員、對(duì)象常量、鏈?zhǔn)秸{(diào)用以及一種像類(lèi)式語(yǔ)言一樣定義構(gòu)造函數(shù)的方法等話題。

命名空間模式

使用命名空間可以減少全局變量的數(shù)量,與此同時(shí),還能有效地避免命名沖突和前綴的濫用。

本章后續(xù)要介紹的沙箱模式則可以避免這些缺點(diǎn)。

// 重構(gòu)前:5個(gè)全局變量
// 注意:反模式
// 構(gòu)造函數(shù)
function Parent() {} 
function Child() {}
// 一個(gè)變量
var some_var = 1;

// 一些對(duì)象
var module1 = {}; 
module1.data = {a: 1, b: 2}; 
var module2 = {};

可以通過(guò)創(chuàng)建一個(gè)全局對(duì)象(通常代表應(yīng)用名)比如MYAPP來(lái)重構(gòu)上述這類(lèi)代碼,然后將上述例子中的函數(shù)和變量都變?yōu)樵撊謱?duì)象的屬性:

// 重構(gòu)后:一個(gè)全局變量
// 全局對(duì)象
var MYAPP = {};

// 構(gòu)造函數(shù)
MYAPP.Parent = function () {}; 
MYAPP.Child = function () {};

// 一個(gè)變量
MYAPP.some_var = 1;

// 一個(gè)對(duì)象容器
MYAPP.modules = {};

// 嵌套的對(duì)象
MYAPP.modules.module1 = {}; 
MYAPP.modules.module1.data = {a: 1, b: 2}; 
MYAPP.modules.module2 = {};

這種模式在大多數(shù)情況下非常適用,但也有它的缺點(diǎn):

代碼量稍有增加;在每個(gè)函數(shù)和變量前加上這個(gè)命名空間對(duì)象的前綴,會(huì)增加代碼量,增大文件大小

該全局實(shí)例可以被隨時(shí)修改

命名的深度嵌套會(huì)減慢屬性值的查詢

本章后續(xù)要介紹的沙箱模式則可以避免這些缺點(diǎn)。

通用命名空間函數(shù)

隨著程序復(fù)雜度的提高,代碼會(huì)被分拆在不同的文件中以按照頁(yè)面需要來(lái)加載,這樣一來(lái),就不能保證你的代碼一定是第一個(gè)定義命名空間或者某個(gè)屬性的,甚至?xí)l(fā)生屬性覆蓋的問(wèn)題。所以,在創(chuàng)建命名空間或者添加屬性的時(shí)候,最好先檢查下是否存在,如下所示:

// 不安全的做法
var MYAPP = {};
// 更好的做法
if (typeof MYAPP === "undefined") {
    var MYAPP = {}; 
}
// 簡(jiǎn)寫(xiě)
var MYAPP = MYAPP || {};

如上所示,如果每次做類(lèi)似操作都要這樣檢查一下就會(huì)有很多重復(fù)的代碼。例如,要聲明MYAPP.modules.module2,就要重復(fù)三次這樣的檢查。所以,我們需要一個(gè)可復(fù)用的namespace()函數(shù)來(lái)專門(mén)處理這些檢查工作,然后用它來(lái)創(chuàng)建命名空間,如下所示:

// 使用命名空間函數(shù)
MYAPP.namespace("MYAPP.modules.module2");

// 等價(jià)于:
// var MYAPP = {
//  modules: {
//      module2: {}
//  }
// };

下面是上述namespace函數(shù)的實(shí)現(xiàn)示例。這種實(shí)現(xiàn)是非破壞性的,意味著如果要?jiǎng)?chuàng)建的命名空間已經(jīng)存在,則不會(huì)再重復(fù)創(chuàng)建:

var MYAPP = MYAPP || {};

MYAPP.namespace = function(ns_string){
    var parts = ns_string.split("."),
        parent = MYAPP;

    if(parts[0] === "MYAPP"){
        parts.shift();
    }

    for(var i = 0, len = parts.length; i < len; i++){
        if(parent[parts[i]] === undefined){
            parent[parts[i]] = {}
        }
        parent = parent[parts[i]]
    }
    return parent;
}
var module2 = MYAPP.namespace("MYAPP.modules.module2");
console.log(module2 === MYAPP.modules.module2); // true

var modules = MYAPP.namespace("modules");
console.log(modules === MYAPP.modules); // true
依賴聲明

JavaScript庫(kù)往往是模塊化而且有用到命名空間的,這使得你可以只使用你需要的模塊。比如在YUI2中,全局變量YAHOO就是一個(gè)命名空間,各個(gè)模塊都是全局變量的屬性,比如YAHOO.util.Dom(DOM模塊)、YAHOO.util.Event(事件模塊)。

將你的代碼依賴在函數(shù)或者模塊的頂部進(jìn)行聲明是一個(gè)好主意。聲明就是創(chuàng)建一個(gè)本地變量,指向你需要用到的模塊:

var myFunction = function () {
    // 依賴
    var event = YAHOO.util.Event,
        dom = YAHOO.util.Dom;

    // 在函數(shù)后面的代碼中使用event和dom……
};

這是一個(gè)相當(dāng)簡(jiǎn)單的模式,但是有很多的好處:

明確的依賴聲明是告知使用你代碼的開(kāi)發(fā)者,需要保證指定的腳本文件被包含在頁(yè)面中。

將聲明放在函數(shù)頂部使得依賴很容易被查找和解析。

本地變量(如dom)永遠(yuǎn)會(huì)比全局變量(如YAHOO)要快,甚至比全局變量的屬性(如YAHOO.util.Dom)還要快,這樣會(huì)有更好的性能。使用了依賴聲明模式之后,全局變量的解析在函數(shù)中只會(huì)進(jìn)行一次,在此之后將會(huì)使用更快的本地變量(備注:本地變量直接指向最后一級(jí)對(duì)象,event)。

一些高級(jí)的代碼壓縮工具比如YUI Compressor和Google Closure compiler會(huì)重命名本地變量(比如event可能會(huì)被壓縮成一個(gè)字母,如A),這會(huì)使代碼更精簡(jiǎn),但這個(gè)操作不會(huì)對(duì)全局變量進(jìn)行,因?yàn)檫@樣做不安全。

私有屬性和方法 私有成員

通過(guò)閉包實(shí)現(xiàn):

function Gadget() {
    // 私有成員
    var name = "iPod";
    // 公有函數(shù)
    this.getName = function () {
        return name;
    };
}
var toy = new Gadget();

// name是是私有的
console.log(toy.name); // undefined
// 公有方法可以訪問(wèn)到name
console.log(toy.getName()); // "iPod"
特權(quán)方法

特權(quán)方法的概念不涉及到任何語(yǔ)法,它只是一個(gè)給可以訪問(wèn)到私有成員的公有方法的名字(就好像它們有更多權(quán)限一樣)。
在前面的例子中,getName()就是一個(gè)特權(quán)方法,因?yàn)樗性L問(wèn)name屬性的特殊權(quán)限。

私有成員失效

當(dāng)你直接通過(guò)特權(quán)方法返回一個(gè)私有變量,而這個(gè)私有變量恰好是一個(gè)對(duì)象或者數(shù)組時(shí),外部的代碼可以修改這個(gè)私有變量,因?yàn)樗前匆脗鬟f的。

function Gadget() {
    // 私有成員
    var specs = {
        screen_width: 320,
        screen_height: 480,
        color: "white"
    };

    // 公有函數(shù)
    this.getSpecs = function () {
        return specs; // 直接返回對(duì)象(數(shù)組也是對(duì)象),會(huì)導(dǎo)致私有對(duì)象能在外面被修改
    };
}

解決方法:返回精簡(jiǎn)后新對(duì)象(返回需要用到的部分屬性),或?qū)λ接袑?duì)象進(jìn)行復(fù)制(返回副本)。

眾所周知的“最低授權(quán)原則”(Principle of Least Authority,簡(jiǎn)稱POLA),指永遠(yuǎn)不要給出比真實(shí)需要更多的東西。

原型和私有成員

使用構(gòu)造函數(shù)創(chuàng)建私有成員的一個(gè)弊端是,每一次調(diào)用構(gòu)造函數(shù)創(chuàng)建對(duì)象時(shí)這些私有成員都會(huì)被創(chuàng)建一次。

function Gadget() {
    // 私有成員
    var name = "iPod";
    // 公有函數(shù)
    this.getName = function () {
        return name;
    };
}

Gadget.prototype = (function () {
    // 私有成員
    var browser = "Mobile Webkit";
    // 公有函數(shù)
    return {
        getBrowser: function () {
            return browser;
        }
    };
}());

var toy = new Gadget();
console.log(toy.getName()); // 自有的特權(quán)方法 
console.log(toy.getBrowser()); // 來(lái)自原型的特權(quán)方法
將私有函數(shù)暴露為公有方法

“暴露模式”是指將已經(jīng)有的私有函數(shù)暴露為公有方法。

我們來(lái)看一個(gè)例子,它建立在對(duì)象字面量的私有成員模式之上:

var myarray;

(function () {

    var astr = "[object Array]",
        toString = Object.prototype.toString;

    function isArray(a) {
        return toString.call(a) === astr;
    }

    function indexOf(haystack, needle) {
        var i = 0,
            max = haystack.length;
        for (; i < max; i += 1) {
            if (haystack[i] === needle) {
                return i;
            }
        }
        return ?1;
    }

    myarray = {
        isArray: isArray,
        indexOf: indexOf,
        inArray: indexOf
    };

}());
模塊模式

模塊模式使用得很廣泛,因?yàn)樗梢詾榇a提供特定的結(jié)構(gòu),幫助組織日益增長(zhǎng)的代碼。不像其它語(yǔ)言,JavaScript沒(méi)有專門(mén)的“包”(package)的語(yǔ)法,但模塊模式提供了用于創(chuàng)建獨(dú)立解耦的代碼片段的工具,這些代碼可以被當(dāng)成黑盒,當(dāng)你正在寫(xiě)的軟件需求發(fā)生變化時(shí),這些代碼可以被添加、替換、移除。

模塊模式是我們目前討論過(guò)的好幾種模式的組合,即:

命名空間模式

即時(shí)函數(shù)模式

私有和特權(quán)成員模式

依賴聲明模式

第一步是初始化一個(gè)命名空間。我們使用本章前面部分的namespace()函數(shù),創(chuàng)建一個(gè)提供數(shù)組相關(guān)方法的套件模塊:

MYAPP.namespace("MYAPP.utilities.array");

下一步是定義模塊。使用一個(gè)即時(shí)函數(shù)來(lái)提供私有作用域供私有成員使用。即時(shí)函數(shù)返回一個(gè)對(duì)象,也就是帶有公有接口的真正的模塊,可以供其它代碼使用:

MYAPP.utilities.array = (function () {
    return {
        // todo...
    };
}());

下一步,給公有接口添加一些方法:

MYAPP.utilities.array = (function () {
    return {
        inArray: function (needle, haystack) {
            // ...
        },
        isArray: function (a) {
            // ...
        }
    };
}());

如果需要的話,你可以在即時(shí)函數(shù)提供的閉包中聲明私有屬性和私有方法。同樣,依賴聲明放置在函數(shù)頂部,在變量聲明的下方可以選擇性地放置輔助初始化模塊的一次性代碼。函數(shù)最終返回的是一個(gè)包含模塊公共API的對(duì)象:

MYAPP.namespace("MYAPP.utilities.array");
MYAPP.utilities.array = (function () {

        // 依賴聲明
    var uobj = MYAPP.utilities.object,
        ulang = MYAPP.utilities.lang,

        // 私有屬性
        array_string = "[object Array]",
        ops = Object.prototype.toString;

        // 私有方法
        // ……

        // 結(jié)束變量聲明

    // 選擇性放置一次性初始化的代碼
    // ……

    // 公有API
    return {

        inArray: function (needle, haystack) {
            for (var i = 0, max = haystack.length; i < max; i += 1) {
                if (haystack[i] === needle) {
                    return true;
                }
            }
        },

        isArray: function (a) {
            return ops.call(a) === array_string;
        }
        // ……更多的方法和屬性
    };
}());

模塊模式被廣泛使用,是一種值得強(qiáng)烈推薦的模式,它可以幫助我們組織代碼,尤其是代碼量在不斷增長(zhǎng)的時(shí)候。

暴露模塊模式

我們?cè)诒菊轮杏懻撍接谐蓡T模式時(shí)已經(jīng)討論過(guò)暴露模式。模塊模式也可以用類(lèi)似的方法來(lái)組織,將所有的方法保持私有,只在最后暴露需要使用的方法來(lái)初始化API。

上面的例子可以變成這樣:

MYAPP.utilities.array = (function () {

        // 私有屬性
    var array_string = "[object Array]",
        ops = Object.prototype.toString,

        // 私有方法
        inArray = function (haystack, needle) {
            for (var i = 0, max = haystack.length; i < max; i += 1) {
                if (haystack[i] === needle) {
                    return i;
                }
            }
            return ?1;
        },
        isArray = function (a) {
            return ops.call(a) === array_string;
        };
        // 結(jié)束變量定義

    // 暴露公有API
    return {
        isArray: isArray,
        indexOf: inArray
    };
}());
在模塊中引入全局上下文

作為這種模式的一個(gè)常見(jiàn)的變種,你可以給包裹模塊的即時(shí)函數(shù)傳遞參數(shù)。你可以傳遞任何值,但通常情況下會(huì)傳遞全局變量甚至是全局對(duì)象本身。引入全局上下文可以加快函數(shù)內(nèi)部的全局變量的解析,因?yàn)橐胫髸?huì)作為函數(shù)的本地變量:

MYAPP.utilities.module = (function (app, global) {

    // 全局對(duì)象和全局命名空間都作為本地變量存在

}(MYAPP, this));
代碼復(fù)用模式

在做代碼復(fù)用的工作的時(shí)候,謹(jǐn)記Gang of Four在書(shū)中給出的關(guān)于對(duì)象創(chuàng)建的建議:“優(yōu)先使用對(duì)象創(chuàng)建而不是類(lèi)繼承”。

類(lèi)式(傳統(tǒng))繼承(classical inheritance) vs 現(xiàn)代繼承模式
類(lèi)式繼承:按照類(lèi)的方式考慮JavaScript,并產(chǎn)生了一些假定在類(lèi)的基礎(chǔ)上的開(kāi)發(fā)思路和繼承模式。
現(xiàn)代繼承模式:其他任何不需要以類(lèi)的方式考慮的模式。

當(dāng)需要給項(xiàng)目選擇一個(gè)繼承模式時(shí),有不少的備選方案。你應(yīng)該盡量選擇那些現(xiàn)代繼承模式,除非團(tuán)隊(duì)已經(jīng)覺(jué)得“無(wú)類(lèi)不歡”。

跳過(guò)類(lèi)繼承..

通過(guò)復(fù)制屬性實(shí)現(xiàn)繼承

在這種模式中,一個(gè)對(duì)象通過(guò)簡(jiǎn)單地復(fù)制另一個(gè)對(duì)象來(lái)獲得功能。下面是一個(gè)簡(jiǎn)單的實(shí)現(xiàn)這種功能的extend()函數(shù):

function extend(parent, child) {
    var i;
    child = child || {};
    for (i in parent) {
        if (parent.hasOwnProperty(i)) {
            child[i] = parent[i];
        }
    }
    return child;
}

上面給出的實(shí)現(xiàn)叫作對(duì)象的“淺拷貝”(shallow copy),與之相對(duì),“深拷貝”是指檢查準(zhǔn)備復(fù)制的屬性本身是否是對(duì)象或者數(shù)組,如果是,也遍歷它們的屬性并復(fù)制。如果使用淺拷貝的話(因?yàn)樵贘avaScript中對(duì)象是按引用傳遞),如果你改變子對(duì)象的一個(gè)屬性,而這個(gè)屬性恰好是一個(gè)對(duì)象,那么你也會(huì)改變父對(duì)象。實(shí)際上這對(duì)方法來(lái)說(shuō)可能很好(因?yàn)楹瘮?shù)也是對(duì)象,也是按引用傳遞),但是當(dāng)遇到其它的對(duì)象和數(shù)組的時(shí)候可能會(huì)有些意外情況。

現(xiàn)在讓我們來(lái)修改一下extend()函數(shù)以便實(shí)現(xiàn)深拷貝。你需要做的事情只是檢查一個(gè)屬性的類(lèi)型是否是對(duì)象,如果是,則遞歸遍歷它的屬性。另外一個(gè)需要做的檢查是這個(gè)對(duì)象是真的對(duì)象還是數(shù)組,可以使用第三章討論過(guò)的數(shù)組檢查方式。最終深拷貝版的extend()是這樣的:

function extendDeep(parent, child) {
    var i,
        toStr = Object.prototype.toString,
        astr = "[object Array]";

    child = child || {};

    for (i in parent) {
        if (parent.hasOwnProperty(i)) {
            if (typeof parent[i] === "object") {
                child[i] = (toStr.call(parent[i]) === astr) ? [] : {};
                extendDeep(parent[i], child[i]);
            } else {
                child[i] = parent[i];
            }
        }
    }
    return child;
}

這種模式并不高深,因?yàn)楦緵](méi)有原型牽涉進(jìn)來(lái),而只跟對(duì)象和它們的屬性有關(guān)。

混元(Mix-ins)

“混元”模式,從任意多數(shù)量的對(duì)象中復(fù)制屬性,然后將它們混在一起組成一個(gè)新對(duì)象。

function mix() {
    var arg, prop, child = {};
    for (arg = 0; arg < arguments.length; arg += 1) {
        for (prop in arguments[arg]) {
            if (arguments[arg].hasOwnProperty(prop)) {
                child[prop] = arguments[arg][prop];
            }
        }
    }
    return child;
}

這里我們只是簡(jiǎn)單地遍歷、復(fù)制自有屬性,并沒(méi)有與父對(duì)象有任何鏈接。

借用方法

apply、call、bind(ES5)。
apply是接受數(shù)組,而call是接受一個(gè)一個(gè)的參數(shù)。

在低于ES5的環(huán)境中時(shí)如何實(shí)現(xiàn)Function.prototype.bind():

if (typeof Function.prototype.bind === "undefined") {
    Function.prototype.bind = function (thisArg) {
        var fn = this,
        slice = Array.prototype.slice,
        args = slice.call(arguments, 1);

        return function () {
            return fn.apply(thisArg, args.concat(slice.call(arguments)));
        };
    };
}
小結(jié)

在JavaScript中,繼承有很多種方案可以選擇,在本章中你看到了很多類(lèi)式繼承和現(xiàn)代繼承的方案。學(xué)習(xí)和理解不同的模式是有好處的,因?yàn)檫@可以增強(qiáng)你對(duì)這門(mén)語(yǔ)言的掌握能力。

但是,也許在開(kāi)發(fā)過(guò)程中繼承并不是你經(jīng)常面對(duì)的一個(gè)問(wèn)題。一部分是因?yàn)檫@個(gè)問(wèn)題已經(jīng)被使用某種方式或者某個(gè)你使用的類(lèi)庫(kù)解決了,另一部分是因?yàn)槟悴恍枰贘avaScript中建立很長(zhǎng)很復(fù)雜的繼承鏈。在靜態(tài)強(qiáng)類(lèi)型語(yǔ)言中,繼承可能是唯一可以復(fù)用代碼的方法,但在JavaScript中有更多更簡(jiǎn)單更優(yōu)化的方法,包括借用方法、綁定、復(fù)制屬性、混元等。

記住,代碼復(fù)用才是目標(biāo),繼承只是達(dá)成這個(gè)目標(biāo)的一種手段。

DOM與瀏覽器模式 延遲加載

所謂的延遲加載是指在頁(yè)面的load事件之后再加載外部文件。通常,將一個(gè)大的合并后的文件分成兩部分是有好處的:

一部分是頁(yè)面初始化和綁定UI元素的事件處理函數(shù)必須的

第二部分是只在用戶交互或者其它條件下才會(huì)用到的

分成兩部分的目標(biāo)就是逐步加載頁(yè)面,讓用戶盡快可以進(jìn)行一些操作。剩余的部分在用戶可以看到頁(yè)面的時(shí)候再在后臺(tái)加載。

加載第二部分JavaScript的方法也是使用動(dòng)態(tài)script元素,將它加在head或者body中:

    ……頁(yè)面主體部分……

    
    
    

### 按需加載
創(chuàng)建一個(gè)require()函數(shù)或者方法,它接受一個(gè)需要被加載的腳本文件的文件名,還有一個(gè)在腳本被加載完畢后執(zhí)行的回調(diào)函數(shù)。

require("extra.js", function () {
    functionDefinedInExtraJS();
});
function require(file, callback) {

    var script = document.getElementsByTagName("script")[0], newjs = document.createElement("script");

    // IE
    newjs.onreadystatechange = function () {
        if (newjs.readyState === "loaded" || newjs.readyState === "complete") {
            newjs.onreadystatechange = null;
            callback();
        }
    };

    // 其它瀏覽器
    newjs.onload = function () {
        callback();
    };

    newjs.src = file;
    script.parentNode.insertBefore(newjs, script);
}

這個(gè)實(shí)現(xiàn)的幾點(diǎn)說(shuō)明:

在IE中需要監(jiān)聽(tīng)readystatechange事件,然后判斷狀態(tài)是否為"loaded"或者"complete"。其它的瀏覽器會(huì)忽略這里。

在Firefox,Safari和Opera中,通過(guò)onload屬性監(jiān)聽(tīng)load事件。

這個(gè)方法在Safari 2中無(wú)效。如果必須要處理這個(gè)瀏覽器,需要設(shè)一個(gè)定時(shí)器,周期性地去檢查某個(gè)指定的變量(在腳本中定義的)是否有定義。當(dāng)它變成已定義時(shí),就意味著新的腳本已經(jīng)被加載并執(zhí)行。

預(yù)加載JavaScript

在延遲加載模式和按需加載模式中,我們加載了當(dāng)前頁(yè)面需要用到的腳本,除此之外,我們也可以加載當(dāng)前頁(yè)面不需要但可能在接下來(lái)的頁(yè)面中需要的腳本。這樣的話,當(dāng)用戶進(jìn)入第二個(gè)頁(yè)面時(shí),腳本已經(jīng)被預(yù)加載過(guò),整體體驗(yàn)會(huì)變得更快。

預(yù)加載可以簡(jiǎn)單地通過(guò)動(dòng)態(tài)腳本模式實(shí)現(xiàn),但這也意味著腳本會(huì)被解析和執(zhí)行。解析僅僅會(huì)在頁(yè)面加載時(shí)間中增加預(yù)加載消耗的時(shí)間,但執(zhí)行卻可能導(dǎo)致JavaScript錯(cuò)誤,因?yàn)轭A(yù)加載的腳本會(huì)假設(shè)自己運(yùn)行在第二個(gè)頁(yè)面上,比如找一個(gè)特定的DOM節(jié)點(diǎn)就可能出錯(cuò)。

僅加載腳本而不解析和執(zhí)行是可能的,這也同樣適用于CSS和圖像。

在IE中,你可以使用熟悉的圖片信標(biāo)模式來(lái)發(fā)起請(qǐng)求:

new Image().src = "preloadme.js";

在其它的瀏覽器中,你可以使用替代script元素,然后將它的data屬性指向腳本的URL:

var obj = document.createElement("object");
obj.data = "preloadme.js";
document.body.appendChild(obj);

為了阻止object可見(jiàn),你應(yīng)該設(shè)置它的width和height屬性為0。

你可以創(chuàng)建一個(gè)通用的preload()函數(shù)或者方法,使用條件初始化模式(第四章)來(lái)處理瀏覽器差異:

var preload;
if (/*@cc_on!@*/false) { // IE支持條件注釋
    preload = function (file) {
        new Image().src = file;
    };
} else {
    preload = function (file) {
        var obj = document.createElement("object"),
            body = document.body;

        obj.width = 0;
        obj.height = 0;
        obj.data = file;
        body.appendChild(obj);
    };
}

使用這個(gè)新函數(shù):

preload("my_web_worker.js");

這種模式的壞處在于存在用戶代理(瀏覽器)嗅探,但這里無(wú)法避免,因?yàn)樘匦詸z測(cè)沒(méi)有辦法告知足夠的瀏覽器行為信息。比如在這個(gè)模式中,理論上你可以測(cè)試typeof Image是否是"function"來(lái)代替嗅探,但這種方法其實(shí)沒(méi)有作用,因?yàn)樗械臑g覽器都支持new Image();只是有一些瀏覽器會(huì)為圖片多帶帶做緩存,意味著作為圖片緩存下來(lái)的組件(文件)在第二個(gè)頁(yè)面中不會(huì)被作為腳本取出來(lái),而是會(huì)重新下載。

瀏覽器嗅探中使用條件注釋很有意思,這明顯比在navigator.userAgent中找字符串要安全得多,因?yàn)橛脩艨梢院苋菀椎匦薷倪@些字符串。 比如: var isIE = /*@cc_on!@*/false; 會(huì)在其它的瀏覽器中將isIE設(shè)為false(因?yàn)楹雎粤俗⑨專贗E中會(huì)是true,因?yàn)樵跅l件注釋中有取反運(yùn)算符!。在IE中就像是這樣: var isIE = !false; // true

預(yù)加載模式可以被用于各種組件(文件),而不僅僅是腳本。比如在登錄頁(yè)就很有用,當(dāng)用戶開(kāi)始輸入用戶名時(shí),你可以使用打字的時(shí)間開(kāi)始預(yù)加載(非敏感的東西),因?yàn)橛脩艉芸赡軙?huì)到第二個(gè)也就是登錄后的頁(yè)面。

完~

Github: https://github.com/JChehe/blog
博客:http://jchehe.github.io/

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://m.hztianpu.com/yun/79316.html

相關(guān)文章

  • JavaScript模式讀書(shū)筆記一:基本技巧

    摘要:模式的讀書(shū)筆記,個(gè)人向更新進(jìn)度隨我的閱讀進(jìn)度基本技巧盡量少用全局變量防止變量污染注意變量提升問(wèn)題盡量使用單一模式,只使用一個(gè)在函數(shù)頂部進(jìn)行變量聲明函數(shù)體循環(huán)優(yōu)化循環(huán)條件優(yōu)化對(duì)進(jìn)行操作上面那種循環(huán),將作為循環(huán)條件,每次循環(huán)時(shí)都要訪問(wèn)數(shù)據(jù)的長(zhǎng)度 《JavaScript模式》的讀書(shū)筆記,個(gè)人向!更新進(jìn)度隨我的閱讀進(jìn)度 基本技巧 盡量少用全局變量 防止變量污染 注意JS變量提升問(wèn)題 盡量使用...

    wapeyang 評(píng)論0 收藏0
  • JavaScript 語(yǔ)言精粹》讀書(shū)筆記 - 函數(shù)

    摘要:語(yǔ)言精粹讀書(shū)筆記第四章函數(shù)函數(shù)字面量函數(shù)字面量包含個(gè)部分第一部分,保留字第二部分,函數(shù)名,它可以被忽略。這個(gè)超級(jí)延遲綁定使得函數(shù)對(duì)高度復(fù)用。構(gòu)造器調(diào)用模式一個(gè)函數(shù),如果創(chuàng)建的目的就是希望結(jié)合的前綴來(lái)調(diào)用,那它就被稱為構(gòu)造器構(gòu)造。 《JavaScript 語(yǔ)言精粹》 讀書(shū)筆記 第四章 函數(shù) Functions 函數(shù)字面量 函數(shù)字面量包含4個(gè)部分: 第一部分, 保留字 function...

    wdzgege 評(píng)論0 收藏0
  • JavaScript 設(shè)計(jì)模式與開(kāi)發(fā)實(shí)踐讀書(shū)筆記

    摘要:設(shè)計(jì)模式與開(kāi)發(fā)實(shí)踐讀書(shū)筆記最近利用碎片時(shí)間在上面閱讀設(shè)計(jì)模式與開(kāi)發(fā)實(shí)踐讀書(shū)這本書(shū),剛開(kāi)始閱讀前兩章內(nèi)容,和大家分享下我覺(jué)得可以在項(xiàng)目中用的上的一些筆記。事件綁定暫時(shí)這么多,以后會(huì)不定期更新一些關(guān)于我讀這本書(shū)的筆記內(nèi)容 JavaScript 設(shè)計(jì)模式與開(kāi)發(fā)實(shí)踐讀書(shū)筆記 最近利用碎片時(shí)間在 Kindle 上面閱讀《JavaScript 設(shè)計(jì)模式與開(kāi)發(fā)實(shí)踐讀書(shū)》這本書(shū),剛開(kāi)始閱讀前兩章內(nèi)容,...

    FingerLiu 評(píng)論0 收藏0
  • JavaScript模式讀書(shū)筆記(五)對(duì)象創(chuàng)制模式

    命名空間 var MYNAMESPACE = MYNAMESPACE || {}; //構(gòu)造函數(shù) MYNAMESPACE.Child = function () {} // 變量 MYNAMESPACE.mystr= 6-ara forerer MYNAMESPACE.Person = function(name) { this.name = name; }; //原型 MYNAMES...

    Yujiaao 評(píng)論0 收藏0
  • Effective JavaScript讀書(shū)筆記(一)

    摘要:如果為假值,不傳或者傳入,函數(shù)都會(huì)返回但是,傳入這個(gè)值是完全有可能的,所以這種判斷形勢(shì)是不正確的或者使用來(lái)判斷也可以原始類(lèi)型優(yōu)于封裝類(lèi)型對(duì)象擁有六個(gè)原始值基本類(lèi)型布爾值,數(shù)字,字符串,,和對(duì)象。 作為一個(gè)前端新人,多讀書(shū)讀好書(shū),夯實(shí)基礎(chǔ)是十分重要的,正如蓋樓房一樣,底層穩(wěn)固了,才能越壘越高。從開(kāi)始學(xué)習(xí)到現(xiàn)在,基礎(chǔ)的讀了紅寶書(shū)《JavaScript高級(jí)程序設(shè)計(jì)》,犀牛書(shū)《JavaScri...

    zhoutao 評(píng)論0 收藏0
  • JavaScript 設(shè)計(jì)模式讀書(shū)筆記(六)——門(mén)面模式

    摘要:簡(jiǎn)單的門(mén)面模式實(shí)例事件綁定函數(shù)門(mén)面模式的作用是將復(fù)雜的接口進(jìn)行包裝,變成一個(gè)便于使用的接口。還是以事件相關(guān)為例,事件綁定中還有兩個(gè)常用的分別是和。 門(mén)面模式是什么,與其我去用笨拙的語(yǔ)言去解釋,不如看下面這張圖,曾經(jīng)在網(wǎng)上很火的一張圖片,說(shuō)的是一位兒子為他的爸媽設(shè)置的電腦桌面。 showImg(http://segmentfault.com/img/bVcgHm); 有了這些起好名字...

    pubdreamcc 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

閱讀需要支付1元查看
<