2017-04-05 面向對象 學習筆記

工廠模式補充

  • 核心思路
  • 提供父構造函數
  • 設置構造函數的原型對象
  • 提供工廠方法
  • 定制合作伙伴(設置子構造函數)
  • 使用工廠函數創建對象
function MakePerson(){};
MakePerson.prototype.desLog = function(){
        console.log(this.des);
}
MakePerson.factory = function(type){
        if(type == undefined){
                throw "錯誤";
        }
        if(typeof MakePerson[type] !='function'){
                throw "錯誤";
        }
        //設置原型對象繼承
        MakePerson[type].prototype = MakePerson.prototype;
        //創建對象
        var newPerson = new MakePerson[type]();
        return newPerson;
}
MakePerson.badMan = fucntion(){
        this.des = '我是壞人';
}
MakePerson.goodMan = function(){
        this.des = '我是好人';
}
MakePerson.ladyBoy = function(){
        this.des = '我是人妖';
}
var badMan = MakePerson.factory('badMan');
badMan.desLog();
var ladyBoy = MakePerson.factory('ladyBoy');
ladyBoy.desLog();

單例模式簡單說明

  • 單例模式

  • 其他語言
    一個類在整個程序運行過程中只有一個實例對象

  • js 語言:js 本身并沒有類的概念,動態,腳本,弱類型,基于原型對象,面向對象。
    構造函數創建出來的對象永遠都是同一個對象

  • js 中的對象

  • 字面量的方式{}

  • 內置構造函數 + 工廠函數

  • 自定義構造函數

  • 使用場景

  • 某一個實例對象在程序中多次使用,每次在使用的時候不需要都重新創建,只需要創建一個,以后再用的時候直接復用之前的對象就可以

單例模式的實現

  • 全局變量
  • 提供一個全局的變量
  • 在構造函數內部先檢查全局變量是否有值
  • 如果有值,說明之前已經創建并賦值了,如果沒有值,那么說明是第一次調用
  • 如果是第一次調用那么就把新創建的對象賦值給變量,第二次調用的時候變量就有值了
  • 缺點
    全局變量在整個作用域中都可以訪問和修改,因此不安全
function Dog(){
        return 10;
}
var d1 = new Dog();
var d2 = new Dog();
var instance;
function Person(){
        if(instance){
                console.log('對象已經存在,直接返回');
                return instance;
        }
        //創建空對象并且賦值給 this
        instance = this;
        this.name = '張三';
        console.log('第一次調用');
}
var p1 = new Person();
var p2 = new Person();
var p3 = new Person();
var p4 = new Person();
console.log(p1 == p4);
//instance = {age:20}:
var p5 = new Person();
console.log(p5,p1);
//instance = 'demo';
console.log(p5);   //新創建的對象()

單例模式的實現方式2(靜態屬性)

function Person(){
        if(Person.instance){
                console.log('對象已經存在,直接返回');
                return Person.instance;
         }
         this.name = '張三';
        Person.instance = this;
        console.log('對象是第一次創建');
}
var p1 = new Person();
var p2 = new Person();
console.log(p1 ==  p2);
var p3 = new Person();
var instance = 'demo';
var p4 = new Person();
console.log(p1 == p4);
Person.instance = {};
var p5 = new Person{};
console.log(p1 == p5);

單例模式的實現方式3(閉包-惰性函數)

  • 閉包 + 惰性函數定義
  • 問題:
    對象的構造器屬性指向的是舊的構造函數
    在創建對象后設置的原型對象成員無法訪問
function Person(){
        //提供私有變量
        var instance;
        //設置屬性并把對象賦值給私有變量
        this.name = '張三';
        instance = this;
        console.log('第一次調用');
        //重新構造函數
        Person = function(){
                console.log('直接返回');
                return instance;
        }
}
Person.prototype.old = '老的';
var p1 = new Person();
var p2 = new Person();
Person.prototype.new = '新的';
console.log(p1.constructor == p2.constructor);  //相等
console.log(p1.constructor == Person);
console.log(p1.constructor);
console.log(Person);
console.log(p1.old);
console.log(p1.new);

單例模式的實現方式4(閉包-惰性函數定義)

  • 核心過程
  • 提供構造函數
  • 提供私有變量
  • 重寫構造函數,在構造函數內部直接返回私有變量
  • 設置構造函數的原型對象
  • 創建 new 構造函數對象,賦值給私有變量
  • 設置構造器屬性
  • 設置私有變量指向對象的成員
  • 把私有變量返回
function Person(){
        var instance;
        Person = function(){
                return instance;
        }
console.log(name);
//設置構造函數的原型對象
//__proto__ 在正式的代碼中不推薦使用
//Person.prototype = this.__proto__;
Person.prototype = Object.getPrototype(this);
//Person.prototype = this;    this 實例對象
//創建 new 構造函數對象,賦值給私有變量
instance = new Person();
//設置構造器屬性
//instance.constructor = Person;    添加屬性
Person.prototype.constructor = Person;
//設置私有變量指向對象的成員
instance.name = "張安";
//把私有變量返回
return instance;
}
Person.prototype.hi = 'hi';
var p1 = new Person();
var p2 = new Person();
Person.prototype.hello = 'hello';
console.log(p1 == p2);
console.log(p1.constructor == Person);
console.log(p1.hi);
console.log(p1.hello);

單例模式的實現方式5(全局變量-即時函數)

var Person;
(function(){
        var instance;
        Person = function(){
                if(instance){
                        return instance;
                }
                instance = this;
                this.name = '張三';
        }
})()

var p1 = new Person();
var p2 = new Person();

//console.log(instance);
console.log(p1 == p2);

觀察者模式簡單介紹

觀察者模式
售樓部 王
客戶1(手機)
客戶2(手機)
張三 - 莉莉(我餓了);
狀態發布者(被觀察者)
狀態訂閱者(觀察者)
注冊訂閱者

var lili = {
        user: [];
        addUser:funciton(fn){
                this.user.push(fn)
        },
        eat:function(){
                console.log('我餓了');
                for(var i = 0;i < this.user.length;i++){
                        this.user[i]();
                }
        }
};
var zhangsan = {
        eat_lili:function(){
                console.log('我陪你一起去吃飯把');
        }
};
var lisi = {
        eat_lili:funciton(){
                console.log('我已經把飯做好了,等會來我家——李四');
        }      
};
lili.addUser(zhangsan.eat_lili);
lili.eat();
lili.addUser(lisi.eat_lili);
lili.eat();

觀察者模式實現1(基礎版本)

var rose = {
        use:[],
        addUser:funciton(fn){
                this.user.push(fn);
        },
        removeUser:fucntion(fn){
                for(var i = 0; i < this.user.length;i++){
                        if(this.user[i] == fn){
                                console.log('用戶取消');
                                this.user.spllice(i,1);
                                break;
                        }
                }
        },
        sleep.funciton(){
                console.log('我困了___rose');
                for(var i = 0; i < this.user.length; i ++){
                        this.user[i]();
                }
        }
};
var lucy = {
        user:[],
        addUser:function(fn){
                for(var i = 0;i < this.user.length;i++){
                        if(this.user[i] == fn){
                                console.log('用戶取消了訂閱');
                                this.user.splice(i,1);
                                break;
                        }
                }
        },
        sleep:function(){
                console.log('我困了__lucy');
                for(var i = 0;i < this.user.length:i++){
                        this.user[i]();
                }
        }
}
var jack = {
        sleep_rose:function(){
                console.log('天黑說晚安__jack');
        }
}
var tom = {
        sleep_rose:function(){
                console.log('白天不懂夜的黑__tom');
        },
        sleep_lucy:function(){
                console.log('白夜行__tom');
        }
}
rose.addUser(jack.sleep_rose);
rose.addUser(tom.sleep_rose);
lucy.addUser(tom.sleep_lucy);
lucy.sleep();
rose.sleep();

觀察者模式2(多個發布者)

角色:
rose:發布者
Jack:訂閱者
狀態:
我困了
響應:
說一句晚安
1發布者2訂閱者
思考:2發布者(rose + lucy)2訂閱者
rose - jack
rose - tom
lucy - tom
多個發布者
把發布者的共同部分提取出來作為一個模版(對象)
如果有某個對象想要稱為發布者,那么直接拷貝模版對象即可(封裝函數)
思考:2發布者(rose + lucy)2訂閱者 多個狀態
我困了(rose - jack)
我餓了(rose - tom)

var publisher = {
        addUser:function(fn){
                this.user.push(fn);
        },
        removeUser:function(fn){
                for(var i = 0;i < this.user.length;i++){
                        if(this.user[i] == fn){
                              console.log('用戶取消了');
                              this.user.splice(i,1);
                              break;
                        }
                }
        },
        sleep:funciton(){
                console.log('我困了');
                for(var i = 0;i < this.user.length;i++){
                        this.user[i]();
                }
        }
}
funciton MakePublisher(o){
        for(var i inpublisher){
                if(publisher.hasOwnProperty(i) && typeof publisher[i] == 'function'){
                        o[i] = publisher[i];
                }
        }
        o.user = [];
}
var rose = {};
var lucy = {};
MakePublisher(rose);
MakePublisher(lucy);
var jack = {
        sleep_rose:funciton(){
                console.log('天黑說晚安__jack');
        }
};
var tom = {
        sleep_rose:function(){
                console.log('白天不懂夜的黑__tom');
        },
        sleep_lucy:function(){
                console.log('白夜行__tom');
        }
};
rose.addUser(jack.sleep_rose);
rose.sleep();
lucy.addUser(tom.sleep_lucy);
lucy.sleep();

觀察者模式實現3(多個狀態)

var publisher = {
        addUser:function(fn,type){
                this.user[type].push(fn);
        },
        removeUser:function(fn,type){
                for(var i = 0; i < this.user.length;i++){
                          if(this.user[type][i] == fn){
                                  console.log('用戶取消了訂閱');
                                  this.user[type].splice(i,1);
                                  break;
                          }
                 }
        }
};
function MakePublisher(o){
        for(var i in publisher){
                if(publisher.hasOwnProperty(i)&&typeof publisher[i] == 'function'){
                                                o[i] = publisher[i];
                }
        }
        o.user = {
                eat:[],
                sleep:[],
                read:[]
        };
}
var rose = {
        sleep:function(){
                for(var i = 0 ;i < this.user['sleep'].length;i++){
                        this.user['sleep'][i]();
                }
        },
        eat:function(){
                console.log('我困了__');
                for(var i = 0 ; i< this.user['eat'].length;i++){
                        this.user['eat'][i]();
                }
        }
};
MakePublisher(rose);
var jack = {
        sleep_rose:funciton(){
                console.log('天黑說晚安__');
        }
};
var tom = {
        eat_rose:function(){
                console.log('我們一起去吃大餐吧___tom');
        },
        read_lucy:function(){
                console.log('我在圖書館門口等你__tom');
        }
};
rose.addUser(jack.sleep_rose,'sleep');
rose.addUser(tom.eat_rose,'eat');
rose.sleep();
rose.eat();
var lucy = {
        read:funciton(){
                console.log('我想看書');
                for(var i = 0 ; i < this.user['read'].length:i++){
                        this.user['read'][i]();
                }
        }
};
MakePublisher(lucy);
lucy.addUser(tom.read_lucy,'read');
lucy.read();

觀察者模式實現4(通用處理)

var publisher = {
        addUser:function(fn,type){
                if(this.user[type] == undefined){
                        this.user[type] = [];
                }
                this.user[type].push(fn);
        },
        removeUser:function(fn,type){
                this.publish(type,fn);
        },
        publish:function(type,fn){
                for(var i = 0 ;i < this.user[type].length;i++){
                        if(typeof fn == 'function'){
                                if(this.user[type][i] == fn){
                                        console.log('用戶取消了訂閱');  
                                        this.user[type].splice(i,1);
                                        break;
                                }
                        }else{
                                this.type[type][i]();
                        }
                }
        }
}
function MakePublisher(o){
        for(var i in publisher){
                if(publisher.hasOwnProperty(i)&&typeof publisher[i] =='function'){
                        o[i] = publisher[i];
                }
        }
        o.user = {};
}
var rose = {
        sleep:function(){
                console.log('我困了');
                this.publish('sleep');
        },
        eat:function(){
                console.log('我餓了');
                this.publish('我餓了');
        }
};
var jack  = {
        sleep_rose:function(){
                console.log('天黑說晚安__jack');
        }
}
  var tom  = {
        eat_rose:function () {
            console.log("我們一起去吃大餐吧___tom");
        },
        read_lucy:function () {
            console.log("我在圖書館門口等你___tom");
        },
        run_lucy:function () {
            console.log("我在操場等你___tom");
        },
    }
    rose.addUser(jack.sleep_rose,"sleep");
    rose.addUser(tom.eat_rose,"eat");
    rose.sleep();
    rose.eat();

    var lucy = {
        read:function () {
            console.log("我想看書");
            this.publish("read");
        },
        run:function () {
            console.log("我想跑步");
            this.publish("run");
        },
    };
    MakePublisher(lucy);
    lucy.addUser(tom.read_lucy,"read");
    lucy.read();
    lucy.addUser(tom.run_lucy,"run");
    lucy.run();
    lucy.removeUser(tom.run_lucy,"run");
    lucy.run();

觀察者模式5(讓訂閱者稱為發布者)

 var publisher = {
        addUser:function (fn,type) {
            if (this.user[type] == undefined) {
                this.user[type] = [];
            }
            this.user[type].push(fn);
        },
        removeUser:function (fn,type) {
           this.publish(type,fn);
        },
        publish:function (type,fn) {
            for (var i = 0; i < this.user[type].length; i++) {
                if (typeof fn == "function")
                {
                    if (this.user[type][i] == fn)
                    {
                        console.log("用戶取消了訂閱");
                        this.user[type].splice(i,1);
                        break;
                    }
                }else
                {
                    this.user[type][i]();
                }

            }
        }
    }
    function MakePublisher(o) {
        for (var i in publisher) {
            if (publisher.hasOwnProperty(i) && typeof publisher[i] == "function")
            {
                o[i] = publisher[i];
            }
        }
        o.user = {};
    }

    var rose = {
        run:function () {
            console.log("我要去跑步啦,有一起的嗎?");
            this.publish("run");
        },
        read_jack:function () {
            console.log("我陪你一起吧");
        }
    };
    MakePublisher(rose);

    var jack = {
        run_rose:function () {
            console.log("我在操場等你");
        },
        read:function () {
            console.log("我要看書啦");
            this.publish("read");
        }
    }
    rose.addUser(jack.run_rose,"run");
    rose.run();

    MakePublisher(jack);
    jack.addUser(rose.read_jack,"read");
    jack.read();

備忘模式(函數結構緩存)

  • 如果一個函數內部實現復雜,執行需要花費很長時間,且可能會調用多次,且參數可能一樣,我們考慮對結果進行緩存處理,不必每次調用的時候都執行一遍函數
  • 在函數內部:
  • 先檢查想要的結果是否存在,如果存在那么就直接返回
  • 如果不存在,那么就執行一遍函數得到結果并保存到緩存中
<script>
    var cache = {};
    function demo(param) {
        if (cache[param])
        {
            console.log("直接使用緩存數據");
            return cache[param];
        }
        //會花很長的時間處理任務,得到一個結果
        var str = param + "我是一個很復雜的任務";
        cache[param] = str;
        console.log("執行函數,計算得到結果,并且保存一份到緩存中");
        return str;
    }

    demo("hello");
    demo("hello");
    demo("hello");

</script>

<script>
    function demo(param) {
        if (demo.cache[param])
        {
            console.log("直接使用緩存數據");
            return demo.cache[param];
        }
        //會花很長的時間處理任務,得到一個結果
        var str = param + "我是一個很復雜的任務";
        demo.cache[param] = str;
        console.log("執行函數,計算得到結果,并且保存一份到緩存中");
        return str;
    }

    //初始化
    demo.cache = {};
    demo("hello");
    demo("hello");
    demo("hello");

</script>

命名空間模式

  • 把所有的東西都寫在一個對象里面
  • 命名空間
  • 其他語言都支持命名空間。
  • js 本身并沒有命名空間的概念
  • 提供一個命名空間(對象),對象的命名格式為全部大寫,推薦使用項目的名稱來命名
  • 優點
  • 全局只有一個變量,方便管理
  • 保護數據,訪問數據必須使用對象.熟悉的方式來訪問
  • 缺點
  • 前綴很長 QQ.p1.dog.name
  • 通過前綴可以操作所有的數據,因此也存在被覆蓋的問題
  • 建議:
    在每次賦值之前都需要檢查,檢查該對象|屬性是否存在

通用的命名空間函數

  var QQ = QQ || {};
    QQ.namespace = function (str) {
        //01 切割字符串
        var arr = str.split(".");

        //先刪除第一個元素
        arr.splice(0,1);
        //設置父節點
        var superNode = QQ;
        console.log(arr);
        //02 遍歷數組
        for (var i = 0; i < arr.length; i++) {
            if (superNode[arr[i]] == undefined)
            {
                superNode[arr[i]] = {}
            }

            //每循環一次,都需要更新父節點
            superNode = superNode[arr[i]];
        }
    }

    QQ.person = {
        name:"張三"
    }
    QQ.namespace("QQ.person.car.des.a.b.c.d");
    QQ.namespace("QQ.person.car.a.b.c.d.e.f.g.e.e.s.sa.a");
    console.log(QQ);

eval 的簡單說明

  • eval 的作用:
    和Function 類型,但是它并不是用來創建函數的,直接將字符串轉換稱 js 代碼執行,缺點性能不好,破壞詞法作用域

  • Function 用來創建函數對象

  • 使用注意:
    在解析 json 數據的時候注意點

  • json 和對象的區別:

  • json 是一種數據格式,有格式的字符串

  • 標準的 json 的 key 全部都加上雙引號

  • json 中不能有函數

  • 解析 json

  • json 字符串 -》 js 對象

  • js 對象 -》 json 字符串

<script>
    var func = new Function("console.log(\"我是傳奇\")");
    func();

    eval("var obj = {}");
    console.log(obj);

    var json = "{\"name\":\"張三\"}";
//    var o = JSON.parse(json);
    console.log(json);
//    console.log(o);
//    var o = eval(json);  //不正確

    //001 解決方式1
    eval("var o =" + json);
    console.log(o);
    //002 解決方式2
    var o1 = eval("(" + json + ")");
    console.log(o1);

    //o1 -- >json
    console.log(JSON.stringify(o1));;
</script>

<script>
    var a = 10;
    function demo() {
        eval("var a = 20");
        console.log(a);
    }
    demo();

</script>
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,333評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,491評論 3 416
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,263評論 0 374
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,946評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,708評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,186評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,255評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,409評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,939評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,774評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,976評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,518評論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,209評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,641評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,872評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,650評論 3 391
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,958評論 2 373

推薦閱讀更多精彩內容

  • 工廠模式類似于現實生活中的工廠可以產生大量相似的商品,去做同樣的事情,實現同樣的效果;這時候需要使用工廠模式。簡單...
    舟漁行舟閱讀 7,798評論 2 17
  • Spring Cloud為開發人員提供了快速構建分布式系統中一些常見模式的工具(例如配置管理,服務發現,斷路器,智...
    卡卡羅2017閱讀 134,781評論 18 139
  • 前言 人生苦多,快來 Kotlin ,快速學習Kotlin! 什么是Kotlin? Kotlin 是種靜態類型編程...
    任半生囂狂閱讀 26,243評論 9 118
  • 昨天晚上下班回來跟媽媽視頻,媽媽說你大姨夫走了。 我要拿碗準備裝飯的手,突然不知自己要干嘛。一下癱坐到身旁的椅子上...
    花花噠世界閱讀 345評論 0 2
  • 喜歡你到底是什么感覺?我愛我的女朋友,可是我又很喜歡另一個女孩子,另一個女孩子也喜歡我,抉擇到底。。。
    刻進你生命閱讀 222評論 0 0