javascript中call apply 與 bind方法詳解,applybind

來源:互聯網
上載者:User

javascript中call apply 與 bind方法詳解,applybind

在JavaScript中,call、apply和bind是Function對象內建的三個方法,本文將通過幾個情境的應用,來詳細理解三個方法。

call()

call() 方法在使用一個指定的this值和若干個指定的參數值的前提下調用某個函數或方法。

當調用一個函數時,可以賦值一個不同的 this 對象。this 引用當前對象,即 call 方法的第一個參數。

通過 call 方法,你可以在一個對象上借用另一個對象上的方法,比如Object.prototype.toString.call([]),就是一個Array對象借用了Object對象上的方法。

文法 fun.call(thisArg[, arg1[, arg2[, ...]]])
thisArg
在fun函數運行時指定的this值。需要注意的是下面幾種情況

(1)不傳,或者傳null,undefined, 函數中的this指向window對象
(2)傳遞另一個函數的函數名,函數中的this指向這個函數的引用,並不一定是該函數執行時真正的this值
(3)值為原始值(數字,字串,布爾值)的this會指向該原始值的自動封裝對象,如 String、Number、Boolean
(4)傳遞一個對象,函數中的this指向這個對象

arg1, arg2, ...
指定的參數列表。

例子
初級應用例子

function a(){ //輸出函數a中的this對象 console.log(this); }//定義函數bfunction b(){} var obj = {name:'這是一個屌絲'}; //定義對象obja.call(); //windowa.call(null); //windowa.call(undefined);//windowa.call(1); //Numbera.call(''); //Stringa.call(true); //Booleana.call(b);// function b(){}a.call(obj); //Object

使用call方法調用匿名函數並且指定內容相關的this

在下面的例子中,當調用 greet 方法的時候,該方法的 this 值會綁定到 i對象。

function greet() { var reply = [this.person, '是一個輕量的', this.role].join(' '); console.log(reply);}var i = {function greet() { var reply = [this.person, '是一個輕量的', this.role].join(' '); console.log(reply);}var i = { person: 'JSLite.io', role: 'Javascript 庫。'};greet.call(i); // JSLite.io 是一個輕量的 Javascript 庫。 person: 'JSLite.io', role: 'Javascript 庫。'};greet.call(i); // JSLite.io 是一個輕量的 Javascript 庫。

使用call方法調用匿名函數

在下例中的for迴圈體內,我們建立了一個匿名函數,然後通過調用該函數的call方法,將每個數組元素作為指定的this值執行了那個匿名函數。這個匿名函數的主要目的是給每個數組元素對象添加一個print方法,這個print方法可以列印出各元素在數組中的正確索引號。當然,這裡不是必須得讓數組元素作為this值傳入那個匿名函數(普通參數就可以),目的是為了示範call的用法。

var animals = [ {species: 'Lion', name: 'King'}, {species: 'Whale', name: 'Fail'}];for (var i = 0; i < animals.length; i++) { (function (i) {  this.print = function () {   console.log('#' + i + ' ' + this.species + ': ' + this.name);  }  this.print(); }).call(animals[i], i);}//#0 Lion: King//#1 Whale: Fail

使用call方法調用函數傳參數

var a = { name:'JSLite.io', //定義a的屬性 say:function(){ //定義a的方法  console.log("Hi,I'm function a!"); }};function b(name){ console.log("Post params: "+ name); console.log("I'm "+ this.name); this.say();}b.call(a,'test');//Post params: test//I'm onepixel//I'm function a!

apply()

文法與 call() 方法的文法幾乎完全相同,唯一的區別在於,apply的第二個參數必須是一個包含多個參數的數組(或類數組對象)。apply的這個特性很重要,

在調用一個存在的函數時,你可以為其指定一個 this 對象。 this 指當前對象,也就是正在調用這個函數的對象。 使用 apply, 你可以唯寫一次這個方法然後在另一個對象中繼承它,而不用在新對象中重複寫該方法。

文法:fun.apply(thisArg[, argsArray])
注意: 需要注意:Chrome 14 以及 Internet Explorer 9 仍然不接受類數組對象。如果傳入類數組對象,它們會拋出異常。

參數
thisArg

同上call 的thisArg參數。

argsArray

一個數組或者類數組對象,其中的數組元素將作為單獨的參數傳給 fun 函數。如果該參數的值為null 或 undefined,則表示不需要傳入任何參數。從ECMAScript 5 開始可以使用類數組對象。

例子

function jsy(x,y,z){ console.log(x,y,z);}jsy.apply(null,[1,2,3]); // 1 2 3

使用apply來連結構造器的例子

你可以使用apply來給一個對象連結構造器,類似於Java. 在接下來的例子中我們會建立一個叫做construct的全域的Function函數,來使你能夠在構造器中使用一個類數組對象而非參數列表。

Function.prototype.construct = function(aArgs) { var fConstructor = this,  fNewConstr = function() {  fConstructor.apply(this, aArgs);  }; fNewConstr.prototype = fConstructor.prototype; return new fNewConstr();};function MyConstructor () { for (var nProp = 0; nProp < arguments.length; nProp++) {  console.log(arguments,this)  this["property" + nProp] = arguments[nProp]; }}var myArray = [4, "Hello world!", false];var myInstance = MyConstructor.construct(myArray);console.log(myInstance.property1);    // logs "Hello world!"console.log(myInstance instanceof MyConstructor); // logs "true"console.log(myInstance.constructor);    // logs "MyConstructor"

使用apply和內建函數

聰明的apply用法允許你在某些本來需要寫成遍曆陣列變數的任務中使用內建的函數。在接下裡的例子中我們會使用Math.max/Math.min來找出一個數組中的最大/最小值。

//裡面有最大最小數字值的一個數組對象var numbers = [5, 6, 2, 3, 7];/* 使用 Math.min/Math.max 在 apply 中應用 */var max = Math.max.apply(null, numbers);// 一般情況是用 Math.max(5, 6, ..) 或者 Math.max(numbers[0], ...) 來找最大值var min = Math.min.apply(null, numbers);//通常情況我們會這樣來找到數位最大或者最小值//比對上面的栗子,是不是下面的看起來沒有上面的舒服呢?max = -Infinity, min = +Infinity;for (var i = 0; i < numbers.length; i++) { if (numbers[i] > max) max = numbers[i]; if (numbers[i] < min)  min = numbers[i];}

參數數組切塊後迴圈傳入

function minOfArray(arr) { var min = Infinity; var QUANTUM = 32768; for (var i = 0, len = arr.length; i < len; i += QUANTUM) { var submin = Math.min.apply(null, arr.slice(i, Math.min(i + QUANTUM, len))); console.log(submin, min) min = Math.min(submin, min); } return min;}var min = minOfArray([5, 6, 2, 3, 7]);

bind

bind() 函數會建立一個新函數(稱為綁定函數)

bind是ES5新增的一個方法
傳參和call或apply類似
不會執行對應的函數,call或apply會自動執行對應的函數
返回對函數的引用
文法 fun.bind(thisArg[, arg1[, arg2[, ...]]])

下面例子:當點擊網頁時,EventClick被觸發執行,輸出JSLite.io p1 p2, 說明EventClick中的this被bind改變成了obj對象。如果你將EventClick.bind(obj,'p1','p2') 變成 EventClick.call(obj,'p1','p2') 的話,頁面會直接輸出 JSLite.io p1 p2

var obj = {name:'JSLite.io'};/** * 給document添加click事件監聽,並綁定EventClick函數 * 通過bind方法設定EventClick的this為obj,並傳遞參數p1,p2 */document.addEventListener('click',EventClick.bind(obj,'p1','p2'),false);//當點擊網頁時觸發並執行function EventClick(a,b){ console.log(   this.name, //JSLite.io   a, //p1   b //p2 )}// JSLite.io p1 p2

相容

if (!Function.prototype.bind) { Function.prototype.bind = function (oThis) { if (typeof this !== "function") {  // closest thing possible to the ECMAScript 5  // internal IsCallable function  throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable"); } var aArgs = Array.prototype.slice.call(arguments, 1),   fToBind = this, // this在這裡指向的是目標函數  fNOP = function () {},  fBound = function () {   return fToBind.apply(this instanceof fNOP     ? this //此時的this就是new出的obj     : oThis || this,//如果傳遞的oThis無效,就將fBound的調用者作為this        //將通過bind傳遞的參數和調用時傳遞的參數進行合并,並作為最終的參數傳遞    aArgs.concat(Array.prototype.slice.call(arguments)));  }; fNOP.prototype = this.prototype; //將目標函數的原型對象拷貝到新函數中,因為目標函數有可能被當作建構函式使用 fBound.prototype = new fNOP(); //返回fBond的引用,由外部按需調用 return fBound; };}

相容例子來源於:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Function/bind#Compatibility

應用情境:繼承

function Animal(name,weight){ this.name = name; this.weight = weight;}function Cat(){ // 在call中將this作為thisArgs參數傳遞 // Animal方法中的this就指向了Cat中的this // 所以Animal中的this指向的就是cat對象 // 在Animal中定義了name和weight屬性,就相當於在cat中定義了這些屬性 // cat對象便擁有了Animal中定義的屬性,從而達到了繼承的目的 Animal.call(this,'cat','50'); //Animal.apply(this,['cat','50']); this.say = function(){  console.log("I am " + this.name+",my weight is " + this.weight); }}//當通過new運算子產生了cat時,Cat中的this就指向了cat對象var cat = new Cat();cat.say();//輸出=> I am cat,my weight is 50

原型擴充

在原型函數上擴充和自訂方法,從而不汙染原生函數。例如:我們在 Array 上擴充一個 forEach

function test(){ // 檢測arguments是否為Array的執行個體 console.log(  arguments instanceof Array, //false  Array.isArray(arguments) //false ); // 判斷arguments是否有forEach方法 console.log(arguments.forEach);  // undefined // 將數組中的forEach應用到arguments上 Array.prototype.forEach.call(arguments,function(item){  console.log(item); // 1 2 3 4 });}test(1,2,3,4);

您可能感興趣的文章:
  • js apply/call/caller/callee/bind使用方法與區別分析
  • javascript中call,apply,bind的用法對比分析
  • 淺談javascript中call()、apply()、bind()的用法
  • 開啟Javascript中apply、call、bind的用法之旅模式
  • 跟我學習javascript的call(),apply(),bind()與回調
  • 淺談javascript的call()、apply()、bind()的用法
  • 淺談javascript中的call、apply、bind

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.