類庫(kù)

本文整理自MVC的JavaScript Web富應(yīng)用開發(fā),歡迎購(gòu)買原版書籍
一、MVC是一種設(shè)計(jì)模式
4、類的概念
JavaScript 中并沒有真正的類,但JavaScript 中有構(gòu)造函數(shù)和new 運(yùn)算符。構(gòu)造函數(shù)用來給實(shí)例對(duì)象初始化屬性和值。任何JavaScript 函數(shù)都可以用做構(gòu)造函數(shù),構(gòu)造函數(shù)必須使用new 運(yùn)算符作為前綴來創(chuàng)建新的實(shí)例。
new 運(yùn)算符改變了函數(shù)的執(zhí)行上下文,同時(shí)改變了return 語句的行為。實(shí)際上,使用new和構(gòu)造函數(shù)和傳統(tǒng)的實(shí)現(xiàn)了類的語言中的使用方法是很類似的:

var Person = function(name) {
     this.name = name;
};
// 實(shí)例化一個(gè)Person
var alice = new Person('alice');
// 檢查這個(gè)實(shí)例
assert( alice instanceof Person );

要不然就返回任意非原始類型的值。比如,我們可以返回一個(gè)用以新建一個(gè)新類的函數(shù),第一步要做的是創(chuàng)建自己的類模擬庫(kù):

var Class=function(){
     var klass=function(){
          this.init.apply(this,arguments);
     }
     klass.prototype.inti=function(){};
    return klass;
}
var Person=new Class; //具體參見new的用法 此時(shí)的Person等于的是一個(gè)function
Peson.prototype.init=function(){
     //基于Person的實(shí)例做初始化
}

5、在JavaScript中,在構(gòu)造函數(shù)中給類添加函數(shù)和給對(duì)象添加屬性是一模一樣
Person.find=functon(){};
var person=Perons.find();
要想給構(gòu)造函數(shù)添加實(shí)例函數(shù),則需要用到構(gòu)造函數(shù)的prototype
Person.prototype.breath=function(){};
var person=new Person();
person.breath();
一般常用的模式是給類的prototype起一個(gè)別名,fn
Person.fn=Person.proptype;
Person.fn.run=function(){ };
6、給類庫(kù)添加方法
直接給類設(shè)置屬性和設(shè)置其靜態(tài)成員是等價(jià)的:
var Person = new Class;
// 直接給類添加靜態(tài)方法
Person.find = function(id){ /* ... / };
// 這樣我們可以直接調(diào)用它們
var person = Person.find(1);
給類的原型設(shè)置的屬性在類的實(shí)例中也是可用的:
var Person = new Class;
// 在原型中定義函數(shù)
Person.prototype.save = function(){ /
... */ };
// 這樣就可以在實(shí)例中調(diào)用它們
var person = new Person;
person.save();
我們采用另外一種不同的方法來給類添加屬性,這里用到了兩個(gè)函數(shù)extend和include

var class=function(){
     var klass=function(){
          this.init.apply(this,arguments);
     };
     klass.prototype.init=function(){};
     //定義prototype別名
     klass.fn=klass.prototype;
     //定義類的別名
     klass.fn.parent=klass;
     //給類添加屬性
     klass.extend=function(obj){
          var extended=obj.extended;
          for(var i in obj){
               klass[i]=obj[i];
          }
          if(extended) extended(klass);
     };
     //給類添加屬性
     klass.inclue=function(obj){
          var inclued=obj.inclued;
          for(var i in obj){
               klass.fn[i]=obj[i];
          }
          if(inclued) inclued(klass);
     };
}

var Person=new Class;
Person.extend({
     find:function(id){}
     exists:functions(id){}
});
var person=Person.find(1);

include() 函數(shù)的工作原理也是一樣的,只不過不是將屬性復(fù)制至類中,而是復(fù)制至類的原型中。換句話說,這里的屬性是類實(shí)例的屬性,而不是類的靜態(tài)屬性。

var Person=new Class;
Person.include({
     save:function(){},
     save:functions(id){}
})
var person=new Person;
person.save();

7、基于原型的類繼承
如果你給Array.prototype 添加了屬性,那么所有的JavaScript 數(shù)組都具有了這些屬性。代碼如下:

var Animal=function(){};
Animation.prototype.breath=function(){
     console.log("breath");
}
var Dog=function(){};
//通過原型基礎(chǔ)
Dog.prototype=new Animal;
Dog.prototype.wag=function(){
     console.log("wag')
}
實(shí)例
var dog=new Dog();
dog.breath();
dog.wag();

給“類”庫(kù)添加繼承
現(xiàn)在來給我們自定義的“類”庫(kù)添加繼承,我們通過傳入一個(gè)可選的父類來創(chuàng)建新類:

var Class=function(){
     var klass=funtion(){
          this.init.apply(this,arguments);
     };
     //改變class原型
     if(parent){
          var subclass=function(){};
          subclass.prototype=parent.prototype;
          klass.prototype=new subclass();
     };
     kclass.prototype.inti=function(){};
     //定義別名
     klass.fn=klass.prototype;
     kclass.fn.parent=klass;
     kclass._super=kclass.__prototype__;
     /* include/extend 相關(guān)的代碼…… */
     return klass;
}

var Class=function(){
     var klass=funtion(){
          this.init.apply(this,arguments);
     };
     //改變class原型
     if(parent){
          var subclass=function(){};
          subclass.prototype=parent.prototype;
          klass.prototype=new subclass();
     };
     kclass.prototype.inti=function(){};
     //定義別名
     klass.fn=klass.prototype;
     kclass.fn.parent=kclass;
     kclass._super=kclass.__prototype__;
     /* include/extend 相關(guān)的代碼…… */
     klass.extend=function(obj){
          var extended=obj.extended;
          for(var i in obj){
               klass[i]=obj[i];
          }
          if(extended) extended(klass);
     };
     //給類添加屬性
     klass.inclue=function(obj){
          var inclued=obj.inclued;
          for(var i in obj){
               klass.fn[i]=obj[i];
          }
          if(inclued) inclued(klass);
     };
     return klass;
}

8、函數(shù)調(diào)用
在javascript中,函數(shù)和其他東西都是對(duì)象,然而函數(shù)可調(diào)用。
jQuery 在其API 的實(shí)現(xiàn)中就利用了apply() 和call() 來更改上下文,比如在事件處理程序中或者使用each() 來做迭代時(shí)。起初這很讓人費(fèi)解,一旦你理解了就會(huì)發(fā)現(xiàn)它非常有用:

$('.clicky’).click(function(){
// ‘this’指向當(dāng)前節(jié)點(diǎn)
$(this).hide();
});
$('p’).each(function(){
// ‘this’指向本次迭代
$(this).remove();
});

為了訪問原始上下文,可以將this的值存入一個(gè)局部變量中,這是一個(gè)常見的模式;

var clicky=function(){
     wasClicked:function(){};
     addListeners:function(){
          var self=this;
          $('.cicky').click(
               fuction(){
                    sele.wasCliked();
               };
          )
     }
}
clicky.addListeners();
然而,我們可以使用apply 來將這段代碼變得更干凈一些,通過將回調(diào)包裝在另外一個(gè)匿名函數(shù)中,來保持原始的上下文:
var proxy=function(func,thisObject){
     return (
          function (){
               return func.apply(thisObject,arguments);//改變func的執(zhí)行對(duì)象
          }
     )
}
var clicky={
     wasClicked:function{};
     addListener:function(){
          var self=this;
          $('.clicky').click(proxy(this.wasClicked,this));
     }
}
var App {
log: function(){
     if (typeof console == "undefined") return;
// 將參數(shù)轉(zhuǎn)換為合適的數(shù)組
var args = jQuery.makeArray(arguments);
// 插入一個(gè)新的參數(shù)
args.unshift("(App)");
// 委托給console
console.log.apply(console, args);
}
};

9、控制類庫(kù)的作用域
我們?cè)陬惡蛯?shí)例中都添加proxy 函數(shù),這樣就可以在事件處理程序之外處理函數(shù)的時(shí)候和下面這段代碼所示的場(chǎng)景中保持類的作用域:

var Class=function(parent){
     var klass=function(){
          this.init.apply(this,argument)
     };
     klass.prototype.init=function(){};
     klass.fn=klass.prototype;
     klass.fn.parent=ckass;
     //添加一個(gè)poxy函數(shù)
     klass.proxy=function(func){
          var self=this;
          return (function(){
               return func.apply(self,arguments)
          })
     }
     //在實(shí)例中冶添加
     klass.prototype=klass.proxy;
     return klass;
}
現(xiàn)在使用proxy函數(shù)來包裝函數(shù),以包裝在作用域中正確調(diào)用
var Button=new Class();
Button.include({
     init:function(){
          this.element=jQuery(element);
          //代理click函數(shù)
          this.element.click(this.proxy(this.click));
     //this.element.click(this.click.apply(this.argument))
     },
     click:function(){}
});

9、添加私有函數(shù)
通過創(chuàng)建匿名函數(shù)的方式來創(chuàng)建私有作用域;

var Person = function(){};
(function(){
     var findById = function(){ /* ... */ };
     Person.find = function(id){
     if (typeof id == "integer")
          return findById(id);
     };
})();

我們將類的屬性都包裝進(jìn)一個(gè)匿名函數(shù)中,然后創(chuàng)建了局部變量(findById),這些局部變量只能在當(dāng)前作用域中被訪問到。Person 變量是在全局作用域中定義的,因此可以在任何地方都能訪問到。
定義變量的時(shí)候不要丟掉var 運(yùn)算符,因?yàn)槿绻麃G掉var 就會(huì)創(chuàng)建全局變量。如果你需要定義全局變量,在全局作用域中定義它或者定義為window 的屬性:

(function(exports){
     var foo = "bar";
     // 將變量暴露出去
     exports.foo = foo;
})(window);
assertEqual(foo, "bar");
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容