js基础篇——call/apply、arguments、undefined/null

a.call和apply方法详解


call方法: 

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

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

  说明: call 方法能够用来代替另外一个对象调用一个方法。call 方法可将一个函数的对象上下文从初始的上下文改变为由 thisObj 指定的新对象。若是没有提供 thisObj 参数,那么 Global 对象被用做 thisObj。 程序员

 

apply方法: 数组

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

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

  说明:若是 argArray 不是一个有效的数组或者不是 arguments 对象,那么将致使一个 TypeError。若是没有提供 argArray 和 thisObj 任何一个参数,那么 Global 对象将被用做 thisObj, 而且没法被传递任何参数。学习

 

实例学习:this

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

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

 

复制代码
function Animal(){ this.name = "Animal"; this.showName = function(){ alert(this.name);} } function Cat(){ this.name = "Cat"; } var animal = new Animal(); var cat = new Cat(); animal.showName.call(cat,",");//输出结果为"Cat" animal.showName.apply(cat,[]);//输出结果为"Cat"
复制代码

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

 

实现继承

复制代码
function Animal(name){ this.name = name; this.showName = function(){ alert(this.name);} } function Cat(name){ Animal.call(this, name); } var cat = new Cat("Black Cat"); cat.showName();
复制代码

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

         拓展:多重继承

复制代码
function Class10(){ this.showSub = function(a,b){ alert(a-b); } } function Class11(){ this.showAdd = function(a,b){ alert(a+b); } } function Class2(){ Class10.call(this); Class11.call(this); }
复制代码

  备注: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库里有个格式化的函数,展现了这个灵活性。

复制代码
function format(string) { var args = arguments; var pattern = new RegExp('%([1-' + arguments.length + '])', 'g'); return String(string).replace(pattern, function(match, index,position,all) { console.log(match + '&' + index + '&' + position + '&' + all); return args[index]; }); };
复制代码

  掉用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对象建立函数

复制代码
 function makeFunc() { var args = Array.prototype.slice.call(arguments); var func = args.shift(); return function() { return func.apply(null, args.concat(Array.prototype.slice.call(arguments))); }; }
复制代码

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

  执行

var majorTom = makeFunc(format, "This is Major Tom to ground control. I’m %1."); 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是形参(定义时规定的须要的参数)长度,由此能够判断调用时形参长度是否和实参长度一致。

复制代码
//用于验证参数 function calleeLengthDemo(arg1, arg2) { if (arguments.length==arguments.callee.length) { window.alert("验证形参和实参长度正确!"); return; } else { alert("实参长度:" +arguments.length); alert("形参长度: " +arguments.callee.length); } } //递归计算 var sum = function(n){ if (n <= 0) return 1; else return n +arguments.callee(n - 1) } //比较通常的递归函数: var sum = function(n){ if (1==n) return 1; else return n + sum (n-1); }
复制代码

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

 

拓展 functionName.caller 

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

复制代码
// caller demo { function callerDemo() { if (callerDemo.caller) { var a= callerDemo.caller.toString(); alert(a); } else { alert("this is a top function"); } } function handleCaller() { callerDemo(); } handleCaller();
复制代码

  执行结果:

  

  

 c.undefined和null


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

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

  代码以下:

var a = undefined; var a = null;

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

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

复制代码
if (!undefined) console.log('undefined is false'); // undefined is false if (!null) console.log('null is false'); // null is false  undefined == null // true
复制代码

  上面代码说明,二者的行为是何等类似!可是咱们去查看undefined和null的各自的类型却发现类型是不一样的。js基础类型中没有null类型

typeof null;//"object" typeof undefined;//"undefined"

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

 

历史缘由

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

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

Number(null) // 0 5 + null // 5

  可是,JavaScript的设计者Brendan Eich,以为这样作还不够,有两个缘由。

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

typeof null // "object"

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

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

 

最初设计

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

Number(undefined)  // NaN 5 + undefined // NaN

 

目前的用法

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

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

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

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

Object.getPrototypeOf(Object.prototype)  // null

  undefined表示"缺乏值",就是此处应该有一个值,可是尚未定义。典型用法是:

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

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

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

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

复制代码
var i; i // undefined function f(x){console.log(x)} f() // undefined var o = new Object(); o.p // undefined var x = f(); x // undefined
复制代码
相关文章
相关标签/搜索