a.call和apply方法详解


call方法:

  语法:call([thisObj[,arg1[, arg2[,   [,.argN]]]]])

  定义:调用一个对象的一个方法,以另一个对象替换当前对象。

  说明: call 方法可以用来代替另一个对象调用一个方法。call 方法可将一个函数的对象上下文从初始的上下文改变为由 thisObj 指定的新对象。如果没有提供 thisObj 参数,那么 Global 对象被用作 thisObj。

apply方法:

  语法:apply([thisObj[,argArray]])

  定义:应用某一对象的一个方法,用另一个对象替换当前对象。

  说明:如果 argArray 不是一个有效的数组或者不是 arguments 对象,那么将导致一个 TypeError。如果没有提供 argArray 和 thisObj 任何一个参数,那么 Global 对象将被用作 thisObj, 并且无法被传递任何参数。

实例学习:

  1. function add(a,b){ alert(a+b);}
  2. function sub(a,b){ alert(a-b);}
  3. add.call(sub,3,1);

  打印结果为4。调用add函数,但是调用对象(上下文环境)不是add对象,而是sub函数对象。注意:js中的函数其实是对象,函数名是对 Function 对象的引用。

  1. function Animal(){
  2. this.name = "Animal";
  3. this.showName = function(){ alert(this.name);}
  4. }
  5. function Cat(){ this.name = "Cat"; }
  6. var animal = new Animal();
  7. var cat = new Cat();
  8. animal.showName.call(cat,",");//输出结果为"Cat"
  9. animal.showName.apply(cat,[]);//输出结果为"Cat"

  call 的意思是把 animal 的方法放到cat上执行,上下文环境为cat,原来cat是没有showName() 方法,现在是把animal 的showName()方法放到 cat上来执行,而cat的this.name是Cat。所以this.name 应该是 Cat

实现继承

  1. function Animal(name){
  2. this.name = name;
  3. this.showName = function(){ alert(this.name);}
  4. }
  5. function Cat(name){ Animal.call(this, name); }
  6. var cat = new Cat("Black Cat");
  7. cat.showName();

  Animal.call(this) 的意思就是调用Animal方法,但是使用 this对象代替Animal对象,上下文环境变成了this。new Cat("Black Cat")中使用Animal.call给当前的上下文环境设置了属性name和方法showName。

拓展:多重继承

  1. function Class10(){
  2. this.showSub = function(a,b){ alert(a-b); }
  3. }
  4.  
  5. function Class11(){
  6. this.showAdd = function(a,b){ alert(a+b); }
  7. }
  8.  
  9. function Class2(){
  10. Class10.call(this);
  11. Class11.call(this);
  12. }

  备注:js的继承还有其他方法,例如使用原型链,这个不属于本文的范畴,只是在此说明call 的用法。说了call ,当然还有 apply,这两个方法基本上是一个意思,区别在于 call 的第二个参数可以是任意类型,而apply的第二个参数必须是数组或arguments。

b.arguments使用


什么是arguments

  arguments 是是JavaScript里的一个内置对象,它很古怪,也经常被人所忽视,但实际上是很重要的。所有主要的js函数库都利用了arguments对象。所以agruments对象对于javascript程序员来说是必需熟悉的。

  所有的函数都有属于自己的一个arguments对象,它包括了函所要调用的参数。他不是一个数组,如果用typeof arguments,返回的是’object’。虽然我们可以用调用数据的方法来调用arguments。比如length,还有index方法。但是数 组的push和pop对象是不适用的。

使用arguments创建一个灵活的函数

  看起来貌似argument对象使用起来十分有限,但是实际上它是一个非常有用的对象。你可以通过使用argument对象让函数能够调用数量不定 的参数。在Dean Edwards的base2库里有个格式化的函数,展示了这个灵活性。

  1. function format(string) {
  2. var args = arguments;
  3. var pattern = new RegExp('%([1-' + arguments.length + '])', 'g');
  4. return String(string).replace(pattern, function(match, index,position,all) {
  5. console.log(match + '&' + index + '&' + position + '&' + all);
  6. return args[index];
  7. });
  8. };

  掉用format('And the %1 want to know whose %2 you %3', 'papers', 'shirt', 'wear');结果为"And the papers want to know whose shirt you wear";控制台打印为

  %1&1&8&And the %1 want to know whose %2 you %3

  %2&2&30&And the %1 want to know whose %2 you %3

  %3&3&37&And the %1 want to know whose %2 you %3

把arguments对象转换成一个真正的数组

  虽然arguments对象不是一个真正的javascript数组,但是我们还是可以轻易的把它转换成标准的数据 ,然后进行数组操作。

  var args = Array.prototype.slice.call(arguments);

  那么现在这个变量args就含有一个含有函数所有参数的标准javascript数组对象。

拓展:使用上一节的format函数,通过预置的arguments对象创建函数

  1. function makeFunc() {
  2. var args = Array.prototype.slice.call(arguments);
  3. var func = args.shift();
  4. return function() {
  5. return func.apply(null, args.concat(Array.prototype.slice.call(arguments)));
  6. };
  7. }

  该方法会将第一个参数取出来,然后返回一个curry化函数,该curry化函数的参数(第二个arguments)将和makeFunc的从第二个参数开始的参数组合成新数组。并返回makeFunc第一个参数的apply调用

  执行

  1. var majorTom = makeFunc(format, "This is Major Tom to ground control. I’m %1.");
  2. majorTom("stepping through the door");

  结果为:"This is Major Tom to ground control. I’m stepping through the door."

  控制台打印:%1&1&41&This is Major Tom to ground control. I’m %1.

 [function.]arguments.callee

  说明:arguments.callee方法返回的是正在执行的函数本身。

  callee 属性是 arguments 对象的一个成员,它表示对函数对象本身的引用,这有利于匿名函数的递归或者保证函数的封装性,例如下边示例的递归计算1到n的自然数之和。而该属性仅当相关函数正在执行时才可用。还有需要注意的是callee拥有length属性,这个属性有时候用于验证还是比较好的。arguments.length是实参长度,arguments.callee.length是形参(定义时规定的需要的参数)长度,由此可以判断调用时形参长度是否和实参长度一致。

  1. //用于验证参数
  2. function calleeLengthDemo(arg1, arg2) {
  3. if (arguments.length==arguments.callee.length) {
  4. window.alert("验证形参和实参长度正确!");
  5. return;
  6. } else {
  7. alert("实参长度:" +arguments.length);
  8. alert("形参长度: " +arguments.callee.length);
  9. }
  10. }
  11.  
  12. //递归计算
  13. var sum = function(n){
  14. if (n <= 0) return 1;
  15. else return n arguments.callee(n - 1)
  16. }
  17.  
  18. //比较一般的递归函数:
  19. var sum = function(n){
  20. if (1==n) return 1;
  21. else return n + sum (n-1);
  22. }

  调用时:alert(sum(100));其中函数内部包含了对sum自身的引用,函数名仅仅是一个变量名,在函数内部调用sum即相当于调用一个全局变量,不能很好的体现出是调用自身,这时使用callee会是一个比较好的方法。

拓展 functionName.caller 

  说明: 返回是谁调用了functionName 函数。functionName 对象是所执行函数的名称。对于函数来说,caller 属性只有在函数执行时才有定义。如果函数是由顶层调用的,那么 caller 包含的就是 null 。如果在字符串上下文中使用 caller 属性,那么结果和 functionName.toString 一样,也就是说,显示的是函数的反编译文本。 下面的例子说明了 caller 属性的用法:

  1. // caller demo {
  2. function callerDemo() {
  3. if (callerDemo.caller) {
  4. var a= callerDemo.caller.toString();
  5. alert(a);
  6. } else {
  7. alert("this is a top function");
  8. }
  9. }
  10.  
  11. function handleCaller() {
  12. callerDemo();
  13. }
  14.  
  15. handleCaller();

  执行结果:

  

  

c.undefined和null


  大多数计算机语言,有且仅有一个表示"无"的值,比如,C语言的NULL,Java语言的null,Python语言的none,Ruby语言的nil。有点奇怪的是,JavaScript语言居然有两个表示"无"的值:undefined和null。这是为什么?

相似性
  在JavaScript中,将一个变量赋值为undefined或null,老实说,几乎没区别。

  代码如下:

  1. var a = undefined;
  2. var a = null;

  上面代码中,a变量分别被赋值为undefined和null,这两种写法几乎等价。

  undefined和null在if语句中,都会被自动转为false,相等运算符甚至直接报告两者相等。

  1. if (!undefined)
  2. console.log('undefined is false');
  3. // undefined is false
  4.  
  5. if (!null)
  6. console.log('null is false');
  7. // null is false
  8.  
  9. undefined == null
  10. // true

  上面代码说明,两者的行为是何等相似!但是我们去查看undefined和null的各自的类型却发现类型是不同的。js基础类型中没有null类型

  1. typeof null;//"object"
  2. typeof undefined;//"undefined"

  既然undefined和null的含义与用法都差不多,为什么要同时设置两个这样的值,这不是无端增加JavaScript的复杂度,令初学者困扰吗?Google公司开发的JavaScript语言的替代品Dart语言,就明确规定只有null,没有undefined!

历史原因

  原来,这与JavaScript的历史有关。1995年JavaScript诞生时,最初像Java一样,只设置了null作为表示"无"的值。

  根据C语言的传统,null被设计成可以自动转为0。

  1. Number(null) //
  2.  
  3. 5 + null //

  但是,JavaScript的设计者Brendan Eich,觉得这样做还不够,有两个原因。

  首先,null像在Java里一样,被当成一个对象。

  1. typeof null // "object"

  但是,JavaScript的数据类型分成原始类型(primitive)和合成类型(complex)两大类,Brendan Eich觉得表示"无"的值最好不是对象。

  其次,JavaScript的最初版本没有包括错误处理机制,发生数据类型不匹配时,往往是自动转换类型或者默默地失败。Brendan Eich觉得,如果null自动转为0,很不容易发现错误。因此,Brendan Eich又设计了一个undefined。

最初设计

  JavaScript的最初版本是这样区分的:null是一个表示"无"的对象,转为数值时为0;undefined是一个表示"无"的原始值,转为数值时为NaN。

  1. Number(undefined) // NaN
  2. 5 + undefined // NaN

目前的用法

  但是,上面这样的区分,在实践中很快就被证明不可行。目前,null和undefined基本是同义的,只有一些细微的差别。

  null表示"没有对象",即该处不应该有值。典型用法是:

  (1) 作为函数的参数,表示该函数的参数不是对象。

  (2) 作为对象原型链的终点。

  1. Object.getPrototypeOf(Object.prototype) // null

  undefined表示"缺少值",就是此处应该有一个值,但是还没有定义。典型用法是:

  (1)变量被声明了,但没有赋值时,就等于undefined。

  (2) 调用函数时,应该提供的参数没有提供,该参数等于undefined。

  (3)对象没有赋值的属性,该属性的值为undefined。

  (4)函数没有返回值时,默认返回undefined。

  1. var i;
  2. i // undefined
  3.  
  4. function f(x){console.log(x)}
  5. f() // undefined
  6.  
  7. var o = new Object();
  8. o.p // undefined
  9.  
  10. var x = f();
  11. x // undefined

  上面的文章部分是摘自网上的文章记录下的古老笔记,记录的时候没有注明出处现在也不好找了,如果某大牛路过发现里面包含您写的博文,请在评论中注明出处,本人补上,谢谢。

  

  如果觉得本文不错,请点击右下方【推荐】!

js基础篇——call/apply、arguments、undefined/null的更多相关文章

  1. 前端面试题目汇总摘录(JS 基础篇)

    JS 基础 JavaScript 的 typeof 返回那些数据类型 object number function boolean undefined string typeof null; // o ...

  2. JS基础篇--sort()方法的用法,参数以及排序原理

    JS基础篇--sort()方法的用法,参数以及排序原理   sort() 方法用于对数组的元素进行排序,并返回数组.默认排序顺序是根据字符串Unicode码点.语法:arrayObject.sort( ...

  3. 前端面试题目汇总摘录(JS 基础篇 —— 2018.11.02更新)

    温故而知新,保持空杯心态 JS 基础 JavaScript 的 typeof 返回那些数据类型 object number function boolean undefined string type ...

  4. 前端之js基础篇

    JavaScript概述 ECMAScript和JavaScript的关系 1996年11月,JavaScript的创造者--Netscape公司,决定将JavaScript提交给国际标准化组织ECM ...

  5. js基础篇string&&array(应YX同学面试复习要求 - -)

    js中的数据类型一共有五个基本数据类型,分别是undefined,null,boolean,number,string. js中的Object类型中包括两大类型:Function类型和array类型. ...

  6. js 基础篇(点击事件轮播图的实现)

    轮播图在以后的应用中还是比较常见的,不需要多少行代码就能实现.但是在只掌握了js基础知识的情况下,怎么来用较少的而且逻辑又简单的方法来实现呢?下面来分析下几种不同的做法: 1.利用位移的方法来实现 首 ...

  7. Vue.js基础篇实战--一个ToDoList小应用

    距离开始学Vue已经过去一个多月了,总想把学到的东西柔和在一起,做点东西出来,于是有了这个Todolist小应用. 使用vuex 纯粹基础,没有用到web pack,vuex,npm,下次把它改造一下 ...

  8. JS基础 —— call、apply 和 bind

    函数的三个原型方法 作用:改变this指向 call MDN:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Glo ...

  9. JS基础篇之作用域、执行上下文、this、闭包

    前言:JS 的作用域.执行上下文.this.闭包是老生常谈的话题,也是新手比较懵懂的知识点.当然即便你作为老手,也未必真的能理解透彻这些概念. 一.作用域和执行上下文 作用域: js中的作用域是词法作 ...

随机推荐

  1. java servlet之过滤器1(解决jsp之间POST方式数据传递乱码)

    首先,看看没有解决乱码的效果,新建两个jsp页面(a.jsp跳转到b.jsp). <form action="b.jsp" method="post"&g ...

  2. ORACLE10g数据库字符集设置和客户端字符集设置不一致问题

    在家里自己电脑上又重新安装了Oracle 10g和PLSQL Developer,装完后启动PLSQL Developer,弹出如下错误信息: 解决方案: 在Windows运行命令行中输入regedi ...

  3. 必应词典UWP版-开发小结

    摘要 必应词典UWP版已经上线2周了!相信有不少用户都已经体验过了吧!得益于Win10全新.强大的API,新版词典在性能上.UI体验上都有了大幅的提升,今天,小编就为大家讲讲必应词典UWP开发的故事. ...

  4. 【吉光片羽】之 Web API

    1.在asp项目中直接添加apiController,需要新增Global.asax文件.再增加一个webapiConfig,如果需要访问方式为"api/{controller}/{acti ...

  5. angular ng-model类型格式转化

    在angular开发中我们经常会遇见输入框中的string的值,却想在scope上的model表现为整型.浮点.货币,或者在radio的value是一个true,false的Boolean类型,一组c ...

  6. iOS——Core Animation 知识摘抄(二)

    阴影 主要是shadowOpacity .shadowColor.shadowOffset和shadowRadius四个属性 shadowPath属性 我们已经知道图层阴影并不总是方的,而是从图层内容 ...

  7. SignalR + KnockoutJS + ASP.NET MVC4 实现井字游戏

    1.1.1 摘要 今天,我们将使用SignalR + KnockoutJS + ASP.NET MVC实现一个实时HTML5的井字棋游戏. 首先,网络游戏平台一定要让用户登陆进来,所以需要一个登陆模块 ...

  8. Git bash 配置ssh key

    问题描述 昨天为了配置Qt create中的Git,把我一直在使用的Github删除了,今本以为,这样git的一些配置还在,可是,今天上传一些提交的时候,提示我,git没有密钥.梳理一下,这个简单的配 ...

  9. 知方可补不足~sqlserver中使用sp_who查看sql的进程

    回到目录 在SQLSERVER中每个会话,即每个查询分析器窗口都会产生一个SQL进程,对于那些持续时间短的进程,它们转瞬即失,而对于持续时间比较长的,我们需要希望查看它的运行状态,就可以借助SQL提供 ...

  10. Java程序员的日常 —— 多进程开发

    最近再弄进程管理相关的工作,因此必要的就涉及到各种系统下关于进程的管理. 这里简单的介绍下: 如何在Java中执行命令 在windows下肯定是dos命令了,而在linux则为shell命令.执行的方 ...