call和apply原理与源码分析

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;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值