欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

javascript框架設(shè)計(jì)之種子模塊

 更新時(shí)間:2015年06月23日 10:06:56   投稿:hebedich  
本文給大家介紹的是司徒正美的javascript框架設(shè)計(jì)的第二章種子模塊的相關(guān)內(nèi)容,算是一個(gè)小小的讀后感,小伙伴們可以參考下。

種子模塊也叫核心模塊,是框架中最先執(zhí)行的部分。即便像jQuery那樣的單文件函數(shù)庫(kù),它的內(nèi)部也分很多模塊,必然有一些模塊執(zhí)行時(shí)在最前面立即執(zhí)行,有一些模塊只有用到才執(zhí)行。有的模塊可有可無(wú),存在感比較弱,只有在特定的瀏覽器下才運(yùn)行。

種子模塊就是其中的先鋒,它里邊的方法不一定要求個(gè)個(gè)功能齊全,設(shè)計(jì)優(yōu)良,但一定要極具擴(kuò)展性,常用,穩(wěn)定。

擴(kuò)展性是指通過(guò)他們能給將其它模塊包含進(jìn)來(lái);常用是指絕大多數(shù)的模塊都能用到它們,防止做重復(fù)工作。穩(wěn)定是指在版本迭代時(shí)不輕易被新方法替代。

參照許多框架和庫(kù)的實(shí)現(xiàn),我們認(rèn)為種子模塊包含如下功能:對(duì)象擴(kuò)展,數(shù)組化,類(lèi)型判定,簡(jiǎn)單的綁定與卸載,無(wú)沖突處理,模塊的加載與domReady.本章學(xué)習(xí)的內(nèi)容以mass Framework種子模塊為范本。

https://github.com/RubyLouvre/mass-Framework

1.命名空間

種子模塊作為一個(gè)框架最開(kāi)始的部分,負(fù)責(zé)輔建全局的基礎(chǔ)設(shè)施外。jQuery就有一個(gè)很好的開(kāi)頭,使用IIFE(立即調(diào)用函數(shù)表達(dá)式).

LIFE是現(xiàn)代javascript框架里最主要的基礎(chǔ)設(shè)施,它就像細(xì)胞一樣包裹自身,防止變量污染。就像一個(gè)立足點(diǎn),這個(gè)就是命名空間,如prototype.js,mootools,它們讓你感受不到框架的存在,它的意義深刻到j(luò)avascript、DOM、BOM等整個(gè)執(zhí)行環(huán)境的每個(gè)角落,對(duì)原生的對(duì)象原型就行擴(kuò)展。由于道格拉斯(JSON作者)的極力反對(duì),新的框架都在命名空間上構(gòu)建了。

我們看怎么在javascript上模擬命名空間。javascript一切基于對(duì)象,但只有符合類(lèi)型的對(duì)象才符合要求,比如function 、RegExp、Object,不過(guò)最常用的是object和function。我們往一個(gè)對(duì)象上添加一個(gè)屬性,而這個(gè)屬性又是一個(gè)對(duì)象,這個(gè)對(duì)象我們又可以為它添加一個(gè)對(duì)象,通過(guò)這種方法,我們就可以有條不紊的構(gòu)建我們的框架。用戶(hù)想調(diào)用某個(gè)方法,就以xxx.yyy.zzz()的形式調(diào)用。

  if( typeof(Ten) === "undefined" ){
    Ten = {};
    Ten.Function = { /*略*/ }
    Ten.Array = { /*略*/ }
    Ten.Class = { /*略*/ }
    Ten.JSONP = new Ten.Class(/*略*/ )
    Ten.XHR = new Ten.Class(/*略*/ )
  }

縱觀各大類(lèi)庫(kù)的實(shí)現(xiàn),一開(kāi)始基本都是定義一個(gè)全局變量作為命名空間,然后對(duì)它進(jìn)行擴(kuò)展,如Base2的Base,Ext的Ext,jQuery的jQuery,YUI的YUI,dojo的dojo,MochiKit的mochKit。從全局變量的污染程度來(lái)看,分為兩類(lèi):

prototype.js和mootools與Base2歸為一類(lèi),Prototype的哲學(xué)是對(duì)javascript的原生對(duì)象進(jìn)行擴(kuò)展。早些年,prototype差點(diǎn)稱(chēng)為事實(shí)的標(biāo)準(zhǔn)。因此沒(méi)有考慮到與其它庫(kù)共存的問(wèn)題。基本Prototype,也發(fā)展出諸如script.aculo.us,rico,Plotr,protoChart,Script2等非常優(yōu)秀的類(lèi)庫(kù)以一大類(lèi)收費(fèi)插件。而且,有些淵源的插件幾乎都與Prototype有關(guān),比如lightBox。mootools是prototype.js的升級(jí)版,更加OO,全面復(fù)制其API。Base2則是想修復(fù)IE的bug,讓IE擁有標(biāo)準(zhǔn)瀏覽器的API,因此也把所有原生的對(duì)象污染一遍。

第二類(lèi)是jQuery,YUI,EXT這些框架,YUI和Ext就是對(duì)象嵌套對(duì)象的方式構(gòu)建的。jQuery則另辟蹊徑,它是以選擇器為導(dǎo)向的,因此它的命名空間是一個(gè)函數(shù),方便用戶(hù)將css表達(dá)器的字符串傳進(jìn)來(lái)。然后通過(guò)選擇器進(jìn)行查找,最后返回一個(gè)jQuery對(duì)象實(shí)例。

jQuery最開(kāi)始也像Prototype使用$作為它的命名空間,因此,它實(shí)現(xiàn)了很多庫(kù)的共存機(jī)制,在$和jQuery中任意切換,jQuery的多庫(kù)共存原理很簡(jiǎn)單,因此后來(lái)也成為許多小庫(kù)的標(biāo)配。首先,把命名空間保存到一個(gè)臨時(shí)變量中(注意,這時(shí)候這個(gè)對(duì)象并不是自己框架的東西,可能是prototype.js或者其他的),然后再使用個(gè)noConflict放回去。

  //jQuery1.2
  var _jQuery = window.jQury , _$ = window.$; //把可能存在同名變量先保存起來(lái)
  jQury.extend({
    noConflict : function(deep) {
      window.$ = _$; //這時(shí)再放回去
      if (deep) //補(bǔ)充 if ( deep && window.jQuery === jQuery )
        window.jQury = _jQuery;
      return jQury;
    }
  })

參考:http://zhidao.baidu.com/question/1239712776390687219.html

但jQuery的noConflict只是對(duì)單文件的類(lèi)庫(kù)框架有用,像Ext就不能復(fù)制了。因此把命名空間改名后,將Ext置為null,然后通過(guò)動(dòng)態(tài)加載的方法引入新的javascript文件中,該文件會(huì)以Ext調(diào)用,會(huì)導(dǎo)致報(bào)錯(cuò)。

2.對(duì)象擴(kuò)展

我們需要一種機(jī)制,將新功能添加到我們的命名空間上來(lái)。這方法在javascript通常稱(chēng)作extend或mixin。javascript對(duì)象在屬性描述符(Property Descriptor)沒(méi)有誕生之前,是可以隨意添加、更改、刪除其成員的,因此,擴(kuò)展一個(gè)對(duì)象非常便捷。一個(gè)簡(jiǎn)單的擴(kuò)展方法實(shí)現(xiàn)是這樣的。

  function extend (destination,source){
    for (var property in source)
      destination[property] = source[property];
    return destination;
  }

不過(guò),舊版本IE在這里有個(gè)問(wèn)題,它認(rèn)為像Object的原型方法就是不應(yīng)該被遍歷出來(lái),因此for in循環(huán)是無(wú)法遍歷valueOf、toString的屬性名。這導(dǎo)致,模擬Object.keys方法是現(xiàn)實(shí)時(shí)也遇到了這個(gè)問(wèn)題。

  Object.keys = Object.keys || function(obj){
    var a = [];
    for(a[a.length] in obj);
    return a;
  }

在不同的框架,這個(gè)方法還有不同的實(shí)現(xiàn),如Ext分別為apply與applyIf兩個(gè)方法,前者會(huì)覆蓋目標(biāo)對(duì)象的同名屬性,而后者不會(huì)。dojo允許多個(gè)對(duì)象合并在一起。jQuery還支持深拷貝。下面是mass Farmework的mix方法。支持多對(duì)象合并與選擇是否覆寫(xiě)。

  function mix(target,source){ //如果最后參數(shù)是布爾,判定是否覆蓋同名屬性
    var args = [].slice.call(arguments), i = 1, key,
      ride = typeof args[args.length - 1] == "boolean" ? args.pop() : true;
    if (args.length === 1){ //處理$.mix(hash)的情形
      target = !this.window ? this : {};
      i = 0;
    }  
    while ((source = args[i++])) {
      for (key in source){ //允許對(duì)象糅雜,用戶(hù)保證都是對(duì)象
        if (ride || !(key in target)) {
          target[key] = source[key];
        }
      }
    }
    return target;
  }

3.數(shù)組化

瀏覽器下存在很多類(lèi)數(shù)組對(duì)象,如function內(nèi)的arguments,通過(guò)document.forms、form.elements,document.links、select.options、document.getElementsByName,document.getElementsByTagName、childNodes、children等方式獲取的節(jié)點(diǎn)的結(jié)合(HTMLCollection 、NodeList)或按照某些特殊的寫(xiě)法自定義對(duì)象。

類(lèi)數(shù)組對(duì)象是一個(gè)很好的存儲(chǔ)結(jié)構(gòu)。不過(guò)功能太弱了,為了能使用純數(shù)組的那些便捷的方法,我們會(huì)在處理它們前都會(huì)做一下轉(zhuǎn)換。

通常來(lái)說(shuō),使用[].slice.call就能轉(zhuǎn)換了 ,不過(guò)功能不夠用,但在舊版本的HTMLCollection、NodeList不是Object的子類(lèi),采用如上的方法會(huì)導(dǎo)致IE執(zhí)行異常。我們看一下

jQuery:makeArray

  var makeArray = function(array) {
    var ret = [] ;
    if(array != null){
      var i = array.length;
      if(i == null || typeof array === "string" || jQuery.isFunction(array) || array.setInterval)
        ret[0] = array;
      else
        while (i)
          ret(--i) = array[i];
    }
    return ret;
  }

mass的實(shí)現(xiàn),一開(kāi)始就進(jìn)行區(qū)分,直接[].slice.call,IE的話自己動(dòng)手實(shí)現(xiàn)一個(gè)slice方法

  $.slice = window.dispatchEvent ? function(nodes,start,end){
    return [].slice.call(nodes,start,end);
  } : function (nodes,start,end){
    var ret = [],
       n = nodes.length;
    if (end === void 0 || typeof end === "number" && isFinite(end)){
      start = parseInt (start,0) || 0;
      end = end == void 0 ? n:parseInt (end,10);
      if(start < 0){
        start += n;
      }
      if (end > n) {
        end =n
      };
      if (end < 0) {
        end += n
      };
      for (var i = start; i < end; ++i){
        ret[i-start] = nodes[i];
      }
    }
    return ret;
  }

4.類(lèi)型的判定

javascript存在兩套類(lèi)型系統(tǒng),一套是基本的數(shù)據(jù)類(lèi)型,另一套是對(duì)象類(lèi)型系統(tǒng)?;緮?shù)據(jù)類(lèi)型包括6中 。分別是undefined、string、null、boolean、function、object。基本數(shù)據(jù)類(lèi)型是通過(guò)typeof來(lái)檢測(cè)的。對(duì)象類(lèi)型系統(tǒng)是以基礎(chǔ)類(lèi)型系統(tǒng)為基礎(chǔ)的,通過(guò)instanceof來(lái)檢測(cè)的。然而,javascript自帶的這兩套識(shí)別機(jī)制非常不靠譜,于是就催生了isXXX系列。就拿typeof來(lái)說(shuō),它只能粗略識(shí)別出string、number、boolearn、function、undefined、object這6種數(shù)據(jù)類(lèi)型,無(wú)法識(shí)別null,RegExpArgument等細(xì)分的對(duì)象類(lèi)型。

  typeof null // => "object"
  typeof document.childNodes //=> safari: "function"
  typeof document.creatElement('embed') //=> ff3-10 "function"
  typeof document.creatElement('object') //=> ff3-10 "function"
  typeof document.creatElement('object') //=> ff3-10 "function"
  typeof /\d/i //在實(shí)現(xiàn)了ecma262v4的瀏覽器返回"function"
  typeof window.alert //ie678 "object"
  var iframe = document.creatElement("iframe")
  document.body.appendChild(iframe)
  xArray = window.frames[window.frames.length - 1].Array;
  var arr = new xArray(1,2,3) //=>[1,2,3]
  arr instanceof Array ;// false
  isNaN("aaa") //=> true

另外,以前人們總是以document.all來(lái)判斷是否為ie,這其實(shí)是很危險(xiǎn)的,因?yàn)?,用document.all來(lái)取得頁(yè)面中所有的元素是不錯(cuò)的注意,這個(gè)方法FF,chrome打算使用很久了,不過(guò)人們都這樣判斷,就是在chrome下有這樣的鬧劇。

  typeof document.all //undefined
  document.all //HTMLAllCollection [728] (728為元素總數(shù))

在判定undefined、null、string、number、boolean、function這六個(gè)還算簡(jiǎn)單,前面兩個(gè)可以分別與void(0)、null比較,后面4個(gè)的typeof也可以滿(mǎn)足90%的情形。這樣說(shuō)是因?yàn)閟tring、number、boolean可以包裝成偽對(duì)象。

  typeof new Boolean(1); //=>"object"
  typeof new Number(1); //=>"object"
  typeof new String("aa"); //=> "object"

這些還不是最難的,難點(diǎn)在于RegExp與Array.判定RegExp的情況很少。Array則不一樣。有關(guān)isArray的實(shí)現(xiàn)不下二十種。都是因?yàn)轼喪奖嫘捅淮蚱屏?。直到prototype.js把Object.prototype.toString發(fā)掘出來(lái)。此方法是直接輸出內(nèi)部的[[Class]],絕對(duì)精準(zhǔn)。有了它,95%的陷阱被跳過(guò)了。

  function isArray(arr){
    return arr instanceof Array;
  }

  function isArray(arr){
    return !!arr && arr.constructor === Array;
  }

  function isArray(arr) { //prototype.js 1.6
    return arr != null && typeof arr === "object" && 'splice' in arr && 'join' in arr;
  }

  function isArray(arr){// Douglas Crockford(JSON作者,反對(duì)原型污染)
    return typeof arr.sort == "function"
  }

  function isArray(array){ //kriszyp
    var result = false;
    try{
      new array.constructor (Math.pow(2,32))
    } catch (e){
      result = /Array/.test(e.message)
    }
    return result;
  };

  function isArray(o){//kangax
    try{
      Array.prototype.toString.call(o);
      return true;
    } catch (e) {
    }
    return false;
  }

  function isArray(o){ //kangax
    if(o && typeof o == 'object' && typeof o.length == 'number' && isFinite(o.length))
    {
      var _origLength = o.length;
      o[o.length] = '__test__';
      var _newLength = o.length;
      o.length = _origLength;
      return _newLength == _origLength + 1;
    }
    return false
  }

至于null 、 undefined 、NaN直接這樣寫(xiě)

  function isNaN(obj) {
    return obj !== obj
  }

  function isNull(obj) {
    return obj === null;
  }

  function isUndefined(obj){
    return obj === void 0;
  }

最后要判定的是對(duì)象是window,由于ECMA是不規(guī)范的Host對(duì)象,window對(duì)象屬于host.所以也就沒(méi)有被約定。就算Object.prototype.toString也對(duì)它沒(méi)辦法

  [object Object] IE6 
  [object Object] IE7 
  [object Object] IE8
  [object Window] IE9
  [object Window] ff3.6
  [object Window] opera10
  [object DOMWindow] safari 4.04
  [object global] chrome5.0

不過(guò)根據(jù)window.window和window.setInterval去判定更加不靠譜,用一個(gè)技巧就可以完美識(shí)別ie6 ie7 ie8的window對(duì)象,其它還用toString,這個(gè)神奇的hack就是,window與document互相比較,如果順序不一樣,結(jié)果也是不一樣的!

剩下的就是一些經(jīng)典方法:

在prototype.js中,擁有isElement,isArray,isHash,isFunctoion,isString,isNumber,isDate,isUndefined。

mootools有一個(gè)typeOf判定基本類(lèi)型,instanceOf判定自定義“類(lèi)”

RightJS 有isFunction , isHash , isString , isNumber , isArray ,isElement, isNode.

Ext有比較全面的判斷,isEmpty,isArray,isDate,isObject,isSimpleObject,isPrimitive,isFunction,isNumber,isMumeric,isString,isBoolean,isElement,isTextNode,isDefined,isIterable,應(yīng)有盡有。最后,還有typeOf判斷基本類(lèi)型。

Underscore.js有isElement,isEmpty,isArray,isArgument,isObject,isFunction,isString,isNumber,isFinite,isNaN,isBoolean,isDate,isRegExp,isNull,isUndefined.

jQuery就不與其它框架一樣了,在jQuery1.4中只有isFunction,isArray,isPlainObject,isEmptyObject。isFunction,isArray用戶(hù)肯定用的較多,isPlainObject是用來(lái)判斷是否是純凈的js對(duì)象。既不是DOM,BOM對(duì)象,也不是自定義的“類(lèi)”的實(shí)例對(duì)象,制造它的目的最初是為了深拷貝,避開(kāi)像window那樣自己引用自己的對(duì)象。isEmptyObject是用于數(shù)據(jù)緩存的系統(tǒng),當(dāng)此對(duì)象為空時(shí),就可以刪除它。

  //jQuery2.0純凈數(shù)組的判定思路
  jQuery.isPlainObject = function(obj){
    //首先排除基礎(chǔ)類(lèi)型不為Object的類(lèi)型,然后是DOM節(jié)點(diǎn)與window對(duì)象
    if(jQuery.type(obj) !== "object" || object.nodeType || jQuery.isWindow(obj)){
      return false;
    }

    //然后回溯它的最近的原型對(duì)象是否有isPrototypeOf.
    //舊版本的IE一些原生的對(duì)象沒(méi)有暴露constructor、prototype。因此在這里過(guò)濾掉
    try{
      if (obj.constructor && !hasOwn.call(obj.constructor.prototype,"isPrototypeOf")){
        return false;
      }
    } case(e) {
      return false;
    }
    return true;
  }

avalon.mobile中有一個(gè)更精簡(jiǎn)的版本,只支持最新的瀏覽器,可以大膽的使用ecma262v5新API

  avalon.isPlainObject = function(obj){
    return obj && typeof obj === "object" && Object.getPrototypeOf(obj) === Object.prototype
  }

isArrayLike也是一個(gè)常用的方法,但是判定一個(gè)類(lèi)數(shù)組太難了,唯一的識(shí)別方法就是判斷有一個(gè)大于0或等于0的length屬性,此外,還有一些共識(shí),如window與函數(shù)和元素節(jié)點(diǎn),如(form元素),不算類(lèi)數(shù)組,雖然它們都滿(mǎn)足前面的條件。因此,至今jQuery都沒(méi)有把它暴露出來(lái)。

  //jQuery2.0
  function isArrayLike(obj){
    var length = obj.length , type = jQuery.type(obj);
    if (jQuery.isWindow(obj)){
      return false;
    }
    if (obj.nodeType === 1 && length){
      return true
    }
    return type === "array" || type !== "function" && (length === 0 || typeof length === "number" && length > 0 && (length -1) in obj);
  }

  // avalonjs
  function isArrayLike (obj) {
    if (obj && typeof obj === "object"){
      var n = obj.length
      if (+n === n && !( n % 1) && n >= 0){//檢測(cè)length是否為非負(fù)整數(shù)
        try{
          if ({}.prototypeIsEnumerable.call(obj,'length') === false){
          return Array.isArray(obj) || /^\s?function/.test(obj.item || obj.callee)
         }
        return true;
       } catch (e) { //IE的NodeList直接報(bào)錯(cuò)
        return true;
       }
      }
    }
  return false
  }

在Prototype.js1.3版本中的研究成果(Object.prototype.toString.call)就應(yīng)用于jQuery,在jQuery1.2中,判斷一個(gè)變量是否為函數(shù)非常復(fù)雜。

復(fù)制代碼 代碼如下:

    isFunction : function(fn){
        return !!fn && typeof fn != "string" && !fn.nodeName && fn.constructor != Array && /^[\s[]?function/.test(fn + "");
    }

jQuery1.43中引入isWindow來(lái)處理makeArray中對(duì)window的判定,引入isNaN用于確保樣式賦值的安全。同時(shí)引入type代替typeof關(guān)鍵字,用于獲取基本數(shù)據(jù)的基本類(lèi)型。

  class2type = {};
  jQuery.each("Boolean Number String Function Array Date RegExpObject".split(" "),function( i , name ){
    class2type[ "[object " + name + "]" ] = name.toLowerCase();
  });

  jQuery.type = function(obj){
    return obj == null ? String(obj) : class2type[toString.call(obj)] || "object";
  }

jQuery1.7中添加isNumeric代替isNaN。這是個(gè)不同于其它框架的isNumber,它可以是個(gè)字符串,只要外觀上像數(shù)字就可以了。但jQuery1.7還做了一個(gè)違背之前提到穩(wěn)定性的事情。冒然去掉jQuery.isNaN,因此,基于舊版jQuery的有大批插件失效。

  //jQuery.1.43-1.64
  jQuery.isNaN = function ( obj ) {
    return obj == null || !rdigit.test( obj ) || isNaN( obj );
  }

  //jQuery1.7就是isNaN的去反版
  jQuery.isNumeric = function ( obj ) {
    return obj != null && rdigit.test( obj ) && !isNaN( obj );
  }

  //jQuery.1.71 - 1.72
  jQuery.isNumeric = function ( obj ) {
    return !isNaN( parseFloat(obj) ) && isFinite( obj );
  }

  //jQuery2.1
  jQuery.isMumeric = function( obj ) {
    return obj - parseFloat(obj) >= 0;
  }

massFarmeWork的思路與jQuery一致,盡量減少isXXX系列的代碼,把is Window,isNaN,nodeName等方法做了整合。代碼較長(zhǎng),既可以獲取類(lèi)型,也可以傳入第二參數(shù)進(jìn)行類(lèi)型比較。

  var class2type = {
    "[objectHTMLDocument]" : "Document",
    "[objectHTMLCollection]" : "NodeList",
    "[objectStaticNodeList]" : "NodeList",
    "[objectIXMLDOMNodeList]" : "NodeList",
    "[objectDOMWindow]" : "window",
    "[object global]" : "window",
    "Null" : "Null",
    "undefined" : "undefined"
  },
  toString = class2type.toString;
  "Boolean,Number,String,Function,Array,Date,RegExp,Window,Document,Arguments,NodeList".replace($.rword,function( name ) {
    class2type[ "[object" + name + "]" ] = name;
  });

  //class2type這個(gè)映射幾乎把常用的判定對(duì)象一網(wǎng)打盡
  mass.type = function( obj , str ){
    var result = class2type[ (obj == null || obj !== obj) ? obj : toString.call(obj) ] || obj.nodeName || "#";
    if(result.charAt(0) === "#") { //兼容舊版瀏覽器的個(gè)別情況,如window.opera
      //利用IE678 window === document為true,document === window為false
      if( obj == obj.document && obj.document != obj ) {
        result = "window"; //返回構(gòu)造器名稱(chēng)
      } else if ( obj.nodeType === 9 ) {
        result = "Document";
      } else if ( obj.callee) {
        result = "Arguments";
      } else if ( isFinite(obj.length) && obj.item ) {
        result = "NodeList" //處理節(jié)點(diǎn)集合
      } else {
        result = toString.call(obj).slice(8,-1);
      }
    }
    if(str){
      result str === result;
    }
    return result;
  }

然后type方法就十分輕松了,用toSring.call(obj)得出值的左鍵,直接從映射中取得。IE678,我們才費(fèi)一些周折處理window,document,argument,nodeList等對(duì)象。

百度的七巧板基于實(shí)用主義,判定也十分嚴(yán)謹(jǐn)。與EXT一樣,能想到的寫(xiě)上,并且判定十分嚴(yán)謹(jǐn)。

目前版本2.0.2.5 http://tangram.baidu.com/api#baidu.type()

  baidu.isDate = function( unknow ) {
  return baidu.type(unknow) == "date" && unknow.toString() != 'Invalid Date' && !isNaN(unknow);
  };
  baidu.isNumber = function( unknow ) {
  return baidu.type(unknow) == "number" && isFinite( unknow );
  };

 5.主流框架的引入機(jī)制-domReady

domReady其實(shí)是一種名為"DOMContentLoaded"事件的別稱(chēng),不過(guò)由于框架的需要,它與真正的DOMContentLoaded有一點(diǎn)區(qū)別,在很多新手和舊的書(shū)中,很多人將其寫(xiě)在window.onload回調(diào)中,防止dom樹(shù)還沒(méi)有建完就開(kāi)始對(duì)節(jié)點(diǎn)操作。而對(duì)于框架來(lái)說(shuō),越早越介入dom就越好,如要進(jìn)行特征偵測(cè)之類(lèi)的。domready還可以滿(mǎn)足用戶(hù)提前綁定事件需求,因?yàn)橛袝r(shí)頁(yè)面圖片過(guò)多等,window.onload事件遲遲不能觸發(fā),這時(shí)用戶(hù)操作都沒(méi)有效果,因此,主流的框架都引入了domReady機(jī)制,并且費(fèi)了很大周折才兼容所有瀏覽器。具體的策略如下:

對(duì)于支持DOMContentLoaded事件使用DOMcontentLoaded事件
舊版本IE使用Diego perini發(fā)現(xiàn)的著名Hack

  //by Diego Perini 2007.10.5
   function IEContentLoaded (w, fn) {
   var d = w.document, done = false,
   // 只執(zhí)行一次用戶(hù)的回調(diào)函數(shù)init()
   init = function () {
    if (!done) {
      done = true;
      fn();
    }
   };
  (function () {
    try {
      // DOM樹(shù)未創(chuàng)建完之前調(diào)用doScroll會(huì)拋出錯(cuò)誤
      d.documentElement.doScroll('left');
    } catch (e) {
      //延遲再試一次~
      setTimeout(arguments.callee, 50);
      return;
    }
    // 沒(méi)有錯(cuò)誤就表示DOM樹(shù)創(chuàng)建完畢,然后立馬執(zhí)行用戶(hù)回調(diào)
    init();
         })();
  //監(jiān)聽(tīng)document的加載狀態(tài)
  d.onreadystatechange = function() {
    // 如果用戶(hù)是在domReady之后綁定的函數(shù),就立馬執(zhí)行
    if (d.readyState == 'complete') {
      d.onreadystatechange = null;
      init();
    }
       };
  }

此外,IE還可以通過(guò)script defer hack進(jìn)行判定

   document.write("<script id=__ie_onload defer src=//0 mce_src=http://0></scr"+"ipt>"); 
    script = document.getElementById("__ie_onload"); 
    script.onreadystatechange = function() { //IE即使是死鏈也能觸發(fā)事件 
          if (this.readyState == "complete") 
    init(); // 指定了defer的script在dom樹(shù)建完才觸發(fā)
  }; 

不過(guò)還有個(gè)問(wèn)題,如果我們的種子模塊是動(dòng)態(tài)加載的,在它插入dom樹(shù)時(shí),DOM樹(shù)是否已經(jīng)建完呢?這該怎么觸發(fā)ready回調(diào)?jQuery的方案是,連onload也監(jiān)聽(tīng)了 ,但如果連onload也沒(méi)趕上,就判定document.readyState等于complete。(完美)可惜ff3.6之前沒(méi)有這屬性,看mass的方案

  var readyList = [];
  mess.ready = function( fn ) {
    if ( readyList ) {
      fn.push( fn );
    } else {
      fn();
    }
  }
  var readyFn ,ready = W3C ? "DOMContentLoaded" : "readyStatechange";
  function fireReady() {
    for (var i = 0 , fn; fn = readyList[i++]) {
      fn();
    }
    readyList = null;
    fireReady = $.noop; //惰性函數(shù),防止IE9調(diào)用_checkDeps
  }
  function doScrollCheck() {
    try { //IE下通過(guò)doScrollCheck檢測(cè)DOM樹(shù)是否建設(shè)完
      html.doScroll("left");
      fireReady();
    } catch (e){
      setTimeout(doScrollCheck);
    }
  }

  //FF3.6前,沒(méi)有readyState屬性
  if (!document.readyState){
    var readyState = document.readyState = document.body ? "complete" : "loading";
    if (document.readyState === "complete") {
      fireReady(); //如果在domReay之外加載
    } else {
      $.bind(document,ready,readyFn = function(){
        if(W3C || document.readyState === "complete") {
          fireReady();
          if(readyState){ //IE下不能該項(xiàng)document.readyState
            document.readyState = "complete";
          }
        }
      });
      if (html.doScroll){
        try {//如果跨域就報(bào)錯(cuò),證明有兩個(gè)窗口
          if (self.eval === parent.eval) {
            doScrollCheck();
          }
        } catch (e) {
          doScrollCheck();
        }
      }
    }

  }

6.無(wú)沖突處理

無(wú)沖突處理也叫多庫(kù)共存,$是這個(gè)重要的函數(shù)名,以至于大家都愛(ài)拿它來(lái)做自己的命名空間,當(dāng)jQuery開(kāi)始發(fā)展時(shí),Prototype是主流,jQuery發(fā)明了noConflict函數(shù)

  var window = this,
  undefined,
  _jQuery = window.jQuery,
  _$ = window.$,
  //將window存入閉包中的同名變量,方便內(nèi)部函數(shù)調(diào)用windows不用太麻煩查找它。
  //_jQuery與_$用于以后重寫(xiě)
  jQuery = window.jQuery = window.$ = function(selector, context){
    //用于返回一個(gè)jQuery對(duì)象
    return new jQuery.fn.init(selector,context);
  }

  jQuery.extend({
    noConflict : function(deep) {
      //引入jQuery類(lèi)庫(kù)后,閉包外邊的window.$與window.jQuery都儲(chǔ)存著一個(gè)函數(shù)
      //它是用來(lái)生成jQuery對(duì)象或在domReady后執(zhí)行里面的函數(shù)
      //回顧最上面的代碼,在還沒(méi)有把function賦值給它們時(shí),_jQuery和_$已經(jīng)被賦值了,因此,它們兩的值必然是undefined
      //因此,這種放棄控制權(quán)的技術(shù)很簡(jiǎn)單,就是用undefined把window.$里邊jQuery函數(shù)清除掉。
      //這時(shí),prototype或mootools的$就被拿走了
      window.$ = _$; //相當(dāng)于window.$ = undefined,如果你有一個(gè)叫jQuery的庫(kù),也能大方的過(guò)渡出去。
      //這時(shí),需要給noConflict添加一個(gè)布爾值,true
    
    if (deep)
      //但我們必須使用一個(gè)東西接納jQuery與jQuey的入口函數(shù)
      //閉包里邊的東西除非被window等宿主引用,否則是不可見(jiàn)的
      //因此,我們把閉包里的jQuery return出去,外面用一個(gè)變量接納就可以
      window.jQuery = _jQuery; //相當(dāng)window.jQuery = undefined
    return jQuery;
    }
  })

使用時(shí),先引入別人的庫(kù),然后引入jQuery,使用調(diào)用$.noConflict()進(jìn)行改名,這樣就不影響別人的$運(yùn)行了。

mass的操作方式是在script標(biāo)簽上定義一個(gè)nick屬性,那么釋放出來(lái)的命名空間就是你的那個(gè)屬性值。里面實(shí)現(xiàn)了類(lèi)似jQuery的機(jī)制。

<script nike="aaa" src="mass.js"></script>
<script>
  aaa.log("xxxxxx")
</script>

以上所述就是本文的全部?jī)?nèi)容了,希望大家能夠喜歡。

相關(guān)文章

最新評(píng)論