<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          9種日常JavaScript編程中經(jīng)常使用的對(duì)象創(chuàng)建模式

          共 9193字,需瀏覽 19分鐘

           ·

          2021-03-18 10:08

          作者 | 湯姆大叔

          介紹

          今天這篇文章主要是跟大家分享9種日常JavaScript編程中經(jīng)常使用的對(duì)象創(chuàng)建模式,利用各種技巧可以極大地避免了錯(cuò)誤或者可以編寫出非常精簡(jiǎn)的代碼。希望對(duì)你有所幫助。

          模式1:命名空間(namespace)

          命名空間可以減少全局命名所需的數(shù)量,避免命名沖突或過度。一般我們?cè)谶M(jìn)行對(duì)象層級(jí)定義的時(shí)候,經(jīng)常是這樣的:
          var app = app || {};app.moduleA = app.moduleA || {};app.moduleA.subModule = app.moduleA.subModule || {};app.moduleA.subModule.MethodA = function () {    console.log("print A");};app.moduleA.subModule.MethodB = function () {    console.log("print B");};

          如果層級(jí)很多的話,那就要一直這樣繼續(xù)下去,很是混亂。namespace模式就是為了解決這個(gè)問題而存在的,我們看代碼:

          // 不安全,可能會(huì)覆蓋已有的MYAPP對(duì)象var MYAPP = {};// 還好if (typeof MYAPP === "undefined") {    var MYAPP = {};}// 更簡(jiǎn)潔的方式var MYAPP = MYAPP || {};
          //定義通用方法MYAPP.namespace = function (ns_string) { var parts = ns_string.split('.'), parent = MYAPP, i;
          // 默認(rèn)如果第一個(gè)節(jié)點(diǎn)是MYAPP的話,就忽略掉,比如MYAPP.ModuleA if (parts[0] === "MYAPP") { parts = parts.slice(1); }
          for (i = 0; i < parts.length; i += 1) { // 如果屬性不存在,就創(chuàng)建 if (typeof parent[parts[i]] === "undefined") { parent[parts[i]] = {}; } parent = parent[parts[i]]; } return parent;};

          調(diào)用代碼,非常簡(jiǎn)單:

          // 通過namespace以后,可以將返回值賦給一個(gè)局部變量var module2 = MYAPP.namespace('MYAPP.modules.module2');console.log(module2 === MYAPP.modules.module2); // true
          // 跳過MYAPPMYAPP.namespace('modules.module51');
          // 非常長(zhǎng)的名字MYAPP.namespace('once.upon.a.time.there.was.this.long.nested.property');

          模式2:定義依賴

          有時(shí)候你的一個(gè)模塊或者函數(shù)可能要引用第三方的一些模塊或者工具,這時(shí)候最好將這些依賴模塊在剛開始的時(shí)候就定義好,以便以后可以很方便地替換掉。

          var myFunction = function () {    // 依賴模塊    var event = YAHOO.util.Event,        dom = YAHOO.util.dom;
          // 其它函數(shù)后面的代碼里使用局部變量event和dom};

          模式3:私有屬性和私有方法

          JavaScript本書不提供特定的語法來支持私有屬性和私有方法,但是我們可以通過閉包來實(shí)現(xiàn),代碼如下:

          function Gadget() {    // 私有對(duì)象    var name = 'iPod';    // 公有函數(shù)    this.getName = function () {        return name;    };}var toy = new Gadget();
          // name未定義,是私有的console.log(toy.name); // undefined
          // 公有方法訪問nameconsole.log(toy.getName()); // "iPod"
          var myobj; // 通過自執(zhí)行函數(shù)給myobj賦值(function () { // 自由對(duì)象 var name = "my, oh my";
          // 實(shí)現(xiàn)了公有部分,所以沒有var myobj = { // 授權(quán)方法 getName: function () { return name; } };} ());

          模式4:Revelation模式

          也是關(guān)于隱藏私有方法的模式,和《深入理解JavaScript之全面解析Module模式》里的Module模式有點(diǎn)類似,但是不是return的方式,而是在外部先聲明一個(gè)變量,然后在內(nèi)部給變量賦值公有方法。代碼如下:

          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; }
          //通過賦值的方式,將上面所有的細(xì)節(jié)都隱藏了 myarray = { isArray: isArray, indexOf: indexOf, inArray: indexOf };} ());
          //測(cè)試代碼console.log(myarray.isArray([1, 2])); // trueconsole.log(myarray.isArray({ 0: 1 })); // falseconsole.log(myarray.indexOf(["a", "b", "z"], "z")); // 2console.log(myarray.inArray(["a", "b", "z"], "z")); // 2
          myarray.indexOf = null;console.log(myarray.inArray(["a", "b", "z"], "z")); // 2

          模式5:鏈模式

          鏈模式可以你連續(xù)可以調(diào)用一個(gè)對(duì)象的方法,比如obj.add(1).remove(2).delete(4).add(2)這樣的形式,其實(shí)現(xiàn)思路非常簡(jiǎn)單,就是將this原樣返回。代碼如下:

          var obj = {    value: 1,    increment: function () {        this.value += 1;        return this;    },    add: function (v) {        this.value += v;        return this;    },    shout: function () {        console.log(this.value);    }};
          // 鏈方法調(diào)用obj.increment().add(3).shout(); // 5
          // 也可以單獨(dú)一個(gè)一個(gè)調(diào)用obj.increment();obj.add(3);obj.shout();

          模式6:函數(shù)語法糖

          函數(shù)語法糖是為一個(gè)對(duì)象快速添加方法(函數(shù))的擴(kuò)展,這個(gè)主要是利用prototype的特性,代碼比較簡(jiǎn)單,我們先來看一下實(shí)現(xiàn)代碼:

          if (typeof Function.prototype.method !== "function") {    Function.prototype.method = function (name, implementation) {        this.prototype[name] = implementation;        return this;    };}

          擴(kuò)展對(duì)象的時(shí)候,可以這么用:

          var Person = function (name) {    this.name = name;}.method('getName',            function () {                return this.name;            }).method('setName', function (name) {    this.name = name;    return this;});

          這樣就給Person函數(shù)添加了getName和setName這2個(gè)方法,接下來我們來驗(yàn)證一下結(jié)果:

          var a = new Person('Adam');console.log(a.getName()); // 'Adam'console.log(a.setName('Eve').getName()); // 'Eve'

          模式7:對(duì)象常量

          對(duì)象常量是在一個(gè)對(duì)象提供set,get,ifDefined各種方法的體現(xiàn),而且對(duì)于set的方法只會(huì)保留最先設(shè)置的對(duì)象,后期再設(shè)置都是無效的,已達(dá)到別人無法重載的目的。實(shí)現(xiàn)代碼如下:

          var constant = (function () {    var constants = {},        ownProp = Object.prototype.hasOwnProperty,    // 只允許設(shè)置這三種類型的值        allowed = {            string: 1,            number: 1,            boolean: 1        },        prefix = (Math.random() + "_").slice(2);
          return { // 設(shè)置名稱為name的屬性 set: function (name, value) { if (this.isDefined(name)) { return false; } if (!ownProp.call(allowed, typeof value)) { return false; } constants[prefix + name] = value; return true; }, // 判斷是否存在名稱為name的屬性 isDefined: function (name) { return ownProp.call(constants, prefix + name); }, // 獲取名稱為name的屬性 get: function (name) { if (this.isDefined(name)) { return constants[prefix + name]; } return null; } };} ());

          驗(yàn)證代碼如下:

          // 檢查是否存在console.log(constant.isDefined("maxwidth")); // false
          // 定義console.log(constant.set("maxwidth", 480)); // true
          // 重新檢測(cè)console.log(constant.isDefined("maxwidth")); // true
          // 嘗試重新定義console.log(constant.set("maxwidth", 320)); // false
          // 判斷原先的定義是否還存在console.log(constant.get("maxwidth")); // 480

          模式8:沙盒模式

          沙盒(Sandbox)模式即時(shí)為一個(gè)或多個(gè)模塊提供單獨(dú)的上下文環(huán)境,而不會(huì)影響其他模塊的上下文環(huán)境,比如有個(gè)Sandbox里有3個(gè)方法event,dom,ajax,在調(diào)用其中2個(gè)組成一個(gè)環(huán)境的話,和調(diào)用三個(gè)組成的環(huán)境完全沒有干擾。Sandbox實(shí)現(xiàn)代碼如下:

          function Sandbox() {    // 將參數(shù)轉(zhuǎn)為數(shù)組    var args = Array.prototype.slice.call(arguments),    // 最后一個(gè)參數(shù)為callback        callback = args.pop(),        // 除最后一個(gè)參數(shù)外,其它均為要選擇的模塊        modules = (args[0] && typeof args[0] === "string") ? args : args[0],        i;
          // 強(qiáng)制使用new操作符 if (!(this instanceof Sandbox)) { return new Sandbox(modules, callback); }
          // 添加屬性 this.a = 1; this.b = 2;
          // 向this對(duì)象上需想添加模塊 // 如果沒有模塊或傳入的參數(shù)為 "*" ,則以為著傳入所有模塊 if (!modules || modules == '*') { modules = []; for (i in Sandbox.modules) { if (Sandbox.modules.hasOwnProperty(i)) { modules.push(i); } } }
          // 初始化需要的模塊 for (i = 0; i < modules.length; i += 1) { Sandbox.modules[modules[i]](this); }
          // 調(diào)用 callback callback(this);}
          // 默認(rèn)添加原型對(duì)象Sandbox.prototype = { name: "My Application", version: "1.0", getName: function () { return this.name; }};

          然后我們?cè)俣x默認(rèn)的初始模塊:

          Sandbox.modules = {};
          Sandbox.modules.dom = function (box) { box.getElement = function () { }; box.getStyle = function () { }; box.foo = "bar";};
          Sandbox.modules.event = function (box) { // access to the Sandbox prototype if needed: // box.constructor.prototype.m = "mmm"; box.attachEvent = function () { }; box.detachEvent = function () { };};
          Sandbox.modules.ajax = function (box) { box.makeRequest = function () { }; box.getResponse = function () { };};

          調(diào)用方式如下:

          // 調(diào)用方式Sandbox(['ajax', 'event'], function (box) {    console.log(typeof (box.foo));    // 沒有選擇dom,所以box.foo不存在});
          Sandbox('ajax', 'dom', function (box) { console.log(typeof (box.attachEvent)); // 沒有選擇event,所以event里定義的attachEvent也不存在});
          Sandbox('*', function (box) { console.log(box); // 上面定義的所有方法都可訪問});

          通過三個(gè)不同的調(diào)用方式,我們可以看到,三種方式的上下文環(huán)境都是不同的,第一種里沒有foo; 而第二種則沒有attachEvent,因?yàn)橹患虞d了ajax和dom,而沒有加載event; 第三種則加載了全部。

          模式9:靜態(tài)成員

          靜態(tài)成員(Static Members)只是一個(gè)函數(shù)或?qū)ο筇峁┑撵o態(tài)屬性,可分為私有的和公有的,就像C#或Java里的public static和private static一樣。

          我們先來看一下公有成員,公有成員非常簡(jiǎn)單,我們平時(shí)聲明的方法,函數(shù)都是公有的,比如:

          // 構(gòu)造函數(shù)var Gadget = function () {};
          // 公有靜態(tài)方法Gadget.isShiny = function () { return "you bet";};
          // 原型上添加的正常方法Gadget.prototype.setPrice = function (price) { this.price = price;};
          // 調(diào)用靜態(tài)方法console.log(Gadget.isShiny()); // "you bet"
          // 創(chuàng)建實(shí)例,然后調(diào)用方法var iphone = new Gadget();iphone.setPrice(500);
          console.log(typeof Gadget.setPrice); // "undefined"console.log(typeof iphone.isShiny); // "undefined"Gadget.prototype.isShiny = Gadget.isShiny;console.log(iphone.isShiny()); // "you bet"

          而私有靜態(tài)成員,我們可以利用其閉包特性去實(shí)現(xiàn),以下是兩種實(shí)現(xiàn)方式。

          第一種實(shí)現(xiàn)方式:

          var Gadget = (function () {    // 靜態(tài)變量/屬性    var counter = 0;
          // 閉包返回構(gòu)造函數(shù)的新實(shí)現(xiàn) return function () { console.log(counter += 1); };} ()); // 立即執(zhí)行
          var g1 = new Gadget(); // logs 1var g2 = new Gadget(); // logs 2var g3 = new Gadget(); // logs 3

          可以看出,雖然每次都是new的對(duì)象,但數(shù)字依然是遞增的,達(dá)到了靜態(tài)成員的目的。

          第二種方式:

          var Gadget = (function () {    // 靜態(tài)變量/屬性    var counter = 0,        NewGadget;
          //新構(gòu)造函數(shù)實(shí)現(xiàn) NewGadget = function () { counter += 1; };
          // 授權(quán)可以訪問的方法 NewGadget.prototype.getLastId = function () { return counter; };
          // 覆蓋構(gòu)造函數(shù) return NewGadget;} ()); // 立即執(zhí)行
          var iphone = new Gadget();iphone.getLastId(); // 1var ipod = new Gadget();ipod.getLastId(); // 2var ipad = new Gadget();ipad.getLastId(); // 3

          數(shù)字也是遞增了,這是利用其內(nèi)部授權(quán)方法的閉包特性實(shí)現(xiàn)的。

          總結(jié)

          以上就是今天介紹的9種對(duì)象創(chuàng)建模式,是我們?cè)谌粘avaScript編程中經(jīng)常使用的對(duì)象創(chuàng)建模式,不同的場(chǎng)景起到了不同的作用,希望大家根據(jù)各自的需求選擇適用的模式。

          參考:http://shichuan.github.com/javascript-patterns/#object-creation-patterns


          推薦閱讀

          10種JavaScript代碼復(fù)用模式


          本文完?


          瀏覽 39
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  天天日,天天插 | 中文字幕一区二区三区四区50岁 | 翔田千里在线一区二区三区 | 国产a不卡 | 国产xxx乱伦 |