arguments
arguments 本身是一个类数组
- 类数组
- 拥有 length 属性
- 拥有数字下标索引
(function () {
// 类数组
let objArr = {
0: "a",
1: "b",
2: "c",
length: 3,
};
// 数组
console.log(Array.from(objArr));
})();
-
衍生的知识点【迭代器】
一个数据结构只要部署了 Symbol.iterator 属性就能使用 for…of 遍历 与 …运算符 操作
(function () { let objArr = { 0: "a", 1: "b", 2: "c", length: 3, [Symbol.iterator]: function* () { for (let i = 0; i < this.length; i++) { yield this[i]; } }, }; console.log([...objArr]); })();
-
arguments.callee
用于指向调用的函数本身
// 匿名函数的递归调用 // 比如计算 1+2+3+4+5+...+n (function (n) { if (n === 1) { return 1; } return n + arguments.callee(n - 1); })(5); // 这里计算的是 1+2+3+4+5
caller
返回调用指定函数的函数【非标准,尽量不要在生产环境中使用】。如果一个函数 f 是在全局作用域内被调用的,则 f.caller 为 null,相反,如果一个函数是在另外一个函数作用域内被调用的,则 f.caller 指向调用它的那个函数
其实也可以说成是 f.caller 其实是函数 f 的执行环境。
function outerFn() {
function innerFn() {
console.log(innerFn.caller);
}
innerFn();
}
outerFn();
-
提一个问题:如果上述代码中 innerFn 不是直接在 outerFn 中执行,而是通过 return innerFn 通过闭包的形式执行。
function outerFn() { return function innerFn() { console.log(innerFn.caller); }; } // 请问打印的结果是什么 outerFn()();
js 代码的解析过程
预编译阶段发生变量声明和函数声明 ( 变量提升 ),没有赋值行为,匿名函数不参与预编译,只有在解释执行阶段才会进行变量初始化
-
一段伪代码
<script> var x = 1; var y = function () {}; function z() {} </script>
-
js 引擎针对上述代码的处理
-
创建一个全局对象 GO(Global Object),那么在这里是 window
-
加载脚本进行语法分析
-
预编译
主要是变量提升
// 下面是预编译做的事情 // 刚刚创建的全局对象 window window = { x: undefined, y: undefined, z: function () {}, //同时创建了document、navigator等等属性 // ...... };
-
开始解释执行代码
在赋值的位置对 window 中的属性赋值
window = { x: 1, y: function () {}, z: function () {}, //同时创建了document、navigator等等属性 // ...... };
Scopes
[ [ Scopes ] ] 是保存函数作用域链的对象
// 普通函数的 Scopes
function fn() {}
console.dir(fn);
/*
[[Scopes]] 中只存放了一个全局的对象,在这里是 window
*/
// 闭包的 Scopes
function closure_Fn() {
var num = 0;
return function () {
return num++;
};
}
var add = closure_Fn();
console.dir(add);
/*
[[Scopes]] 中存放了一个全局的对象,在这里是 window,还有闭包函数
*/