JavaScript 中call apply 那點簡單事

找抽的小陀螺發表於2017-09-23

談談JavaScript 中call apply 那點簡單事

平常是否遇到過call apply 的問題 比如說

  • 怎麼利用call、apply來求一個陣列中最大或者最小值
  • 如何利用call、apply來做繼承
  • apply、call的區別和主要應用場景

這些有可能在面試時候 會問到不知道你清楚嗎 如果你清楚沒有必要太仔細看 不清楚可以看看下面我談談

首先那這三個點那 在我們平常中使用是用來改變函式執行上下文的 說白了就是改變this的指向

上段code

  function Person (name) {
      this.name = name
  }
  Person.prototypr = {
      showname: function() {
         alert(this.name)
      }
  }
  var p = new Person('xiaoming');
  p.showname(); //這裡列印 xiaoming  這個相信大家都知道答案複製程式碼

接著來

var a = {
    name: 'xiaowang'
}
alert(a.showname)  //這裡列印的 undefined   很明顯a 物件裡面沒有showname複製程式碼

這裡我們想到一個方法就是用Person原型的showname方法 這裡八竿子打不著關係 於是call apply 來幫助了


Person.showName.call(a);

Person.showName.apply(a);

Person.showName.bind(a)();

//發生了什麼 都是列印了  牛逼了  來解釋下這些個名次複製程式碼

call apply 其實差不多 就是引數的形式不一樣

call() 引數接受的都是一個一個 call(this, arg1, arg2, ....)
apply() 引數接受的是一個陣列 apply(this, [arg1, arg2, ....])
擦 這不差不多嗎 就一個引數的形式不一樣而已 話不多說來上code
比如面試常問到的

  • 求陣列中的最大和最小值
  var arr = [4,3,6,1,7,2,0,9]
  平常我我們見到是這樣 console.log(Math.max(3,4,2,1,0)) 列印是4  達到了預期 如果資料很多豈不是要一直寫下去嘍
  利用apply
  Math.max.apply(Math, arr) //列印 9
  利用call
  Math.max.apply(Math, 4,3,6,1,7,2,0,9) //列印 9複製程式碼

解釋下上面是啥意思 arr是沒有max的方法的 可是Math是有的
所以利用call 或者apply 來將Math的方法拿過來用

  • 陣列之間的新增
 var a =[1,2,3]
 var b =[4,5,6]
 需求是將b追加到a中 這個使用我們就用到了apply
 Array.prototype.push.apply(a, b); 
 console.log(a) //[1,2,3,4,5,6]複製程式碼

解釋下上面 真陣列才有push的方法 這裡是將 a 拿到b這裡 一個個新增到a中

  • 類(偽)陣列使用陣列方法
    先解釋下啥叫類(偽)陣列 先看下陣列長啥樣
var a = new Array('a','b')
console.log(a) //  0:'a'  1:'b'  length:2

但是如果是這樣的是陣列嗎?
var arrayLike = {
  0: 'a',
  1: 'b',
  length: 2
}
所以說具有length屬性,並且可以通過0、1、2…下標來訪問其中的元素,但是沒有Array中的push、pop等方法。

var a = {
  0: 'xiaoming',
  1: 'xiaowang',
  2: 'xiaoxing',
  length: 3
}
var arr = Array.prototype.slice.call(a)
Array.prototype.slice=function(start, end) {
    var result =  new Array()
    var start = start || 0;
    var end =  end || this.length
    for (var i = start;i<end; i++) {
        result.push(this[i])
    }
    return result
}
console.log(arr) // ["xiaoming", "xiaowang", "xiaoxing"


還有一種方法
使用原型繼承

a.__proto__ = Array.prototype;
console.log(a.constructor === Array) //true
console.log(arr)// ["xiaoming", "xiaowang", "xiaoxing"]複製程式碼

這裡解釋下 注意點資料結構必須是以數字為下標而且一定要有length屬性
陣列的slice 方法底層的實現就是這個 將這個方法拿過來了到a 這個物件中 最後放回陣列["xiaoming", "xiaowang", "xiaoxing"]

  • 用到繼承
var Person = function (name, age) {
  this.name = name;
  this.age = age;
};
var Girl = function (name) {
  Person.call(this, name);
};
var Boy = function (name, age) {
  Person.apply(this, arguments);
}
var g1 = new Girl ('qing');
var b1 = new Boy('qianlong', 100);


等同於
var Person = function (name, age) {
  this.name = name;
  this.age = age;
};
var Girl = function (name, age) {
    this.name = name;
    this.age = age;
};
var Boy = function (name, age) {
    this.name = name;
    this.age = age;
}
var g1 = new Girl ('qing');
var b1 = new Boy('qianlong', 100);複製程式碼

解釋下 Person.call 可以看成把Person 拿到 GirlBoy中使用

簡單部一個 bind()方法會建立一個新函式,稱為繫結函式。
bind是ES5新增的一個方法,不會執行對應的函式(call或apply會自動執行對應的函式),而是返回對繫結函式的引用。

相關文章