JS中call/apply、arguments、undefined/null方法详解


Posted in Javascript onFebruary 15, 2016

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, 并且无法被传递任何参数。

实例学习:

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 对象的引用。

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 应该是 Cat

实现继承

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();

执行结果:

JS中call/apply、arguments、undefined/null方法详解

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

以上所述是小编给大家介绍的JS中call/apply、arguments、undefined/null方法详解,希望对大家有所帮助。

Javascript 相关文章推荐
使Ext的Template可以解析二层的json数据的方法
Dec 22 Javascript
javascript firefox不显示本地预览图片问题的解决方法
Nov 12 Javascript
js单向链表的具体实现实例
Jun 21 Javascript
jQuery实现图片左右滚动特效
Apr 20 Javascript
基于JavaScript实现文字超出部分隐藏
Feb 29 Javascript
完美解决jQuery符号$与其他javascript 库、框架冲突的问题
Aug 09 Javascript
基于JS实现发送短信验证码后的倒计时功能(无视页面刷新,页面关闭不进行倒计时功能)
Sep 02 Javascript
JS图片放大效果简单实现代码
Sep 08 Javascript
基于node.js依赖express解析post请求四种数据格式
Feb 13 Javascript
Vue原理剖析 实现双向绑定MVVM
May 03 Javascript
jQuery实现每隔一段时间自动更换样式的方法分析
May 03 jQuery
angular 组件通信的几种实现方式
Jul 13 Javascript
谷歌showModalDialog()方法不兼容出现对话窗口的解决办法
Feb 15 #Javascript
仅30行代码实现Javascript中的MVC
Feb 15 #Javascript
理解javascript中的with关键字
Feb 15 #Javascript
使用基于Node.js的构建工具Grunt来发布ASP.NET MVC项目
Feb 15 #Javascript
JavaScript模版引擎的基本实现方法浅析
Feb 15 #Javascript
在ASP.NET MVC项目中使用RequireJS库的用法示例
Feb 15 #Javascript
一道常被人轻视的web前端常见面试题(JS)
Feb 15 #Javascript
You might like
详解PHP中的状态模式编程
2015/08/11 PHP
php开发时容易忘记的一些技术细节
2016/02/03 PHP
PHP查询大量数据内存耗尽问题的解决方法
2016/10/28 PHP
解决PHP使用CURL发送GET请求时传递参数的问题
2019/10/11 PHP
PHP $O00OO0=urldecode &amp; eval 解密,记一次商业源码的去后门
2020/09/13 PHP
(仅IE下有效)关于checkbox 三态
2007/05/12 Javascript
Javascript 类与静态类的实现
2010/04/01 Javascript
JS操作iframe里的dom(实例讲解)
2014/01/29 Javascript
Js可拖拽放大的层拖动特效实现方法
2015/02/25 Javascript
javascript关于运动的各种问题经典总结
2015/04/27 Javascript
jQuery搜索框效果实现代码(百度关键词联想)
2021/02/25 Javascript
jQuery实现侧浮窗与中浮窗切换效果的方法
2016/09/05 Javascript
JS匿名函数实例分析
2016/11/26 Javascript
详解JS中的柯里化(currying)
2017/08/17 Javascript
jQuery 1.9版本以上的浏览器判断方法代码分享
2017/08/28 jQuery
JS笛卡尔积算法与多重数组笛卡尔积实现方法示例
2017/12/01 Javascript
vue实现鼠标移入移出事件代码实例
2019/03/27 Javascript
利用JavaScript将Excel转换为JSON示例代码
2019/06/14 Javascript
微信小程序使用车牌号输入法的示例代码
2019/08/20 Javascript
[00:31]DOTA2上海特级锦标赛 Fnatic战队宣传片
2016/03/04 DOTA
pyqt4教程之widget使用示例分享
2014/03/07 Python
Python 给屏幕打印信息加上颜色的实现方法
2019/04/24 Python
python爬虫豆瓣网的模拟登录实现
2019/08/21 Python
余弦相似性计算及python代码实现过程解析
2019/09/18 Python
python scatter函数用法实例详解
2020/02/11 Python
python获取linux系统信息的三种方法
2020/10/14 Python
英语求职信范文
2014/05/23 职场文书
重阳节标语大全
2014/10/07 职场文书
走群众路线学习心得体会
2014/10/31 职场文书
会计求职简历自我评价
2015/03/10 职场文书
敬老院志愿者活动总结
2015/05/06 职场文书
假期读书倡议书3篇
2019/08/19 职场文书
html+css 实现简易导航栏功能
2021/04/07 HTML / CSS
Golang连接并操作MySQL
2022/04/14 MySQL
Win11开始菜单添加休眠选项
2022/04/19 数码科技
SQL中去除重复数据的几种方法汇总(窗口函数对数据去重)
2023/05/08 MySQL