浅谈arguments属性callee
1.首先 arguments 是一个对应于传递给函数的参数的类数组对象
2. arguments.callee 属性包含当前正在执行的函数。
描述
callee 是 arguments 对象的一个属性。它可以用于引用该函数的函数体内当前正在执行的函数。这在函数的名称是未知时很有用,例如在没有名称的函数表达式 (也称为“匿名函数”)内。
警告:在严格模式下,第5版 ECMAScript (ES5) 禁止使用 arguments.callee()。当一个函数必须调用自身的时候, 避免使用 arguments.callee(), 通过要么给函数表达式一个名字,要么使用一个函数声明.
为什么 arguments.callee 从ES5严格模式中删除了?
(改编自 a Stack Overflow answer by olliej)
早期版本的 JavaScript不允许使用命名函数表达式,出于这样的原因, 你不能创建一个递归函数表达式。
例如,下边这个语法就是行的通的:
function factorial (n) {
return !(n > 1) ? 1 : factorial(n - 1) * n;
}
[1,2,3,4,5].map(factorial);
但是:
[1,2,3,4,5].map(function (n) {
return !(n > 1) ? 1 : /* what goes here? */ (n - 1) * n;
});
这个不行。为了解决这个问题, arguments.callee 添加进来了。然后你可以这么做
[1,2,3,4,5].map(function (n) {
return !(n > 1) ? 1 : arguments.callee(n - 1) * n;
});
然而,这实际上是一个非常糟糕的解决方案,因为这 (以及其它的 arguments, callee, 和 caller 问题) 使得在通常的情况(你可以通过调试一些个别例子去实现它,但即使最好的代码也是次优选项,因为(JavaScript 解释器)做了不必要的检查)不可能实现内联和尾递归。另外一个主要原因是递归调用会获取到一个不同的 this 值,例如:
var global = this;
var sillyFunction = function (recursed) {
if (!recursed) { return arguments.callee(true); }
if (this !== global) {
alert("This is: " + this);
} else {
alert("This is the global");
}
}
sillyFunction();
ECMAScript 3 通过允许命名函数表达式解决这些问题。例如:
[1,2,3,4,5].map(function factorial (n) {
return !(n > 1) ? 1 : factorial(n-1)*n;
});
这有很多好处:
- 该函数可以像代码内部的任何其他函数一样被调用
- 它不会在外部作用域中创建一个变量 (除了 IE 8 及以下)
- 它具有比访问arguments对象更好的性能
------------------------------------------------------上面没看懂的话, 看下这个:
在函数内部,有两个特殊的对象:arguments 和 this。其中, arguments 的主要用途是保存函数参数, 但这个对象还有一个名叫 callee 的属性,该属性是一个指针,指向拥有这个 arguments 对象的函数。 请看下面这个非常经典的阶乘函数

function factorial(num){
if (num <=1) {
return 1;
} else {
return num * factorial(num-1)
}
}

定义阶乘函数一般都要用到递归算法;如上面的代码所示,在函数有名字,而且名字以后也不会变 的情况下,这样定义没有问题。但问题是这个函数的执行与函数名 factorial 紧紧耦合在了一起。为 了消除这种紧密耦合的现象,可以像下面这样使用 arguments.callee

function factorial(num){
if (num <=1) {
return 1;
} else {
return num * arguments.callee(num-1);
}
}

在这个重写后的 factorial()函数的函数体内,没有再引用函数名 factorial。这样,无论引用 函数时使用的是什么名字,都可以保证正常完成递归调用。例如

function factorial(num){
if(num <= 1){
return 1;
}else{
return num * arguments.callee(num-1);
}
}
var trueFactorial = factorial;
alert(trueFactorial(5)); //120
factorial = function() {
return 0;
}
alert(trueFactorial(5));// 120 如果没有使用arguments.callee,将返回0

在此,变量 trueFactorial 获得了 factorial 的值,实际上是在另一个位置上保存了一个函数 的指针。然后,我们又将一个简单地返回 0的函数赋值给 factorial 变量。如果像原来的 factorial() 那样不使用 arguments.callee,调用 trueFactorial()就会返回 0。可是,在解除了函数体内的代 码与函数名的耦合状态之后,trueFactorial()仍然能够正常地计算阶乘;至于 factorial(),它现 在只是一个返回 0的函数。
参考自js高程第三版
现在已经不推荐使用arguments.callee();
原因:访问 arguments 是个很昂贵的操作,因为它是个很大的对象,每次递归调用时都需要重新创建。影响现代浏览器的性能,还会影响闭包。
不能用怎么办?
像第三段中的例子,重写 factorial()方法导致trueFactorial()结果不在预期。是为了演示而做的。平时写代码应该避免。
递归时用到arguments.callee()是常见的事情,比如
一道面试题。接受参数n=5,不用for循环输出数组【1,2,3,4,5】
这用递归的思路,配合arguments.callee,代码如下

function show(n) {
var arr = [];
return (function () {
arr.unshift(n);
n--;
if (n != 0) {
arguments.callee();
}
return arr;
})()
}
show(5)//[1,2,3,4,5]

现在arguments.callee 被弃用了。怎么办,其实很简单,给内部函数一个名字即可

function show(n) {
var arr = [];
return (function fn() {
arr.unshift(n);
n--;
if (n != 0) {
fn();
}
return arr;
})()
}
show(5)//[1,2,3,4,5]

参考地址:https://www.cnblogs.com/lijinwen/p/5727550.html
mdn : https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Functions/arguments/callee
浅谈arguments属性callee的更多相关文章
- Abp vNext 番外篇-疑难杂症丨浅谈扩展属性与多用户设计
说明 Abp vNext基础篇的文章还差一个单元测试模块就基本上完成了我争取10.1放假之前给大家赶稿出来,后面我们会开始进阶篇,开始拆一些东西,具体要做的事我会单独开一个文章来讲 缘起 本篇文章缘起 ...
- 浅谈arguments与arguments的妙用
1.每个函数都有一个arguments属性,表示函数的实参集合,这里的实参是重点,就是执行函数时实际传入的参数的集合. 2.arguments不是数组而是一个对象,但它和数组很相似,所以通常称为类数组 ...
- 浅谈title属性与alt属性
XHTML是CSS布局的基础,webjx.com一直强调XHTML知识的学习,重视语义和文档的结构.title 和alt 属性,给我最直观的感受就是,可以提高文档的适应性,并合理提高关键词密度.在XH ...
- 浅谈WPF依赖项属性
浅谈WPF依赖项属性 0. 引言 依赖项属性虽然在使用上和CLR属性一样,但是它是WPF特有的,不同于CLR属性.只是封装为我们常用CLR的属性,在语法使用上和CLR属性一样.WPF中一些功能:动画, ...
- $.ajax()方法详解 ajax之async属性 【原创】详细案例解剖——浅谈Redis缓存的常用5种方式(String,Hash,List,set,SetSorted )
$.ajax()方法详解 jquery中的ajax方法参数总是记不住,这里记录一下. 1.url: 要求为String类型的参数,(默认为当前页地址)发送请求的地址. 2.type: 要求为Str ...
- 浅谈CSS3中display属性的Flex布局
浅谈CSS3中display属性的Flex布局 最近在学习微信小程序,在设计首页布局的时候,新认识了一种布局方式display:flex 1 .container { 2 display: fle ...
- CSS属性中的display属性浅谈;
首先我们要知道什么是块级元素和行内元素有什么区别: 承接上篇文章:(浅谈HTML和body标签) 块级元素:浏览器解析为独占一行的元素(例如:div.table.ul等.),浏览器会在该元素的前后显示 ...
- 浅谈Vue中计算属性(computed)和方法(methods)的差别
浅谈Vue中计算属性(computed)和方法(methods)的差别 源码地址 methods方法和computed计算属性,两种方式的最终结果确实是完全相同 计算属性是基于它们的响应式依赖进行缓存 ...
- 浅谈JS严格模式
浅谈JS严格模式 简介 何为严格模式?严格模式(strict mode)即在严格的条件下运行,在严格模式下,很多正常情况下不会报错的问题语句,将会报错并阻止运行. 但是,严格模式可以显著提高代码的健壮 ...
随机推荐
- 假设检验的python实现命令——Z检验、t检验、F检验
Z检验 statsmodels.stats.weightstats.ztest() import statsmodels.stats.weightstats as sw 参数详解: x1:待检验数据集 ...
- Net6 Configuration & Options 源码分析 Part2 Options
Net6 Configuration & Options 源码分析 Part2 Options 第二部分主要记录Options 模型 OptionsConfigurationServiceCo ...
- sqlserver 中,如何将getdate()时间的时分秒固定为00:00:00或者忽略不要
在使用getdate()时,时间会实时刷新,那么我们就要再查询的时候就需要精确到毫秒后三位,非常难受,那么为了解决这个问题我们可以通过以下几种方法进行固定或者去掉毫秒 1.将毫秒固定为00:00:00 ...
- Docker重要容器命令
镜像下载.域名解析.时间同步请点击 阿里云开源镜像站 容器重要命令 启动守护式容器 docker run -d 镜像 docker run -d image [command][arg...] 使用c ...
- Flask 之 蓝图
蓝图,听起来就是一个很宏伟的东西 在Flask中的蓝图 blueprint 也是非常宏伟的 它的作用就是将 功能 与 主服务 分开怎么理解呢? 比如说,你有一个客户管理系统,最开始的时候,只有一个查看 ...
- sqlmap的常用tamper脚本
sqlmap下的tamper目录存放绕过WAF脚本 使用方法 --tamper 脚本名称,脚本名称 多个tamper脚本之间用空格隔开 apostrophemask.py 用utf8代替引号 equa ...
- Flutter入门教程(一)Flutter简介
这是Flutter系列第一篇文章,后续会持续更新Flutter相关知识,本篇就主要对于Flutter技术做一个简单的入门介绍 一.Flutter简介 Flutter是谷歌的移动UI框架,可以快速在iO ...
- Redis Cluster 集群搭建与扩容、缩容
说明:仍然是伪集群,所有的Redis节点,都在一个服务器上,采用不同配置文件,不同端口的形式实现 前提:已经安装好了Redis,本文的redis的版本是redis-6.2.3 Redis的下载.安装参 ...
- width:auto 和 width:100%有什么区别
width:auto 和 width:100%有什么区别 宽度计算不同 <div class="parent"> <span class="child& ...
- 为什么等待和通知是在 Object 类而不是 Thread 中声明的?
一个棘手的 Java 问题,如果 Java编程语言不是你设计的,你怎么能回答这个问题呢.Java编程的常识和深入了解有助于回答这种棘手的 Java 核心方面的面试问题.为什么 wait,notify ...