call、apply引有、bind 的區(qū)別

1瓣颅、call()

面試當中幾乎每次都會問到一個js中關(guān)于call、apply譬正、bind的問題宫补,比如…

  • 怎么利用call、apply來求一個數(shù)組中最大或者最小值
  • 如何利用call曾我、apply來做繼承
  • apply粉怕、call、bind的區(qū)別和主要應用場景

首先抒巢,要明白這三個函數(shù)的存在意義是什么斋荞?答案是改變函數(shù)執(zhí)行時的上下文,再具體一點就是改變函數(shù)運行時的this指向虐秦。有了這個認識平酿,接下來我們來看一下,怎么使用這三個函數(shù)凤优。

  let obj = {name: 'tony'};
  
  function Child(name){
    this.name = name;
  }
  
  Child.prototype = {
    constructor: Child,
    showName: function(){
      console.log(this.name);
    }
  }
  var child = new Child('thomas');
  child.showName(); // thomas
  
  //  call,apply,bind使用
  child.showName.call(obj);
  child.showName.apply(obj);
  let bind = child.showName.bind(obj); // 返回一個函數(shù)
  bind(); // tony
復制代碼

我們拿別人的showName方法,并動態(tài)改變其上下文幫自己輸出了信息蜈彼,說到底就是實現(xiàn)了復用

bind

bind方法是事先把fn的this改變?yōu)槲覀円胍慕Y(jié)果筑辨,并且把對應的參數(shù)值準備好,以后要用到了幸逆,直接的執(zhí)行即可棍辕,也就是說bind同樣可以改變this的指向,但和apply还绘、call不同就是不會馬上的執(zhí)行(如上一個例子)

注意:bind這個方法在IE6~8下不兼容楚昭。

區(qū)別

上面看起來三個函數(shù)的作用差不多,干的事幾乎是一樣的拍顷,那為什么要存在3個家伙呢抚太,留一個不就可以。所以其實他們干的事從本質(zhì)上講都是一樣的動態(tài)的改變this上下文,但是多少還是有一些差別的..

  • call昔案、apply與bind的差別

call和apply改變了函數(shù)的this上下文后便執(zhí)行該函數(shù),而bind則是返回改變了上下文后的一個函數(shù)尿贫。

  • call、apply的區(qū)別

他們倆之間的差別在于參數(shù)的區(qū)別踏揣,call和aplly的第一個參數(shù)都是要改變上下文的對象庆亡,而call從第二個參數(shù)開始以參數(shù)列表的形式展現(xiàn),apply則是把除了改變上下文對象的參數(shù)放在一個數(shù)組里面作為它的第二個參數(shù)捞稿。

let arr1 = [1, 2, 19, 6];
//例子:求數(shù)組中的最值
console.log(Math.max.call(null, 1,2,19,6)); // 19
console.log(Math.max.call(null, arr1)); // NaN
console.log(Math.max.apply(null, arr1)); //  19 直接可以用arr1傳遞進去
復制代碼

例子2:

function fn() {
    console.log(this);
}
// apply方法結(jié)果同下
fn.call(); // 普通模式下this是window又谋,在嚴格模式下this是undefined
fn.call(null); // 普通模式下this是window,在嚴格模式下this是null
fn.call(undefined); // 普通模式下this是window娱局,在嚴格模式下this是undefined
復制代碼

應用

  • 將偽數(shù)組轉(zhuǎn)化為數(shù)組(含有l(wèi)ength屬性的對象搂根,dom節(jié)點, 函數(shù)的參數(shù)arguments)

js中的偽數(shù)組(例如通過document.getElementsByTagName獲取的元素、含有l(wèi)ength屬性的對象)具有l(wèi)ength屬性铃辖,并且可以通過0剩愧、1勾邦、2…下標來訪問其中的元素鸟廓,但是沒有Array中的push、pop等方法邀窃。就可以利用call犬第,apply來轉(zhuǎn)化成真正的數(shù)組锦积,就可以使用數(shù)組的方法了

case1: dom節(jié)點:

<div class="div1">1</div>
<div class="div1">2</div>
<div class="div1">3</div>

let div = document.getElementsByTagName('div');
console.log(div); // HTMLCollection(3) [div.div1, div.div1, div.div1] 里面包含length屬性

let arr2 = Array.prototype.slice.call(div);
console.log(arr2); // 數(shù)組 [div.div1, div.div1, div.div1]
復制代碼

但是這個不適用于IE6~8,會報錯:

SCRIPT5014: Array.prototype.slice: 'this' 不是 JavaScript 對象 (報錯)
復制代碼

那么在IE6~8下就只能通過循環(huán)一個個加到數(shù)組中了:

for (var i = 0; i < oLis.length; i++) {
    ary[ary.length] = oLis[i];
}
復制代碼

基于IE6~8和標準瀏覽器中的區(qū)別歉嗓,抽取出類數(shù)組對象轉(zhuǎn)換為數(shù)組的工具類:

function listToArray(likeAry) {
    var ary = [];
    try {
        ary = Array.prototype.slice.call(likeAry);
    } catch (e) {
        for (var i = 0; i < likeAry.length; i++) {
            ary[ary.length] = likeAry[i];
        }
    }
    return ary;
}
復制代碼

case2: fn內(nèi)的arguments

function fn10() {
    return Array.prototype.slice.call(arguments);
}
console.log(fn10(1,2,3,4,5)); // [1, 2, 3, 4, 5]
復制代碼

注意:對于arguments借用數(shù)組的方法是不存在任何兼容性問題的丰介。

case3: 含有l(wèi)ength屬性的對象

let obj4 = {
    0: 1,
    1: 'thomas',
    2: 13,
    length: 3 // 一定要有l(wèi)ength屬性
};

console.log(Array.prototype.slice.call(obj4)); // [1, "thomas", 13]
復制代碼
  • 數(shù)組拼接,添加

    let arr1 = [1,2,3];
    let arr2 = [4,5,6];

    //數(shù)組的concat方法:返回一個新的數(shù)組
    let arr3 = arr1.concat(arr2);
    console.log(arr3); // [1, 2, 3, 4, 5, 6]

    console.log(arr1); // [1, 2, 3] 不變
    console.log(arr2); // [4, 5, 6] 不變
    // 用 apply方法
    [].push.apply(arr1,arr2); // 給arr1添加arr2
    console.log(arr1); // [1, 2, 3, 4, 5, 6]
    console.log(arr2); // 不變
    復制代碼

  • 判斷變量類型

    let arr1 = [1,2,3];
    let str1 = 'string';
    let obj1 = {name: 'thomas'};
    //
    function isArray(obj) {
    return Object.prototype.toString.call(obj) === '[object Array]';
    }
    console.log(fn1(arr1)); // true

    // 判斷類型的方式,這個最常用語判斷array和object哮幢,null(因為typeof null等于object)
    console.log(Object.prototype.toString.call(arr1)); // [object Array]
    console.log(Object.prototype.toString.call(str1)); // [object String]
    console.log(Object.prototype.toString.call(obj1)); // [object Object]
    console.log(Object.prototype.toString.call(null)); // [object Null]
    復制代碼

  • 利用call和apply做繼承

    function Animal(name){
    this.name = name;
    this.showName = function(){
    console.log(this.name);
    }
    }

    function Cat(name){
    Animal.call(this, name);
    }

    // Animal.call(this) 的意思就是使用this對象代替Animal對象带膀,那么
    // Cat中不就有Animal的所有屬性和方法了嗎,Cat對象就能夠直接調(diào)用Animal的方法以及屬性了
    var cat = new Cat("TONY");
    cat.showName(); //TONY
    復制代碼

  • 多繼承

    function Class1(a,b) {
      this.showclass1 = function(a,b) {
        console.log(`class1: ${a},$橙垢`);
      }
    }
    
    function Class2(a,b) {
      this.showclass2 = function(a,b) {
        console.log(`class2: ${a},$垛叨`);
      }
    }
    
    function Class3(a,b,c) {
      Class1.call(this);
      Class2.call(this);
    }
    
    let arr10 = [2,2];
    let demo = new Class3();
    demo.showclass1.call(this,1); // class1: 1,undefined
    demo.showclass1.call(this,1,2); // class1: 1,1
    demo.showclass2.apply(this,arr10); // class2: 2,2
    
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市柜某,隨后出現(xiàn)的幾起案子嗽元,更是在濱河造成了極大的恐慌,老刑警劉巖喂击,帶你破解...
    沈念sama閱讀 211,194評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件剂癌,死亡現(xiàn)場離奇詭異,居然都是意外死亡翰绊,警方通過查閱死者的電腦和手機佩谷,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,058評論 2 385
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來辞做,“玉大人,你說我怎么就攤上這事寡具〕用” “怎么了?”我有些...
    開封第一講書人閱讀 156,780評論 0 346
  • 文/不壞的土叔 我叫張陵童叠,是天一觀的道長框喳。 經(jīng)常有香客問我,道長厦坛,這世上最難降的妖魔是什么五垮? 我笑而不...
    開封第一講書人閱讀 56,388評論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮杜秸,結(jié)果婚禮上放仗,老公的妹妹穿的比我還像新娘。我一直安慰自己撬碟,他們只是感情好诞挨,可當我...
    茶點故事閱讀 65,430評論 5 384
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著呢蛤,像睡著了一般惶傻。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上其障,一...
    開封第一講書人閱讀 49,764評論 1 290
  • 那天银室,我揣著相機與錄音,去河邊找鬼。 笑死蜈敢,一個胖子當著我的面吹牛辜荠,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播扶认,決...
    沈念sama閱讀 38,907評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼侨拦,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了辐宾?” 一聲冷哼從身側(cè)響起狱从,我...
    開封第一講書人閱讀 37,679評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎叠纹,沒想到半個月后季研,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,122評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡誉察,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,459評論 2 325
  • 正文 我和宋清朗相戀三年与涡,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片持偏。...
    茶點故事閱讀 38,605評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡驼卖,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出鸿秆,到底是詐尸還是另有隱情酌畜,我是刑警寧澤,帶...
    沈念sama閱讀 34,270評論 4 329
  • 正文 年R本政府宣布卿叽,位于F島的核電站桥胞,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏考婴。R本人自食惡果不足惜贩虾,卻給世界環(huán)境...
    茶點故事閱讀 39,867評論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望沥阱。 院中可真熱鬧缎罢,春花似錦、人聲如沸考杉。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,734評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽奔则。三九已至蛮寂,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間易茬,已是汗流浹背酬蹋。 一陣腳步聲響...
    開封第一講書人閱讀 31,961評論 1 265
  • 我被黑心中介騙來泰國打工及老, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人范抓。 一個月前我還...
    沈念sama閱讀 46,297評論 2 360
  • 正文 我出身青樓骄恶,卻偏偏與公主長得像,于是被迫代替她去往敵國和親匕垫。 傳聞我的和親對象是個殘疾皇子僧鲁,可洞房花燭夜當晚...
    茶點故事閱讀 43,472評論 2 348

推薦閱讀更多精彩內(nèi)容