[Effective JavaScript 笔记]第29条:避免使用非标准的栈检查属性
许多js环境都提供检查调用栈的功能。调用栈是指当前正在执行的活动函数链。在某些旧的宿主环境中,每个arguments对象含有两个额外的属性:arguments.callee和arguments.caller。前者指向使用该arguments对象被调用的函数。后者指向调用该arguments对象被调用的函数的函数。许多环境支持arguments.callee,但它除了允许匿名函数递归地引用自身之外,没有更多的用途了。(高3中认为使用arguments.callee可以解除函数体内的代码和函数名之间的耦合,看来也不是完全没有用的)
图示
下面是一个简单的图示,可以容易了解arguments的callee,caller,及函数的caller
var factorial=(function(n){
return (n<=1)?1:(n*arguments.callee(n-1));
})
但这个也是特别的有用,可以使用函数名来引用函数自身
function factorial(n){
return (n<=1)?1:(n*factorial(n-1));
}
arguments.caller属性更为强大。它指向的是使用该arguments对象调用函数的函数。出于安全考虑,大多数环境已经移除了此特性,因此用它时要检测一下才行。许多JS环境也提供了一个相似的函数对象属性--非标准但普遍适应的caller属性。它指向函数最近的调用者。
function revealCaller(){
return revealCaller.caller;
}
function start(){
return revealCaller();
}
start()===start;//true;
可以利用该属性获取一个提供当前调用栈快照的数据结构。构建一个栈跟踪:
function getCallStack(){
var stack=[];
for(var f=getCallStack.caller;f;f=f.caller){
stack.push(f);
}
return stack;
}
使用示例
function f1(){
return getCallStack();
}
function f2(){
return f1();
}
var trace=f2();//[f1(), f2()]
脆弱性,当某个函数在调用栈中出现不止一次,那么栈检查逻辑将会陷入循环。
function f(n){
return n===0?getCallStack():f(n-1);
}
var trace=f(1);//
问题出在哪?由于函数f递归地调用其自身,因此其caller属性会自动更新,指回到函数f。所以,函数getCallStack会陷入无限地查找函数f的循环之中。即使我们试图检测该循环,但在函数f调用其自身之前也没有关于哪个函数调用了它的信息。因为其他调用栈的信息已经丢失了。
这些栈检查属性都是非标准的,在移植性或适用性上很受限制。在ES5的严格模式的函数中,它们是被禁止使用的。试图获取严格函数或arguments对象的caller或callee属性都将报错。
function f(){
'use strict';
return f.caller;
}
f();//Uncaught TypeError: 'caller' and 'arguments' are restricted function properties and cannot be accessed in this context.(…)
最好的策略是完全避免栈检查。如果检查栈的理由完全是为了测试,那么更为可靠的方式是使用交互式的调试器。
提示
避免使用非标准的arguments.caller和arguments.callee属性,它们不具备良好的移植性
避免使用非标准的函数对象caller属性,因为在包含全部栈信息方面,它是不可靠的
附录:这个没附录,放水一篇,因为这节实在没什么可写的。
[Effective JavaScript 笔记]第29条:避免使用非标准的栈检查属性的更多相关文章
- [Effective JavaScript 笔记]第40条:避免继承标准类
ECMAScript标准库里配备了许多重要的类,如Array,function,以及Date等.扩展这些类生成子类可以方便完成很多工作,但它们的定义具有很多特殊的行为,所以很难写出行为正确的类. Ar ...
- [Effective JavaScript 笔记] 第4条:原始类型优于封闭对象
js有5种原始值类型:布尔值.数字.字符串.null和undefined. 用typeof检测一下: typeof true; //"boolean" typeof 2; //&q ...
- [Effective JavaScript 笔记] 第5条:避免对混合类型使用==运算符
“1.0e0”=={valueOf:function(){return true;}} 是值是多少? 这两个完全不同的值使用==运算符是相等的.为什么呢?请看<[Effective JavaSc ...
- [Effective JavaScript 笔记]第27条:使用闭包而不是字符串来封装代码
函数是一种将代码作为数据结构存储的便利方式,代码之后可以被执行.这使得富有表现力的高阶函数抽象如map和forEach成为可能.它也是js异步I/O方法的核心.与此同时,也可以将代码表示为字符串的形式 ...
- [Effective JavaScript 笔记]第28条:不要信赖函数对象的toString方法
js函数有一个非凡的特性,即将其源代码重现为字符串的能力. (function(x){ return x+1 }).toString();//"function (x){ return x+ ...
- [Effective JavaScript 笔记]第15条:当心局部块函数声明笨拙的作用域
嵌套函数声明.没有标准的方法在局部块里声明函数,但可以在另一个函数的顶部嵌套函数声明. function f(){return "global"} function test(x) ...
- [Effective JavaScript 笔记]第68条:使用promise模式清洁异步逻辑
构建异步API的一种流行的替代方式是使用promise(有时也被称为deferred或future)模式.已经在本章讨论过的异步API使用回调函数作为参数. downloadAsync('file.t ...
- [Effective JavaScript 笔记]第46条:使用数组而不要使用字典来存储有序集合
对象属性无序性 js对象是一个无序属性集合. var obj={}; obj.a=10; obj.b=30; 属性a和属性b并没有谁前谁后之说.for...in循环,先输出哪个属性都有可能.获取和设置 ...
- [Effective JavaScript 笔记]第45条:使用hasOwnProperty方法以避免原型污染
之前的43条,44条讨论了属性的枚举,但都没有彻底地解决属性查找中原型污染的问题.看下面关于字典的一些操作 'zhangsan' in dict; dict.zhangsan; dict.zhangs ...
随机推荐
- 第一章 OO大智慧
今天,正式开始读王涛写的<你必须知道的.NET(第二版)>,刚开始读了序,觉得写的相当精彩,就被吸引住了.看了一会发现本书的特点可能就是以例举例,形象生动,比较期待的样子.虽然前面讲的概念 ...
- [c#基础]DataTable的Select方法
引言 可以说DataTable存放数据的一个离线数据库,将数据一下加载到内存,而DataReader是在线查询,而且只进形式的查询,如果后退一步,就不可能了,DataTable操作非常方便,但也有缺点 ...
- “耐撕”团队记账本 剧透
β发布之后,我们团队开始fork"OneZero"团队的记账本程序.我们在原来的基础上添加了以下功能: 下面是我们团队记账本程序演示的视频:http://v.youku.com/v ...
- 小菜鸟学 MQ(一)
第一步: 从http://activemq.apache.org/ 下载相关文件. apache-activemq-5.8.0-bin.zip 解压到指定目录下. 第二步: cmd 下切换到 mq ...
- javascript 规范
关于变量及方法等的命名,没有硬性规定,但是为了规范,遵循一些约定还是有必要的. 变量定义: 用var 关键字将要使用的变量定义在代码开头,变量间用分号隔开. 原因有二: 一是便于理解,知道下面的代码会 ...
- 【HDU 2160】母猪的故事
题 Description 话说现在猪肉价格这么贵,著名的ACBoy 0068 也开始了养猪生活.说来也奇怪,他养的猪一出生第二天开始就能每天中午生一只小猪,而且生下来的竟然都是母猪. 不过光生小猪也 ...
- Struts2的使用以及Spring整合Struts2
一.如何单独使用Struts2 (1)引入struts2的jar包 commons-fileupload-1.2.1.jar freemarker-2.3.15.jar ognl-2.7.3.jar ...
- POJ3749 破译密码
Description 据说最早的密码来自于罗马的凯撒大帝.消息加密的办法是:对消息原文中的每个字母,分别用该字母之后的第5个字母替换(例如:消息原文中的每个字母A都分别替换成字母F).而你要获得消息 ...
- WPF中嵌入Office编辑器(支持Word、Excel、PPT、Visio等)
现在有一个项目,需要使用wpf做一个简单的客户端,用来生成word.excel.ppt.visio等文档,这就需要能够在wpf中嵌入office的编辑器,并对office文档进行编辑. 在网上搜索了一 ...
- 字符串匹配的KMP算法详解及C#实现
字符串匹配是计算机的基本任务之一. 举例来说,有一个字符串"BBC ABCDAB ABCDABCDABDE",我想知道,里面是否包含另一个字符串"ABCDABD" ...