理解javascript中call/apply的使用和模拟实现

call/apply 的作用

call() 方法调用一个函数, 其具有一个指定的this值和分别地提供的参数.

注意:该方法的作用和 apply() 方法类似,只有一个区别,就是call()方法接受的是若干个参数的列表,而apply()方法接受的是一个包含多个参数的数组。

function sayName(age) {
  // this.name = "person"; (1)
     console.log(this.name,age);
}
const student = {
    name: "student"
};
sayName.call(student,12); //person 12 (1)
sayName.call(student,13); //student 13
// call的作用: call 改变了 this 的指向,指向到 student
//(1)假如函数内部有相同属性情况,引用函数内部的属性

总结来说,call总共做了三件事,给对象加了一个函数,给函数传参,然后执行函数。下面我们对call进行模拟

下面我们先来模拟实现函数调用的this指向和函数的执行,怎么才能让函数的上下文指向调用对象呢,很简单我们直接把函数当作对象里面的一个方法即可,如

const student = {
  name: "student”,
  sayName:function(age){
    console.log(this.name,age);
  }
};
student.sayName(12); //person 12 (1)

我们不能让函数一直在对象里面占用内存,所以在调用之后需要删除,这样我们就可以封装一个简化版的call

// 第一版
Function.prototype.callSub = function(context) {
  context.fn = this;
  context.fn();
  delete context.fn;
};
sayName.callSub(student); //student

这里我们基本上完成一个可用的call,但是最重要的一步传参还没有完成。我们可以通过Arguments 对象取值,取出第二个到最后一个参数,然后放到一个数组里,传给函数调用。

// 第二版
Function.prototype.callSub = function(context) {
  context.fn = this;
  let args = [];
  for (var i = 1; i < arguments.length; i++) { // 需要从第二个参数开始
    args.push(arguments[i]);
  }
  var result = context.fn(...args);
  delete context.fn;
  return result;
};
function sayName(age, name) {
  return {
    age: age,
    name: name
  };
}
const student = {
   name: "小红"
};
console.log(sayName.callSub(student, 12, "小明")); //{age: 12, name: "小明"}

在参数传值这里我们利用了es6的解构赋值功能实现数组到参数的转化,但是call/apply是在es5中加入的,所以我们不能用es6的语法实现,传参的工作。这里我们利用eval()函数拼接一个可执行的js字符串脚本。

还有一点需要注意的是,指定的this值并不一定是该函数执行时真正的this值,如果这个函数处于non-strict mode,则指定为null和undefined的this值会自动指向全局对象(浏览器中就是window对象),同时值为原始值(数字,字符串,布尔值)的this会指向该原始值的自动包装对象。

// 最终版
Function.prototype.callSub = function(context) {
  var context = context || window; // 当context为null 的时候指向window
  context.fn = this;
  let args = [];
  for (var i = 1; i < arguments.length; i++) { // 需要从第二个参数开始
    args.push("arguments[" + i + "]");
  }
  var result = eval("context.fn(" + args + ")");
  delete context.fn;
  return result;
};
function sayName(age, name) {
  return {
    age: age,
    name: name,
    gender:this.gender
  };
}
const student = {
    name: "小红",
    gender:"woman"
};
console.log(sayName.callSub(student, 12, "小明")); //{age: 12, name: "小明", gender: "woman”}

function sayHello() {
  console.log("hello");
}
sayHello.callSub(); // hello

call和apply的区别就是传参的方式不一样

apply的模拟

// apply接受的参数是一个数组
Function.prototype.applySub = function(context, arr) {
  var context = 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 sayName(age, name) {
  return {
    age: age,
    name: name,
    gender: this.gender
  };
}
const student = {
  name: "小红",
  gender: "woman"
};
console.log(sayName.applySub(student, [12, "小明"])); //{age: 12, name: "小明",gender:"woman"}
function sayHello() {
  console.log("hello");
}
sayHello.applySub(); // hello

原文地址:https://www.cnblogs.com/chrissong/p/10493577.html

时间: 2024-08-28 12:37:45

理解javascript中call/apply的使用和模拟实现的相关文章

深入理解JavaScript中创建对象模式的演变(原型)

创建对象的模式多种多样,但是各种模式又有怎样的利弊呢?有没有一种最为完美的模式呢?下面我将就以下几个方面来分析创建对象的几种模式: Object构造函数和对象字面量方法 工厂模式 自定义构造函数模式 原型模式 组合使用自定义构造函数模式和原型模式 动态原型模式.寄生构造函数模式.稳妥构造函数模式 第一部分:Object构造函数和对象字面量方法 我之前在博文<javascript中对象字面量的理解>中讲到过这两种方法,如何大家不熟悉,可以点进去看一看回顾一下.它们的优点是用来创建单个的对象非常方

JavaScript大杂烩6 - 理解JavaScript中的this

在JavaScript开发中,this是很常用的一个关键字,但同时也是一个很容易引入bug的一个关键字,在这里我们就专门总结一下页面中可能出现的this关键字(包括几种在其他页面文件中出现的this). JavaScript中的this关键字通常只使用在函数中,它指向当前函数的调用者,这是this关键字的本质,所有的使用方式都是围绕这个展开的,让我们来看一下在各种性质的函数中this的用法.1. 在对象的函数中使用this var person = { name: 'Frank', say: f

转载 深入理解JavaScript中的this关键字

转载原地址: http://www.cnblogs.com/rainman/archive/2009/05/03/1448392.html 深入理解JavaScript中的this关键字 1. 一般用处 2. this.x 与 apply().call() 3. 无意义(诡异)的this用处 4. 事件监听函数中的this 5. 总结 在JavaScript中this变量是一个令人难以摸清的关键字,this可谓是非常强大,充分了解this的相关知识有助于我们在编写面向对象的JavaScript程

javascript中call,apply,bind的用法对比分析

这篇文章主要给大家对比分析了javascript中call,apply,bind三个函数的用法,非常的详细,这里推荐给小伙伴们. 关于call,apply,bind这三个函数的用法,是学习javascript这门语言无法越过的知识点.下边我就来好好总结一下它们三者各自的用法,及常见的应用场景. 首先看call这个函数,可以理解成"借用“,"请求".想像一下如下的情景:你孤单一人漂泊在外,有急事想往家里打电话,可是很不巧,手机欠费了,或者没电了,或者掉坑里了,总之你的手机就是用

理解javascript中的回调函数(callback)【转】

在JavaScrip中,function是内置的类对象,也就是说它是一种类型的对象,可以和其它String.Array.Number.Object类的对象一样用于内置对象的管理.因为function实际上是一种对象,它可以"存储在变量中,通过参数传递给(别一个)函数(function),在函数内部创建,从函数中返回结果值". 因为function是内置对象,我们可以将它作为参数传递给另一个函数,延迟到函数中执行,甚至执行后将它返回.这是在JavaScript中使用回调函数的精髓.本篇文

理解JavaScript中函数的使用

函数是进行模块化程序设计的基础,编写复杂的Ajax应用程序,必须对函数有更深入的了解. JavaScript中的函数不同于其他的语言,每个函数都是作为一个对象被维护和运行的.通过函数对象的性质,可以很方便的将一个函数赋值给一个变量或者将函数作为参数传递.在继续讲述之前,先看一下函数的使用语法: function func1(…){…} var func2=function(…){…}; var func3=function func4(…){…}; var func5=new Function(

理解 JavaScript 中的 this

前言 理解this是我们要深入理解 JavaScript 中必不可少的一个步骤,同时只有理解了 this,你才能更加清晰地写出与自己预期一致的 JavaScript 代码. 本文是这系列的第三篇,往期文章: 理解 JavaScript 中的作用域 理解 JavaScript 中的闭包 什么是 this 消除误解 在解释什么是this之前,需要先纠正大部分人对this的误解,常见的误解有: 指向函数自身. 指向它所在的作用域. 关于为何会误解的原因这里不多讲,这里只给出结论,有兴趣可以自行查询资料

深入理解JavaScript中的属性和特性

深入理解JavaScript中的属性和特性? JavaScript中属性和特性是完全不同的两个概念,这里我将根据自己所学,来深入理解JavaScript中的属性和特性. 主要内容如下: 理解JavaScript中理解对象的本质.理解对象与类的关系.对象与引用类型的关系 对象属性如何进行分类 属性中特性的理解 第一部分:理解JavaScript中理解对象的本质.理解对象与类的关系.对象与引用类型的关系 对象的本质:ECMA-262把对象定义为:无序属性的集合,其属性可以包含基本值.对象或者函数.即

【干货理解】理解javascript中实现MVC的原理

理解javascript中的MVC MVC模式是软件工程中一种软件架构模式,一般把软件模式分为三部分,模型(Model)+视图(View)+控制器(Controller); 模型:模型用于封装与应用程序的业务逻辑相关的数据以及对数据处理的方法.模型有对数据直接访问的权利.模型不依赖 "视图" 和 "控制器", 也就是说 模型它不关心页面如何显示及如何被操作. 视图:视图层最主要的是监听模型层上的数据改变,并且实时的更新html页面.当然也包括一些事件的注册或者aja