call的特点
-
可以改变我们当前函数的this指向
-
还会让当前函数执行
function fn1() {
console.log(this)
}
// call的特点
// 1)可以改变我们当前函数的this指向
// 2)还会让当前函数执行
fn1.call(); //此时this指向window
function fn1() {
console.log(this)
}
// call的特点
// 1)可以改变我们当前函数的this指向
// 2)还会让当前函数执行
fn1.call(); //此时this指向window
fn1.call('hello')
call还能传参
function fn1() {
console.log(this,arguments)
}
// call的特点
// 1)可以改变我们当前函数的this指向
// 2)还会让当前函数执行
fn1.call(); //此时this指向window
fn1.call('hello')
fn1.call('hello','1','2')
call方法大概原理,在原型链上增加call方法,在方法内部使用this()执行函数
function fn1() {
console.log(this,arguments)
}
// call的特点
// 1)可以改变我们当前函数的this指向
// 2)还会让当前函数执行
fn1.call(); //此时this指向window
fn1.call('hello')
fn1.call('hello','1','2')
function fn2() {
console.log('2')
}
function fn3() {
console.log('3')
}
// Function.prototype.call = function(context){
// this() //执行当前函数
// }
fn2.call(fn3)
function fn1() {
console.log(this,arguments)
}
// call的特点
// 1)可以改变我们当前函数的this指向
// 2)还会让当前函数执行
fn1.call(); //此时this指向window
fn1.call('hello')
fn1.call('hello','1','2')
function fn2() {
console.log('2')
}
function fn3() {
console.log('3')
}
// Function.prototype.call = function(context){
// this() //执行当前函数
// }
fn2.call(fn3)
fn2.call.call(fn3) //call会改变当前的this指向,此时this指向fn3,this()执行fn3()
手写call方法
function fn1() {
console.log(this,arguments)
}
// call的特点
// 1)可以改变我们当前函数的this指向
// 2)还会让当前函数执行
fn1.call(); //此时this指向window
fn1.call('hello')
fn1.call('hello','1','2')
function fn2(a,b) {
console.log('fn2',this,arguments)
}
function fn3() {
console.log('fn3',this,'3')
}
Function.prototype.call = function(context){
context = context ? Object(context):window
console.log('context',context)
context.fn = this
console.log('context.fn',context.fn)
let args = []
for(let i=1;i<arguments.length; i++){
args.push('arguments['+i +']') // ['arguments[1]','arguments[2]']
}
console.log(args)
//利用数组的toString特性
const str = 'context.fn('+args + ')';
console.log(str) //context.fn(arguments[1],arguments[2])
let r = eval(str)
delete context.fn
console.log('r',r)
return r
}
fn2.call(fn3,1,'2')
fn2.call.call(fn3) //call会改变当前的this指向,此时this指向fn3,this()执行fn3()
fn2.call是函数,是如下函数,所以fn2.call.call(fn3) 中最后调用call的调用者为fn2.call,是如下函数。其实因为如下函数挂载到Function.prototype,所以fn2.call.call.call.call无论调用多少次,fn2.call是函数,是函数就有如下方法,如下方法又是函数,则又有如下方法。所以fn2.call.call.call.call.call(fn3)就等于如下函数.call(fn3)。
function(context){
context = context ? Object(context):window
console.log('context',context)
context.fn = this
console.log('context.fn',context.fn)
let args = []
for(let i=1;i<arguments.length; i++){
args.push('arguments['+i +']') // ['arguments[1]','arguments[2]']
}
console.log(args)
//利用数组的toString特性
const str = 'context.fn('+args + ')';
console.log(str) //context.fn(arguments[1],arguments[2])
let r = eval(str)
delete context.fn
console.log('r',r)
return r
}
context=fn3,转变为对象加上fn属性,属性值等于上边此函数,eval (context.fn())=此函数执行,调用者为context=fn3,此时传进此函数的参数为空,context为空,打印出window作为上下文,this=调用者=fn3,context.fn=this=fn3,执行eval(context.fn())=fn3()
apply原理
与call类似,只不过参数传的是数组,所以在call函数中的把参数封装成数组就不用了
function fn2(a,b) {
console.log('fn2',this,arguments)
}
function fn3() {
console.log('fn3',this,'3')
}
Function.prototype.apply = function(context,args){
context = context ? Object(context):window
console.log('context',context)
context.fn = this
console.log('context.fn',context.fn)
console.log(args)
if(!args){
context.fn();
}
//利用数组的toString特性
const str = 'context.fn('+args + ')';
console.log(str) //context.fn(arguments[1],arguments[2])
let r = eval(str)
delete context.fn
console.log('r',r)
return r
}
fn2.call(fn3,[1,2,3,4])