call() 方法使用一個指定的 this 值和單獨給出的一個或多個參數來調用一個函數。git
fun.call(thisArg, arg1, arg2, ...)github
使用調用者提供的 this 值和參數調用該函數的返回值。若該方法沒有返回值,則返回 undefined。數組
首先咱們來看一個例子app
var foo = {
value: 1
}
function bar (name, age) {
console.log(this.value, name, age)
}
bar.call(foo, 'zhangsan', '18') // 1 zhangsan 18
複製代碼
這看起來就像是這樣函數
var foo = {
value: 1,
bar: function (name, age) {
console.log(this.value, name, age)
}
}
foo.bar('zhangsan', '18') // 1 zhangsan 18
複製代碼
但咱們發現foo會多出來一個bar方法,這是咱們不想要的,咱們能夠在foo.bar以後刪除掉這個屬性,看起來也就像這樣測試
foo.fn = function () {}
foo.fn()
delete.fn
複製代碼
var foo = {
value: 1
}
function bar (name, age) {
console.log(this.value, name, age)
}
Function.prototype.call2 = function (context) {
// 咱們先來看看context、this、arguments都是那些參數
console.log('context: ', context)
console.log('this: ', this)
console.log('arguments: ', arguments)
}
bar.call2(foo, 'zhangsan', '18')
複製代碼
咱們能夠看到,context指向的是foo,this指向bar,arguments的第一個參數是foo,剩餘的是咱們須要給bar傳遞的參數ui
所以咱們能夠這樣寫this
var foo = {
value: 1
}
function bar (name, age) {
console.log(this.value, name, age)
}
Function.prototype.call2 = function (context) {
context.fn = this
var args = [] // 用於接收arguments參數
for (var i = 1; i < arguments.length; i++) {
args.push(arguments[i])
}
context.fn(args)
delete context.fn
}
bar.call2(foo, 'zhangsan', '18') // 1 (2) ["zhangsan", "18"] undefined
複製代碼
咱們發現獲得的結果並非咱們想要的,context.fn(args)
args只想當於一個參數,咱們須要把args解構,將每個參數都傳遞給context.fn
,爲了兼容咱們不使用ES6
的...
運算符。spa
JavaScript的eval
函數會將傳入的字符串當作 JavaScript 代碼進行執行prototype
代碼以下
Function.prototype.call2 = function (context) {
context.fn = this
var args = [] // 用於接收arguments參數
for (var i = 1; i < arguments.length; i++) {
args.push('arguments[' + i + ']')
}
eval('context.fn(' + args + ')')
delete context.fn
}
bar.call2(foo, 'zhangsan', '18') // 1 "zhangsan" "18"
複製代碼
一、函數是能夠有返回值!
function bar (name, age) {
console.log(name, age, this.value)
return {name}
}
console.log(bar.call(foo, 'zhangsan')) // {name: "zhangsan"}
console.log(bar.call2(foo, 'zhangsan')) // undefined
複製代碼
咱們發現咱們須要把eval('context.fn(' + args + ')')
的結果return
出去
代碼以下
Function.prototype.call2 = function (context) {
context.fn = this
var args = [] // 用於接收arguments參數
for (var i = 1; i < arguments.length; i++) {
args.push('arguments[' + i + ']')
}
var result = eval('context.fn(' + args + ')')
delete context.fn
return result
}
console.log(bar.call2(foo, 'zhangsan')) // {name: "zhangsan"}
複製代碼
二、this能夠傳遞爲null 當爲null時,默認指向window
代碼以下
Function.prototype.call2 = function (context) {
context = context ? context : window
context.fn = this
var args = [] // 用於接收arguments參數
for (var i = 1; i < arguments.length; i++) {
args.push('arguments[' + i + ']')
}
var result = eval('context.fn(' + args + ')')
delete context.fn
return result
}
複製代碼
三、this爲一個非Object類型的值時
代碼以下
Function.prototype.call2 = function (context) {
context = context ? Object(context) : window
context.fn = this
var args = [] // 用於接收arguments參數
for (var i = 1; i < arguments.length; i++) {
args.push('arguments[' + i + ']')
}
var result = eval('context.fn(' + args + ')')
delete context.fn
return result
}
複製代碼
var foo = {
value: 1
}
function bar (name, age) {
console.log(name, age, this.value)
return {name}
}
console.log(bar.call(123, 'zhangsan'))
Function.prototype.call2 = function (context) {
context = context ? Object(context) : window
context.fn = this
var args = []
for (var i = 1; i < arguments.length; i++) {
args.push('arguments[' + i + ']')
}
var result = eval('context.fn(' + args + ')')
delete context.fn
return result
}
console.log(bar.call2(123, 'zhangsan', '18'))
複製代碼
Function.prototype.call2 = function (context) {
context = context ? Object(context) : window
context.fn = this
const args = [...arguments].slice(1)
const result = context.fn(...args)
delete context.fn
return result
}
複製代碼
apply和call只有一個區別,就是 call() 方法接受的是一個參數列表,而 apply() 方法接受的是一個包含多個參數的數組。
Function.prototype.apply2 = function (context, arr) {
context = context ? Object(context) : window
context.fn = this
var result
if (!arr) {
result = context.fn
} else {
var args = []
for(var i = 0; i < arr.length; i++) {
args.push('arr[' + i + ']')
}
result = eval('context.fn(' + args + ')')
}
delete context.fn
return result
}
複製代碼
Function.prototype.apply2 = function (context, arr) {
context = context ? Object(context) : window
context.fn = this
let result
if (!arr) {
result = context.fn
} else {
result = context.fn(...arr)
}
delete context.fn
return result
}
複製代碼