call与apply源码分析
call与apply都是改变函数内this指向问题
call
1.第一个参数是this指向的对象。
2.使用的单个参数进行传递。
实例
function loadXMLDoc()
{
abc.call(a)
}
let a = {
name : 'bcd'
}
function abc(){
console.log(this.name)
}
//(index):17 bcd
var name = '李四'
var b = {name:'张三'};
function a(n){
console.log(this.name+n+'岁了')
}
a.call(b,'18');//'张三18岁了'
a.call(null,'18');//'李四18岁了'
//有没有发现两种代码的实现的效果是一样的
function loadXMLDoc()
{
a.fun()
delete a.fn
}
let a = {
name : 'bcd',
fun : abc
}
function abc(){
console.log(this.name)
}
//(index):18 bcd
call原理就是:通过将call()指定的对象,添加调用call()的函数作为一个属性,这个时候函数的this指向该对象,然后执行该函数,最后将对象的函数删除。
call源码
Function.prototype.call = function(ctx){
var ctx = ctx || window //判断是否有参数,没有赋值为全局
ctx.fun = this //this是Function实例,即调用本身
var array = [] //储存参数数组
//Javascrip中每个函数都会有一个Arguments对象实例arguments,
//它引用着函数的实参,可以用数组下标的方式"[]"引用arguments的元素。
//arguments.length为函数实参个数,arguments.callee引用函数自身。
for(let i=1;i<arguments.length;i++){
array.push(`arguments[{i}]`)
}
//调用函数,并将参数传给函数
var result = ctx.fun(...array)
//删除对象的函数
delete ctx.fun
return result
}
apply
1.第一个参数是this指向的对象。
2.使用的参数是数组进行传递。
function loadXMLDoc()
{
//创建一个学生类
var student=new Student("qian",21,"一年级");
//测试
alert("name:"+student.name+"\n"+"age:"+student.age+"\n"+"grade:"+student.grade);
}
/*定义一个人类*/
function Person(name,age) {
this.name=name; this.age=age;
}
/*定义一个学生类*/
function Student(name,age,grade) {
Person.apply(this,arguments); this.grade=grade;
}
function loadXMLDoc()
{
var fu = fun.apply(a,[12,13])
}
function fun(n,n1){
console.log(this.name+'--'+n+'--'+n1)
}
let a = {name:'xa'}
apply源码
与call差别不大,只是判断第二个参数是不是数组
不用通过arguments来调参数
Function.prototype.applya = function (obj, arr) {
// 当apply的第一个参数是null的时候,this的默认指向是window
var obj = obj || window;
// 把该函数挂载到对象上
obj.fn = this;
//判断有没有传值
if (!arr) {
result = obj.fn();
} else {
//判断传入的是不是数组,不是的话抛出异常
if (!Array.isArray(arr)) {
throw new Error('上传的必须是数组');
};
var args = [];
// 用于存储apply后面的参数
for (var i = 0; i < arr.length; i++) {
args.push('arr[' + i + ']');
};
// 这里的args默认是会调用Array.toString()方法的
var result = eval('obj.fn(' + args + ')');
}
// 删除函数
delete obj.fn;
// 因为函数可能有放回值,所以把结果也返回出去给他们
return result;
}