談談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會自動執行對應的函式),而是返回對繫結函式的引用。