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

實例詳解jQuery的無new構建

 更新時間:2016年08月02日 15:12:28   投稿:daisy  
這篇文章運用實例介紹了jQuery的無new構建,小編感覺介紹的非常詳細,具有參考借鑒價值,感興趣的朋友一起學習吧。

jQuery的無new構建

jQuery框架的核心就是從HTML文檔中匹配元素并對其執(zhí)行操作、

回想一下使用 jQuery 的時候,實例化一個 jQuery 對象的方法:

// 無 new 構造
$('#test').text('Test');
 
// 當然也可以使用 new
var test = new $('#test');
test.text('Test');

大部分人使用 jQuery 的時候都是使用第一種無 new 的構造方式,直接 $('') 進行構造,這也是 jQuery 十分便捷的一個地方。

當我們使用第一種無 new 構造方式的時候,其本質就是相當于 new jQuery(),那么在 jQuery 內部是如何實現(xiàn)的呢?看看:

(function(window, undefined) {
  var
  // ...
  jQuery = function(selector, context) {
    // The jQuery object is actually just the init constructor 'enhanced'
    return new jQuery.fn.init(selector, context, rootjQuery);
  },
 
  jQuery.fn = jQuery.prototype = {
    init: function(selector, context, rootjQuery) {
      // ...
    }
  }
  jQuery.fn.init.prototype = jQuery.fn;
})(window);

 沒看懂?沒關系,我們一步一步分析。

函數(shù)表達式和函數(shù)聲明

在ECMAScript中,創(chuàng)建函數(shù)的最常用的兩個方法是函數(shù)表達式和函數(shù)聲明,兩者期間的區(qū)別是有點暈,因為ECMA規(guī)范只明確了一點:函數(shù)聲明必須帶有標示符(Identifier)(就是大家常說的函數(shù)名稱),而函數(shù)表達式則可以省略這個標示符: 

   //函數(shù)聲明:
  function 函數(shù)名稱 (參數(shù):可選){ 函數(shù)體 }
  //函數(shù)表達式:
  function 函數(shù)名稱(可選)(參數(shù):可選){ 函數(shù)體 }

所以,可以看出,如果不聲明函數(shù)名稱,它肯定是表達式,可如果聲明了函數(shù)名稱的話,如何判斷是函數(shù)聲明還是函數(shù)表達式呢?

ECMAScript是通過上下文來區(qū)分的,如果function foo(){}是作為賦值表達式的一部分的話,那它就是一個函數(shù)表達式,

如果function foo(){}被包含在一個函數(shù)體內,或者位于程序的最頂部的話,那它就是一個函數(shù)聲明。

 function foo(){} // 聲明,因為它是程序的一部分
 var bar = function foo(){}; // 表達式,因為它是賦值表達式的一部分
 new function bar(){}; // 表達式,因為它是new表達式
 (function(){
  function bar(){} // 聲明,因為它是函數(shù)體的一部分
 })();

還有一種函數(shù)表達式不太常見,就是被括號括住的(function foo(){}),他是表達式的原因是因為括號 ()是一個分組操作符,它的內部只能包含表達式

 再來看jQuery源碼:

(function(window, undefined) {
  /...
})(window)

可以將上面的代碼結構分成兩部分:(function(){window, undefined}) (window) ,

第1個()是一個表達式,而這個表達式本身是一個匿名函數(shù),

所以在這個表達式后面加(window)就表示執(zhí)行這個匿名函數(shù)并傳入?yún)?shù)window。

原型 prototype

認識一下什么是原型?

在JavaScript中,原型也是一個對象,通過原型可以實現(xiàn)對象的屬性繼承,JavaScript的對象中都包含了一個" [[Prototype]]"內部屬性,這個屬性所對應的就是該對象的原型。

對于"prototype"和"__proto__"這兩個屬性有的時候可能會弄混,"Person.prototype"和"Person.__proto__"是完全不同的。

在這里對"prototype"和"__proto__"進行簡單的介紹:

    1.對于所有的對象,都有__proto__屬性,這個屬性對應該對象的原型

    2.對于函數(shù)對象,除了__proto__屬性之外,還有prototype屬性,當一個函數(shù)被用作構造函數(shù)來創(chuàng)建實例時,該函數(shù)的prototype屬性值將被作為原型賦值給所有對象實例(也就是設置實例的__proto__屬性)

function Person(name, age){
  this.name = name;
  this.age = age;
}
Person.prototype.getInfo = function(){
  console.log(this.name + " is " + this.age + " years old");
};
//調用
var will = new Person("Will", 28);
will.getInfo();//"Will is 28 years old"

閉包

閉包的定義:

當一個內部函數(shù)被其外部函數(shù)之外的變量引用時,就形成了一個閉包。

閉包的作用:

在了解閉包的作用之前,我們先了解一下 javascript中的GC機制:

在javascript中,如果一個對象不再被引用,那么這個對象就會被GC回收,否則這個對象一直會保存在內存中。

在上述例子中,B定義在A中,因此B依賴于A,而外部變量 c 又引用了B, 所以A間接的被 c 引用,

也就是說,A不會被GC回收,會一直保存在內存中。為了證明我們的推理,看如下例子:

function A(){
  var count = 0;
  function B(){
    count ++;
    console.log(count);
  }
  return B;
}
var c = A();
c();// 1
c();// 2
c();// 3

count是A中的一個變量,它的值在B中被改變,函數(shù)B每執(zhí)行一次,count的值就在原來的基礎上累加1。因此,A中的count一直保存在內存中。

這就是閉包的作用,有時候我們需要一個模塊中定義這樣一個變量:希望這個變量一直保存在內存中但又不會“污染”全局的變量,這個時候,我們就可以用閉包來定義這個模塊

在看jQuery源碼:

(function(window, undefined) {
  var
  // ...
  jQuery = function(selector, context) {
    // The jQuery object is actually just the init constructor 'enhanced'
    return new jQuery.fn.init(selector, context, rootjQuery);
  },
  jQuery.fn = jQuery.prototype = {
    init: function(selector, context, rootjQuery) {
      // ...
    }
  }
  jQuery.fn.init.prototype = jQuery.fn;
})(window);
 

我們知道了 什么是閉包:當一個內部函數(shù)被其外部函數(shù)之外的變量引用時,就形成了一個閉包。

jQuery.fn的init 函數(shù)被jQuery 的構造函數(shù)調用了,這里形成了一個閉包。
構造函數(shù)及調用代碼:

// ...
  jQuery = function(selector, context) {
    // The jQuery object is actually just the init constructor 'enhanced'
    return new jQuery.fn.init(selector, context, rootjQuery);
  },

問題關鍵來了。

如何實現(xiàn)無new構建

JavaScript是函數(shù)式語言,函數(shù)可以實現(xiàn)類,類就是面向對象編程中最基本的概念

var aQuery = function(selector, context) {
    //構造函數(shù)
}
aQuery.prototype = {
  //原型
  name:function(){},
  age:function(){}
}
var a = new aQuery();
a.name();
 

這是常規(guī)的使用方法,顯而易見jQuery不是這樣玩的

要實現(xiàn)這樣,那么jQuery就要看成一個類,那么$()應該是返回類的實例才對

按照jQuery的抒寫方式

$().ready() 
$().noConflict()

要實現(xiàn)這樣,那么jQuery就要看成一個類,那么$()應該是返回類的實例才對

所以把代碼改一下:

var aQuery = function(selector, context) {
    return new aQuery();
}
aQuery.prototype = {
  name:function(){},
  age:function(){}
}

通過new aQuery(),雖然返回的是一個實例,但是也能看出很明顯的問題,死循環(huán)了!

那么如何返回一個正確的實例?

在javascript中實例this只跟原型有關系

那么可以把jQuery類當作一個工廠方法來創(chuàng)建實例,把這個方法放到aQuery.prototye原型中

var aQuery = function(selector, context) {
    return aQuery.prototype.init(selector);
}
aQuery.prototype = {
  init:function(selector){
    return this;
  }
  name:function(){},
  age:function(){}
}

當執(zhí)行aQuery() 返回的實例:

很明顯aQuery()返回的是aQuery類的實例,那么在init中的this其實也是指向的aQuery類的實例

問題來了init的this指向的是aQuery類,如果把init函數(shù)也當作一個構造器,那么內部的this要如何處理?

var aQuery = function(selector, context) {
    return aQuery.prototype.init(selector);
}
aQuery.prototype = {
  init: function(selector) {
    this.age = 18
    return this;
  },
  name: function() {},
  age: 20
}
aQuery().age //18

 因為this只是指向aQuery類的,所以aQueryage屬性是可以被修改的。

這樣看似沒有問題,其實問題很大的

為什么是new jQuery.fn.init?

看如下代碼:

var aQuery = function(selector, context) {
    return aQuery.prototype.init(selector);
}
aQuery.prototype = {
  init: function(selector) {
    if(selector=="a")
      this.age = 18
    return this;
  },
  name: function() {},
  age: 20
}
aQuery("a").age //18
aQuery("b").age //18
 

當我調用 傳入"a"的時候,修改age=18,及aQuery("a").age 的值為18

但是當我  傳入"b"的時候 并沒又修改 age的值,我也希望得到默認age的值20,但是aQuery("b").age 的值為18.

因為在 調用aQuery("a").age 的時候age被修改了。

這樣的情況下就出錯了,所以需要設計出獨立的作用域才行。

jQuery框架分隔作用域的處理

jQuery = function( selector, context ) {
    // The jQuery object is actually just the init constructor 'enhanced'
    return new jQuery.fn.init( selector, context, rootjQuery );
  },

很明顯通過實例init函數(shù),每次都構建新的init實例對象,來分隔this,避免交互混淆

我們修改一下代碼:

var aQuery = function(selector, context) {
    return new aQuery.prototype.init(selector);
}
aQuery.prototype = {
  init: function(selector) {
    if(selector=="a")
      this.age = 18
    return this;
  },
  name: function() {},
  age: 20
}
aQuery("a").age //18
aQuery("b").age //undefined
aQuery("a").name() //Uncaught TypeError: Object [object Object] has no method 'name' 

又出現(xiàn)一個新的問題,

age  :undefined,

name() :拋出錯誤,無法找到這個方法,所以很明顯new的init跟jquery類的this分離了

怎么訪問jQuery類原型上的屬性與方法?

     做到既能隔離作用域還能使用jQuery原型對象的作用域呢,還能在返回實例中訪問jQuery的原型對象?

實現(xiàn)的關鍵點

// Give the init function the jQuery prototype for later instantiation
jQuery.fn.init.prototype = jQuery.fn;

我們再改一下:

var aQuery = function(selector, context) {
    return new aQuery.prototype.init(selector);
}
aQuery.prototype = {
  init: function(selector) {
    if(selector=="a")
      this.age = 18
    return this;
  },
  name: function() {
     return age;
  },
  age: 20
}
aQuery.prototype.init.prototype = aQuery.prototype; 

aQuery("a").age //18
aQuery("b").age //20
aQuery("a").name()  //20

最后在看一下jQuery源碼:

(function(window, undefined) {
  var
  // ...
  jQuery = function(selector, context) {
    // The jQuery object is actually just the init constructor 'enhanced'
    return new jQuery.fn.init(selector, context, rootjQuery);
  },
  jQuery.fn = jQuery.prototype = {
    init: function(selector, context, rootjQuery) {
      // ...
    }
  }
  jQuery.fn.init.prototype = jQuery.fn;
})(window);

是不是明白了?

哈哈哈~~~

在簡單說兩句:

大部分人初看 jQuery.fn.init.prototype = jQuery.fn 這一句都會被卡主,很是不解。但是這句真的算是 jQuery 的絕妙之處。理解這幾句很重要,分點解析一下:

1)首先要明確,使用 $('xxx') 這種實例化方式,其內部調用的是 return new jQuery.fn.init(selector, context, rootjQuery) 這一句話,也就是構造實例是交給了 jQuery.fn.init() 方法取完成。

2)將 jQuery.fn.init 的 prototype 屬性設置為 jQuery.fn,那么使用 new jQuery.fn.init() 生成的對象的原型對象就是 jQuery.fn ,所以掛載到 jQuery.fn 上面的函數(shù)就相當于掛載到 jQuery.fn.init() 生成的 jQuery 對象上,所有使用 new jQuery.fn.init() 生成的對象也能夠訪問到 jQuery.fn 上的所有原型方法。

3)也就是實例化方法存在這么一個關系鏈 

    1.jQuery.fn.init.prototype = jQuery.fn = jQuery.prototype ;

    2.new jQuery.fn.init() 相當于 new jQuery() ;

    3.jQuery() 返回的是 new jQuery.fn.init(),而 var obj = new jQuery(),所以這 2 者是相當?shù)?,所以我們可以無 new 實例化 jQuery 對象。

總結

以上就是jQuery的無new構建的全部內容,希望本文對大家學習jQuery有所幫助。也請大家繼續(xù)支持腳本之家。

您可能感興趣的文章:

相關文章

  • jQuery中使用each處理json數(shù)據(jù)

    jQuery中使用each處理json數(shù)據(jù)

    這篇文章主要介紹了jQuery中使用each處理json數(shù)據(jù),非常簡單實用,需要的朋友可以參考下
    2015-04-04
  • 教你用jquery實現(xiàn)iframe自適應高度

    教你用jquery實現(xiàn)iframe自適應高度

    iframe因為能和網(wǎng)頁無縫的結合從而不刷新頁面的情況下更新頁面的部分數(shù)據(jù)成為可能,可是 iframe的大小卻不像層那樣可以“伸縮自如”,所以帶來了使用上的麻煩,給iframe設置高度的時候多了也不好,少了更是不行,今天我們就來分享2種使用jquery實現(xiàn)iframe自適應高度的代碼
    2014-06-06
  • JQuery實現(xiàn)防止退格鍵返回的方法

    JQuery實現(xiàn)防止退格鍵返回的方法

    這篇文章主要介紹了JQuery實現(xiàn)防止退格鍵返回的方法,實例分析了jQuery實現(xiàn)使Backspace不可用而瀏覽器中Backspace仍可用的方法,非常具有實用價值,需要的朋友可以參考下
    2015-02-02
  • JQuery 圖片滾動輪播示例代碼

    JQuery 圖片滾動輪播示例代碼

    這篇文章主要介紹了JQuery實現(xiàn)圖片滾動輪播,需要的朋友可以參考下
    2014-03-03
  • jquery拖拽效果完整實例(附demo源碼下載)

    jquery拖拽效果完整實例(附demo源碼下載)

    這篇文章主要介紹了jquery拖拽效果實現(xiàn)方法,詳細介紹了jQuery實現(xiàn)拖拽功能的具體步驟與相關技巧,并附代碼了demo源碼供讀者下載參考,需要的朋友可以參考下
    2016-01-01
  • jquery中toggle函數(shù)交替使用問題

    jquery中toggle函數(shù)交替使用問題

    jQuery 的toggle()函數(shù)使用show()或hide()函數(shù)來切換HTML元素的可見狀態(tài)。今天我們來探討下jquery中toggle函數(shù)交替使用問題
    2015-06-06
  • 基于jQuery實現(xiàn)的水平和垂直居中的div窗口

    基于jQuery實現(xiàn)的水平和垂直居中的div窗口

    在建立網(wǎng)頁布局的時候,我們經常會面臨一個問題,就是讓一個div實現(xiàn)水平和垂直居中,雖然好幾種方式實現(xiàn),但是今天介紹時我最喜歡的方法,通過css和jQuery實現(xiàn)。
    2011-08-08
  • Jquery 學習筆記(二)

    Jquery 學習筆記(二)

    從最開始看到Jquery這樣的選擇器就讓我想起了CSS的選擇器,簡直是同出一轍啊,CSS的選擇器語法個人覺得相當?shù)慕浀?,那么Jquery借鑒CSS也就沒有多少疑問了。
    2009-10-10
  • jquery中ajax跨域方法實例分析

    jquery中ajax跨域方法實例分析

    這篇文章主要介紹了jquery中ajax跨域方法,結合實例分析了jQuery中使用getJSON及$.ajax實現(xiàn)ajax跨域的技巧,需要的朋友可以參考下
    2015-12-12
  • jQuery修改CSS偽元素屬性的方法

    jQuery修改CSS偽元素屬性的方法

    CSS偽元素不是DOM元素,因此你無法直接選擇到它們。下面與大家分享兩種不錯的修改方法,需要的朋友可以參考下
    2014-07-07

最新評論