<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                合規國際互聯網加速 OSASE為企業客戶提供高速穩定SD-WAN國際加速解決方案。 廣告
                [TOC] ## 簡介 ### 對象和面向對象編程 “面向對象編程”(Object Oriented Programming,縮寫為OOP)是目前主流的編程范式。它的核心思想是將真實世界中各種復雜的關系,抽象為一個個對象,然后由對象之間的分工與合作,完成對真實世界的模擬。 傳統的計算機程序由一系列函數或一系列指令組成,而面向對象編程的程序由一系列對象組成。每一個對象都是功能中心,具有明確分工,可以完成接受信息、處理數據、發出信息等任務。因此,面向對象編程具有靈活性、代碼的可重用性、模塊性等特點,容易維護和開發,非常適合多人合作的大型軟件項目。 那么,“對象”(object)到底是什么? 我們從兩個層次來理解。 (1)“對象”是單個實物的抽象。 一本書、一輛汽車、一個人都可以是“對象”,一個數據庫、一張網頁、一個與遠程服務器的連接也可以是“對象”。當實物被抽象成“對象”,實物之間的關系就變成了“對象”之間的關系,從而就可以模擬現實情況,針對“對象”進行編程。 (2)“對象”是一個容器,封裝了“屬性”(property)和“方法”(method)。 所謂“屬性”,就是對象的狀態;所謂“方法”,就是對象的行為(完成某種任務)。比如,我們可以把動物抽象為animal對象,“屬性”記錄具體是那一種動物,“方法”表示動物的某種行為(奔跑、捕獵、休息等等)。 雖然不同于傳統的面向對象編程語言,但是JavaScript具有很強的面向對象編程能力。本章介紹JavaScript如何進行“面向對象編程”。 ### 構造函數 “面向對象編程”的第一步,就是要生成對象。 前面說過,“對象”是單個實物的抽象。所以,通常需要一個模板,表示某一類實物的共同特征,然后“對象”根據這個模板生成。 典型的面向對象編程語言(比如C++和Java),存在“類”(class)這樣一個概念。所謂“類”就是對象的模板,對象就是“類”的實例。JavaScript語言沒有“類”,而改用構造函數(constructor)作為對象的模板。 所謂“構造函數”,就是專門用來生成“對象”的函數。它提供模板,作為對象的基本結構。一個構造函數,可以生成多個對象,這些對象都有相同的結構。 構造函數是一個正常的函數,但是它的特征和用法與普通函數不一樣。下面就是一個構造函數: ~~~ var Vehicle = function() { this.price = 1000; }; ~~~ 上面代碼中,Vehicle就是構造函數,它提供模板,用來生成車輛對象。 構造函數的最大特點就是,函數體內部使用了this關鍵字,代表了所要生成的對象實例。生成對象的時候,必需用new命令,調用Vehicle函數。 ### new命令 new命令的作用,就是執行構造函數,返回一個實例對象。 ~~~ var Vehicle = function (){ this.price = 1000; }; var v = new Vehicle(); v.price // 1000 ~~~ 上面代碼通過new命令,讓構造函數Vehicle生成一個實例對象,保存在變量v中。這個新生成的實例對象,從構造函數Vehicle繼承了price屬性。在new命令執行時,構造函數內部的this,就代表了新生成的實例對象,this.price表示實例對象有一個price屬性,它的值是1000。 使用new命令時,根據需要,構造函數也可以接受參數。 ~~~ var Vehicle = function (p){ this.price = p; }; var v = new Vehicle(500); ~~~ new命令本身就可以執行構造函數,所以后面的構造函數可以帶括號,也可以不帶括號。下面兩行代碼是等價的。 ~~~ var v = new Vehicle(); var v = new Vehicle; ~~~ 一個很自然的問題是,如果忘了使用new命令,直接調用構造函數會發生什么事? 這種情況下,構造函數就變成了普通函數,并不會生成實例對象。而且由于下面會說到的原因,this這時代表全局對象,將造成一些意想不到的結果。 ~~~ var Vehicle = function (){ this.price = 1000; }; var v = Vehicle(); v.price // Uncaught TypeError: Cannot read property 'price' of undefined price // 1000 ~~~ 上面代碼中,調用Vehicle構造函數時,忘了加上new命令。結果,price屬性變成了全局變量,而變量v變成了undefined。 因此,應該非常小心,避免出現不使用new命令、直接調用構造函數的情況。為了保證構造函數必須與new命令一起使用,一個解決辦法是,在構造函數內部使用嚴格模式,即第一行加上`use strict`。 ~~~ function Fubar(foo, bar){ "use strict"; this._foo = foo; this._bar = bar; } Fubar() // TypeError: Cannot set property '_foo' of undefined ~~~ 上面代碼的Fubar為構造函數,use strict命令保證了該函數在嚴格模式下運行。由于在嚴格模式中,函數內部的this不能指向全局對象,默認等于undefined,導致不加new調用會報錯(JavaScript不允許對undefined添加屬性)。 另一個解決辦法,是在構造函數內部判斷是否使用new命令,如果發現沒有使用,則直接返回一個實例對象。 ~~~ function Fubar(foo, bar){ if (!(this instanceof Fubar)) { return new Fubar(foo, bar); } this._foo = foo; this._bar = bar; } Fubar(1, 2)._foo // 1 (new Fubar(1, 2))._foo // 1 ~~~ 上面代碼中的構造函數,不管加不加new命令,都會得到同樣的結果。 ### new命令的原理 使用new命令時,它后面的函數調用就不是正常的調用,而是被new命令控制了。內部的流程是,先創造一個空對象,作為上下文對象,賦值給函數內部的this關鍵字。也就是說,this指的是一個新生成的空對象,所有針對this的操作,都會發生在這個空對象上。 構造函數之所以叫“構造函數”,就是說這個函數的目的,就是操作上下文對象(即this對象),將其“構造”為需要的樣子。如果構造函數的return語句返回的是對象,new命令會返回return語句指定的對象;否則,就會不管return語句,返回構造后的上下文對象。 ~~~ var Vehicle = function (){ this.price = 1000; return 1000; }; (new Vehicle()) === 1000 // false ~~~ 上面代碼中,Vehicle是一個構造函數,它的return語句返回一個數值。這時,new命令就會忽略這個return語句,返回“構造”后的this對象。 但是,如果return語句返回的是一個跟this無關的新對象,new命令會返回這個新對象,而不是this對象。這一點需要特別引起注意。 ~~~ var Vehicle = function (){ this.price = 1000; return { price: 2000 }; }; (new Vehicle()).price // 2000 ~~~ 上面代碼中,構造函數Vehicle的return語句,返回的是一個新對象。new命令會返回這個對象,而不是this對象。 new命令簡化的內部流程,可以用下面的代碼表示。 ~~~ function _new(/* constructor, param, ... */) { var args = [].slice.call(arguments); var constructor = args.shift(); var context = Object.create(constructor.prototype); var result = constructor.apply(context, args); return (typeof result === 'object' && result != null) ? result : context; } var actor = _new(Person, "張三", 28); ~~~ ### instanceof運算符 instanceof運算符用來確定一個對象是否為某個構造函數的實例。 ~~~ var v = new Vehicle(); v instanceof Vehicle // true ~~~ instanceof運算符的左邊放置對象,右邊放置構造函數。在JavaScript之中,只要是對象,就有對應的構造函數。因此,instanceof運算符可以用來判斷值的類型。 ~~~ [1, 2, 3] instanceof Array // true ({}) instanceof Object // true ~~~ 上面代碼表示數組和對象則分別是Array對象和Object對象的實例。最后那一行的空對象外面,之所以要加括號,是因為如果不加,JavaScript引擎會把一對大括號解釋為一個代碼塊,而不是一個對象,從而導致這一行代碼被解釋為“{}; instanceof Object”,引擎就會報錯。 需要注意的是,由于原始類型的值不是對象,所以不能使用instanceof運算符判斷類型。 ~~~ "" instanceof String // false 1 instanceof Number // false ~~~ 上面代碼中,字符串不是String對象的實例(因為字符串不是對象),數值1也不是Number對象的實例(因為數值1不是對象)。 如果存在繼承關系,也就是某個對象可能是多個構造函數的實例,那么instanceof運算符對這些構造函數都返回true。 ~~~ var a = []; a instanceof Array // true a instanceof Object // true ~~~ 上面代碼表示,a是一個數組,所以它是Array的實例;同時,a也是一個對象,所以它也是Object的實例。 利用instanceof運算符,還可以巧妙地解決,調用構造函數時,忘了加new命令的問題。 ~~~ function Fubar (foo, bar) { if (this instanceof Fubar) { this._foo = foo; this._bar = bar; } else return new Fubar(foo, bar); } ~~~ 上面代碼使用instanceof運算符,在函數體內部判斷this關鍵字是否為構造函數Fubar的實例。如果不是,就表明忘了加new命令。 ## this關鍵字 ### 涵義 構造函數內部需要用到this關鍵字。那么,this關鍵字到底是什么意思呢? 簡單說,this就是指函數當前的運行環境。在JavaScript語言之中,所有函數都是在某個運行環境之中運行,this就是這個環境。對于JavaScipt語言來說,一切皆對象,運行環境也是對象,所以可以理解成,所有函數總是在某個對象之中運行,this就指向這個對象。這本來并不會讓用戶糊涂,但是JavaScript支持運行環境動態切換,也就是說,this的指向是動態的,沒有辦法事先確定到底指向哪個對象,這才是最讓初學者感到困惑的地方。 舉例來說,有一個函數f,它同時充當a對象和b對象的方法。JavaScript允許函數f的運行環境動態切換,即一會屬于a對象,一會屬于b對象,這就要靠this關鍵字來辦到。 ~~~ function f(){ console.log(this.x); }; var a = {x:'a'}; a.m = f; var b = {x:'b'}; b.m = f; a.m() // a b.m() // b ~~~ 上面代碼中,函數f可以打印出當前運行環境中x變量的值。當f屬于a對象時,this指向a;當f屬于b對象時,this指向b,因此打印出了不同的值。由于this的指向可變,所以可以手動切換運行環境,以達到某種特定的目的。 前面說過,所謂“運行環境”就是對象,this指函數運行時所在的那個對象。如果一個函數在全局環境中運行,this就是指頂層對象(瀏覽器中為window對象);如果一個函數作為某個對象的方法運行,this就是指那個對象。 可以近似地認為,this是所有函數運行時的一個隱藏參數,決定了函數的運行環境。 ### 使用場合 this的使用可以分成以下幾個場合。 (1)全局環境 在全局環境使用this,它指的就是頂層對象window。 ~~~ this === window // true function f() { console.log(this === window); // true } ~~~ 上面代碼說明,不管是不是在函數內部,只要是在全局環境下運行,this就是指全局對象window。 (2)構造函數 構造函數中的this,指的是實例對象。 ~~~ var O = function(p) { this.p = p; }; O.prototype.m = function() { return this.p; }; ~~~ 上面代碼定義了一個構造函數O。由于this指向實例對象,所以在構造函數內部定義this.p,就相當于定義實例對象有一個p屬性;然后m方法可以返回這個p屬性。 ~~~ var o = new O("Hello World!"); o.p // "Hello World!" o.m() // "Hello World!" ~~~ (3)對象的方法 當a對象的方法被賦予b對象,該方法就變成了普通函數,其中的this就從指向a對象變成了指向b對象。這就是this取決于運行時所在的對象的含義,所以要特別小心。如果將某個對象的方法賦值給另一個對象,會改變this的指向。 ~~~ var o1 = new Object(); o1.m = 1; o1.f = function (){ console.log(this.m);}; o1.f() // 1 var o2 = new Object(); o2.m = 2; o2.f = o1.f o2.f() // 2 ~~~ 從上面代碼可以看到,f是o1的方法,但是如果在o2上面調用這個方法,f方法中的this就會指向o2。這就說明JavaScript函數的運行環境完全是動態綁定的,可以在運行時切換。 如果不想改變this的指向,可以將o2.f改寫成下面這樣。 ~~~ o2.f = function (){ o1.f() }; o2.f() // 1 ~~~ 上面代碼表示,由于f方法這時是在o1下面運行,所以this就指向o1。 有時,某個方法位于多層對象的內部,這時如果為了簡化書寫,把該方法賦值給一個變量,往往會得到意想不到的結果。 ~~~ var a = { b : { m : function() { console.log(this.p); }, p : 'Hello' } }; var hello = a.b.m; hello() // undefined ~~~ 上面代碼表示,m屬于多層對象內部的一個方法。為求簡寫,將其賦值給hello變量,結果調用時,this指向了全局對象。為了避免這個問題,可以只將m所在的對象賦值給hello,這樣調用時,this的指向就不會變。 ~~~ var hello = a.b; hello.m() // Hello ~~~ (4)Node.js 在Node.js中,this的指向又分成兩種情況。全局環境中,this指向全局對象global;模塊環境中,this指向module.exports。 ~~~ // 全局環境 this === global // true // 模塊環境 this === module.exports // true ~~~ ### 使用注意點 (1)避免多層this 由于this的指向是不確定的,所以切勿在函數中包含多層的this。 ~~~ var o = { f1: function() { console.log(this); var f2 = function() { console.log(this); }(); } } o.f1() // Object // Window ~~~ 上面代碼包含兩層this,結果運行后,第一層指向該對象,第二層指向全局對象。一個解決方法是在第二層改用一個指向外層this的變量。 ~~~ var o = { f1: function() { console.log(this); var that = this; var f2 = function() { console.log(that); }(); } } o.f1() // Object // Object ~~~ 上面代碼定義了變量that,固定指向外層的this,然后在內層使用that,就不會發生this指向的改變。 (2)避免數組處理方法中的this 數組的map和foreach方法,允許提供一個函數作為參數。這個函數內部不應該使用this。 ~~~ var o = { v: 'hello', p: [ 'a1', 'a2' ], f: function f() { this.p.forEach(function (item) { console.log(this.v+' '+item); }); } } o.f() // undefined a1 // undefined a2 ~~~ 上面代碼中,foreach方法的參數函數中的this,其實是指向window對象,因此取不到o.v的值。 解決這個問題的一種方法,是使用中間變量。 ~~~ var o = { v: 'hello', p: [ 'a1', 'a2' ], f: function f() { var that = this; this.p.forEach(function (item) { console.log(that.v+' '+item); }); } } o.f() // hello a1 // hello a2 ~~~ 另一種方法是將this當作foreach方法的第二個參數,固定它的運行環境。 ~~~ var o = { v: 'hello', p: [ 'a1', 'a2' ], f: function f() { this.p.forEach(function (item) { console.log(this.v+' '+item); }, this); } } o.f() // hello a1 // hello a2 ~~~ (3)避免回調函數中的this 回調函數中的this往往會改變指向,最好避免使用。 ~~~ var o = new Object(); o.f = function (){ console.log(this === o); } o.f() // true ~~~ 上面代碼表示,如果調用o對象的f方法,其中的this就是指向o對象。 但是,如果將f方法指定給某個按鈕的click事件,this的指向就變了。 ~~~ $("#button").on("click", o.f); ~~~ 點擊按鈕以后,控制臺會顯示false。原因是此時this不再指向o對象,而是指向按鈕的DOM對象,因為f方法是在按鈕對象的環境中被調用的。這種細微的差別,很容易在編程中忽視,導致難以察覺的錯誤。 為了解決這個問題,可以采用下面的一些方法對this進行綁定,也就是使得this固定指向某個對象,減少不確定性。 ## 固定this的方法 this的動態切換,固然為JavaScript創造了巨大的靈活性,但也使得編程變得困難和模糊。有時,需要把this固定下來,避免出現意想不到的情況。JavaScript提供了call、apply、bind這三個方法,來切換/固定this的指向。 ### call方法 函數的call方法,可以指定該函數內部this的指向(即函數執行時所在的作用域),然后在所指定的作用域中,調用該函數。 ~~~ var o = {}; var f = function (){ return this; }; f() === this // true f.call(o) === o // true ~~~ 上面代碼中,在全局環境運行函數f時,this指向全局環境;call方法可以改變this的指向,指定this指向對象o,然后在對象o的作用域中運行函數f。 再看一個例子。 ~~~ var n = 123; var o = { n : 456 }; function a() { console.log(this.n); } a.call() // 123 a.call(null) // 123 a.call(undefined) // 123 a.call(window) // 123 a.call(o) // 456 ~~~ 上面代碼中,a函數中的this關鍵字,如果指向全局對象,返回結果為123。如果使用call方法將this關鍵字指向o對象,返回結果為456。可以看到,如果call方法沒有參數,或者參數為null或undefined,則等同于指向全局對象。 call方法的完整使用格式如下。 ~~~ func.call(thisValue, arg1, arg2, ...) ~~~ 它的第一個參數就是this所要指向的那個對象,后面的參數則是函數調用時所需的參數。 ~~~ function add(a,b) { return a+b; } add.call(this,1,2) // 3 ~~~ 上面代碼中,call方法指定函數add在當前環境(對象)中運行,并且參數為1和2,因此函數add運行后得到3。 call方法的一個應用是調用對象的原生方法。 ~~~ var obj = {}; obj.hasOwnProperty('toString') // false obj.hasOwnProperty = function (){ return true; }; obj.hasOwnProperty('toString') // true Object.prototype.hasOwnProperty.call(obj, 'toString') // false ~~~ 上面代碼中,hasOwnProperty是obj對象繼承的方法,如果這個方法一旦被覆蓋,就不會得到正確結果。call方法可以解決這個方法,它將hasOwnProperty方法的原始定義放到obj對象上執行,這樣無論obj上有沒有同名方法,都不會影響結果。 ### apply方法 apply方法的作用與call方法類似,也是改變this指向,然后再調用該函數。唯一的區別就是,它接收一個數組作為函數執行時的參數,使用格式如下。 ~~~ func.apply(thisValue, [arg1, arg2, ...]) ~~~ apply方法的第一個參數也是this所要指向的那個對象,如果設為null或undefined,則等同于指定全局對象。第二個參數則是一個數組,該數組的所有成員依次作為參數,傳入原函數。原函數的參數,在call方法中必須一個個添加,但是在apply方法中,必須以數組形式添加。 請看下面的例子。 ~~~ function f(x,y){ console.log(x+y); } f.call(null,1,1) // 2 f.apply(null,[1,1]) // 2 ~~~ 上面的f函數本來接受兩個參數,使用apply方法以后,就變成可以接受一個數組作為參數。 利用這一點,可以做一些有趣的應用。 (1)找出數組最大元素 JavaScript不提供找出數組最大元素的函數。結合使用apply方法和Math.max方法,就可以返回數組的最大元素。 ~~~ var a = [10, 2, 4, 15, 9]; Math.max.apply(null, a) // 15 ~~~ (2)將數組的空元素變為undefined 通過apply方法,利用Array構造函數將數組的空元素變成undefined。 ~~~ Array.apply(null, ["a",,"b"]) // [ 'a', undefined, 'b' ] ~~~ 空元素與undefined的差別在于,數組的foreach方法會跳過空元素,但是不會跳過undefined。因此,遍歷內部元素的時候,會得到不同的結果。 ~~~ var a = ["a",,"b"]; function print(i) { console.log(i); } a.forEach(print) // a // b Array.apply(null,a).forEach(print) // a // undefined // b ~~~ (3)轉換類似數組的對象 另外,利用數組對象的slice方法,可以將一個類似數組的對象(比如arguments對象)轉為真正的數組。 ~~~ Array.prototype.slice.apply({0:1,length:1}) // [1] Array.prototype.slice.apply({0:1}) // [] Array.prototype.slice.apply({0:1,length:2}) // [1, undefined] Array.prototype.slice.apply({length:1}) // [undefined] ~~~ 上面代碼的apply方法的參數都是對象,但是返回結果都是數組,這就起到了將對象轉成數組的目的。從上面代碼可以看到,這個方法起作用的前提是,被處理的對象必須有length屬性,以及相對應的數字鍵。 (4)綁定回調函數的對象 上一節按鈕點擊事件的例子,可以改寫成 ~~~ var o = new Object(); o.f = function (){ console.log(this === o); } var f = function (){ o.f.apply(o); // 或者 o.f.call(o); }; $("#button").on("click", f); ~~~ 點擊按鈕以后,控制臺將會顯示true。由于apply方法(或者call方法)不僅綁定函數執行時所在的對象,還會立即執行函數,因此不得不把綁定語句寫在一個函數體內。更簡潔的寫法是采用下面介紹的bind方法。 ### bind方法 bind方法用于將函數體內的this綁定到某個對象,然后返回一個新函數。它的使用格式如下。 ~~~ func.bind(thisValue, arg1, arg2,...) ~~~ 下面是一個例子。 ~~~ var o1 = new Object(); o1.p = 123; o1.m = function (){ console.log(this.p); }; o1.m() // 123 var o2 = new Object(); o2.p = 456; o2.m = o1.m; o2.m() // 456 o2.m = o1.m.bind(o1); o2.m() // 123 ~~~ 上面代碼使用bind方法將o1.m方法綁定到o1以后,在o2對象上調用o1.m的時候,o1.m函數體內部的this.p就不再到o2對象去尋找p屬性的值了。 bind比call方法和apply方法更進一步的是,除了綁定this以外,還可以綁定原函數的參數。 ~~~ var add = function (x,y) { return x*this.m + y*this.n; } var obj = { m: 2, n: 2 }; var newAdd = add.bind(obj, 5); newAdd(5) // 20 ~~~ 上面代碼中,bind方法除了綁定this對象,還綁定了add函數的第一個參數,結果newAdd函數只要一個參數就能運行了。 如果bind方法的第一個參數是null或undefined,等于將this綁定到全局對象,函數運行時this指向全局對象(在瀏覽器中為window)。 ~~~ function add(x,y) { return x+y; } var plus5 = add.bind(null, 5); plus5(10) // 15 ~~~ 上面代碼除了將add函數的運行環境綁定為全局對象,還將add函數的第一個參數綁定為5,然后返回一個新函數。以后,每次運行這個新函數,就只需要提供另一個參數就夠了。 bind方法有一些使用注意點。 (1)每一次返回一個新函數 bind方法每運行一次,就返回一個新函數,這會產生一些問題。比如,監聽事件的時候,不能寫成下面這樣。 ~~~ element.addEventListener('click', o.m.bind(o)); ~~~ 上面代碼表示,click事件綁定bind方法生成的一個匿名函數。這樣會導致無法取消綁定,所以,下面的代碼是無效的。 ~~~ element.removeEventListener('click', o.m.bind(o)); ~~~ 正確的方法是寫成下面這樣: ~~~ var listener = o.m.bind(o); element.addEventListener('click', listener); // ... element.removeEventListener('click', listener); ~~~ (2)bind方法的自定義代碼 對于那些不支持bind方法的老式瀏覽器,可以自行定義bind方法。 ~~~ if(!('bind' in Function.prototype)){ Function.prototype.bind = function(){ var fn = this; var context = arguments[0]; var args = Array.prototype.slice.call(arguments, 1); return function(){ return fn.apply(context, args); } } } ~~~ (3)jQuery的proxy方法 除了用bind方法綁定函數運行時所在的對象,還可以使用jQuery的$.proxy方法,它與bind方法的作用基本相同。 ~~~ $("#button").on("click", $.proxy(o.f, o)); ~~~ 上面代碼表示,$.proxy方法將o.f方法綁定到o對象。 (4)結合call方法使用 利用bind方法,可以改寫一些JavaScript原生方法的使用形式,以數組的slice方法為例。 ~~~ [1,2,3].slice(0,1) // [1] // 等同于 Array.prototype.slice.call([1,2,3], 0, 1) // [1] ~~~ 上面的代碼中,數組的slice方法從[1, 2, 3]里面,按照指定位置和長度切分出另一個數組。這樣做的本質是在[1, 2, 3]上面調用Array.prototype.slice方法,因此可以用call方法表達這個過程,得到同樣的結果。 call方法實質上是調用Function.prototype.call方法,因此上面的表達式可以用bind方法改寫。 ~~~ var slice = Function.prototype.call.bind(Array.prototype.slice); slice([1, 2, 3], 0, 1) // [1] ~~~ 可以看到,利用bind方法,將[1, 2, 3].slice(0, 1)變成了slice([1, 2, 3], 0, 1)的形式。這種形式的改變還可以用于其他數組方法。 ~~~ var push = Function.prototype.call.bind(Array.prototype.push); var pop = Function.prototype.call.bind(Array.prototype.pop); var a = [1 ,2 ,3]; push(a, 4) a // [1, 2, 3, 4] pop(a) a // [1, 2, 3] ~~~ 如果再進一步,將Function.prototype.call方法綁定到Function.prototype.bind對象,就意味著bind的調用形式也可以被改寫。 ~~~ function f(){ console.log(this.v); } var o = { v: 123 }; var bind = Function.prototype.call.bind(Function.prototype.bind); bind(f,o)() // 123 ~~~ 上面代碼表示,將Function.prototype.call方法綁定Function.prototype.bind以后,bind方法的使用形式從f.bind(o),變成了bind(f, o)。 ## 參考鏈接 * Jonathan Creamer,?[Avoiding the "this" problem in JavaScript](http://tech.pro/tutorial/1192/avoiding-the-this-problem-in-javascript) * Erik Kronberg,?[Bind, Call and Apply in JavaScript](https://variadic.me/posts/2013-10-22-bind-call-and-apply-in-javascript.html) * Axel Rauschmayer,?[JavaScript’s this: how it works, where it can trip you up](http://www.2ality.com/2014/05/this.html)
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看