模式應該算是js比較高級的語法了吧。 細細數來,有什麼,構造函數模式,原型模式,訂閱者模式,blablabla~
前幾天在面試鵝廠的時候,也被問及事件模型和模式的問題。 平時用jquery用的爽啊, 什麼on,delegate,trigger常常敲,可是大公司就是大公司,要的就是基礎紮實的淫。 事件模式改天在*, 今天咱們來講說模式之辯。jquery
常常聽人說,js是一個OO的語法,一切皆是對象。可是誰**又知道你說的是什麼意思呢? 騷俠磨嘰,之因此這樣說,是由於在js中,對象其實就是一個散列表(key/value).面試
var obj = { name: "I am an Object", ability:function(){ console.log(this.name); } } obj.ability();
這應該算是一個基本的對象了,基本功能仍是有的。 之因此說起這個東西,就是由於在js中有不少概念都和對象有關,因此在這裏就先給你們一個impression吧.
切入主題ajax
寫過代碼有必定時間的淫應該都會了解一下這個模式吧。 其實說白的就是封裝,將一段重用性高的代碼,封裝起來,以便屢次調用。
老闆來個栗子~
好嘞~json
function Person(name,gender,age){ var obj = new Object(); obj.name = name; obj.gender = gender; obj.age = age; return obj; } var jimmy1 = Person("jimmy1","male",18); var jimmy2 = Person("jimmy2","male",19); console.log(jimmy1.name); //jimmy1 console.log(jimmy2.name); //jimmy2
能夠看到上面演示的, 將一個person給封裝起來,能夠建立無數多我的。 我操,那我之後就能夠用這個寫阿喂。
額~ 能夠是能夠,不過有點 waste . 並且不能很好的說明你建立的究竟是個什麼東西,咱們使用typeof,以及instanceof 來檢驗一下.app
console.log(typeof jimmy1); //"object" console.log(jimmy1 instanceof Object); //true console.log(jimmy1 instanceof Person); //false
咱們細細看一下, 上面例子中,每一個人都建立了一個Obejct() 的實例, 而後添加屬性,方法,最後再返回。 這樣寫簡單明瞭,可是咱們是有技術潔癖的人。 因此咱們要提取公因式,將重複的代碼再提出出來。 比較官方的說法叫作,構造函數模式~函數
構造函數~ 是什麼勒。 我們不弄虛的。this
take is cheap, show me u codeurl
function Person(name,gender,age){ this.name = name; this.gender = gender; this.age = age; } var jimmy1 = new Person("jimmy1",'male',18); jimmy1.name; // jimmy1 var jimmy2 = new Person("jimmy2",'male',18); jimmy2.name; // jimmy2
這就是一個超級典型的構造函數模式, 有 this,有參數,有new,還有實例。
構造函數的原理其實和工廠模式的原理同樣,就是建立一個對象,而後添加對應的屬性和方法.
構造函數不是函數嗎?怎麼和對象扯上關係了。 別忘了咱們開篇說起的 一切皆是對象。 咱們來理一理過程:prototype
(1)建立一個新對象。 // new Person(); 的做用 (2)將構造函數的做用域賦給新對象 //就是將this指向這個對象, 至關於上例中的obj (3)執行構造函數裏面的內容 //給新對象添加方法和屬性, this就是你建立的Obj (4)返回新對象 //就是Obj了
哈哈~ 是否是以爲寫代碼,也能夠寫出藝術的感受嘞~
其實構造函數模式應該算是工廠模式的一個升級版。 在每一個實例上,會存在一個constructor的屬性,來表示該對象的類型.指針
console.log(jimmy1.constructor); //Person console.log(jimmy1 instanceof Person); //true
這樣我總算能夠知道我建立的是否是 一我的了。
但實際的狀況是,我建立的是一個靜態的人,他的動做我該怎麼完成。 加唄~
function Person(name,gender,age){ this.name = name; this.gender = gender; this.age = age; this.speak = function(){ console.log("my name is " +this.name); } } var jimmy1 = new Person("jimmy1",'male',18); jimmy1.speak(); //my name is jimmy1
恩,這樣啊~ 一門高級語言,永遠不會讓你知道你不知道。
想想,和工廠模式是一個道理,每次建立一個實例,我都得實例一個對象,並且記住函數也是對象。
上面的例子中,我在建立Person的實例時, 因爲內部還有一個speak的函數,我還得建立另一個speak的實例對象。並且這些實例都是建在哪裏勒,呵呵,你的內存中~
實際狀況是,若是我建立了>1000 我的, 我比A bra 還小的4G內存怎麼活啊。 js 用於不會讓你失望的。
在社區的衍生中,出現了另一個變體: 原型模式
(Ps:這是我在面試鵝廠的時候,一個經典問題)
說起原型模式,就必須說明一下原型這個概念。想想咱們建立對象的時候作了什麼~
var obj = new Object();
其實上面的寫法,是建立了一個實例對象,而且包含了原型對象(Object)上面的全部方法.
好比說:
obj.toString(); //轉換字符串的方法
總結一下,原型模式其實就是,提供一些列共有的屬性和方法 的模式。
來個栗子:
function Person(){ } Person.prototype.name="jimmy"; Person.prototype.gender="male", Person.prototype.outName = function(){ console.log(this.name); } var jimmy = new Person(); jimmy.outName; //jimmy
。。。好難看啊~
看只是表面,咱們來講說內在。 原型模式的內涵超級豐富。 在原型模式中,新增了一個東西prototype(原型), 這就是原型模式的精華。
上面說了構造函數新增了constructor做爲表示符,原型模式裏面有prototype做爲頂樑柱.
prototype(原型)就是一個指針,用來指向一個對象,而且這個對象是全部實例共有的原型對象.
而這個原型模式和構造函數模式的最重要的一個卻別就是。this指針的指向問題.
使用構造函數模式,這個this指針指向的是構造函數裏面的this.
而使用原型模式,這個this是指向 原型對象(prototype);
我操~不理解啊~ 磨嘰,待我細細解釋.
其實建立原型的方法也是使用構造函數,只是每一個函數建立的時候會自帶一個prototype屬性指向函數的原型對象。並且prototype上還有一個constructor用來指向 該構造函數中的this. 這樣, 原型對象上面就有了和 構造函數的鏈接。
咱們能夠檢驗一下:
//一樣一個例子 function Person(){ } Person.prototype.name="jimmy"; Person.prototype.gender="male", Person.prototype.outName = function(){ console.log(this.name); } var jimmy = new Person(); console.log(jimmy.constructor); //Person console.log(Person.prototype.constructor); //Person
如今咱們只要知道Person.prototype就是表明Person的原型,that's enough~
關於__proto__,prototype,constructor後面我會專門獨立出來講明的。
留個坑,寫完了放一個連接.
說了這麼多,濛濛噠~
來,總結一下實例與構造函數模式以及原型模式之間的聯繫:
原型模式 | 實例<--->構造函數的原型對象 |
構造函數模式: | 實例<--->構造函數 |
這樣應該差很少能理解吧。 盡力了~
可是,一門高級的語言不會讓你知道你不知道.
實際上,使用原型的坑也是不少的。重用性解決了,可是自定義卻不能實現了。
然而這只是一小部分,給你來個大的。
原型模式之引用類型的坑
talk is cheap, show me u code
function Person(){} Person.prototype.wife = { "Sheily":{ age:23, height:170 }, "Adel":{ age:20, height:172 } } var jimmy = new Person(); console.log(jimmy.wife); //兩我的 var sam = new Person(); sam.wife.angela = { age:24, height:18- } console.log(sam.wife); //3我的 console.log(jimmy); //3我的
這樣就能看出明顯的區別。 想一想吧,老婆能是別人的嗎?
聰明的社區 scratch their butt。 而後想到,構造函數模式和原型模式一塊兒用不久over了嗎?
我操~~~ 真聰明. 取個名字吧,混合模式~(本身編的 :)
經過上例的說明,相信你們應該能理解我所說的,原型模式 is not versatile.
所謂的混合就是將二者結合在一塊兒:
構造函數定義的是實例的屬性,而原型模式定義的是共享的屬性(prototype).
來個栗子:
function Person(name,wife){ this.name = name; this.wife = wife; } Person.prototype.myWife = function(){ console.log(this.wife); } var jimmy = new Person("jimmy",{ sheriy:{ age:19, height:180 } }); jimmy.myWife(); //sheriy var sam = new Person('sam',{ angela:{ age:20, height:190 } }) sam.myWife(); // angela
不再用擔憂本身的老婆是別人家的了。
這種方式,應該是js社區極力推崇的。可是咱們寫項目的時候,說實話,真心用不到(由於咱們的項目過小了)。因此在這裏推薦一個,我本身常用的。 字面量模式的寫法.
直接上栗子:
var login = { userName : document.querySelector('#userName'), ps: document.querySelector('#password'), loginBtn: document.querySelector('#loginBtn'), init:function(){ var _this = this; this.loginBtn.addEventListener("click",function(){ var name = _this.userName.getAttribute("value"), ps = _this.ps.getAttribute('value'); http.ajax({ url:Pathurl.login, dataType:'JSON', contentType:"application/json" }) .then(function(data){ //請求成功後的相關操做 }) },false); } } login.init();
這應該算是一個基本的寫法吧。 本人青睞於這種寫法的緣由是,他有一個入口函數,init(),並且獲取元素後,能夠重複性的使用,方便你每次添加元素的時候從新獲取(想一想個人4G內存,你們仍是不要這麼作了吧).ending~