为什么80%的码农都做不了架构师?>>>
1、闭包是函数的代码在运行过程中的一个动态环境,是一个运行期的、动态的概念。
闭包(又称“词法闭包”或“函数闭包”)是一个包含了非本地变量引用环境的函数。
2、变量在语法分析阶段被初始化为undefined。
//
标识符
(
变量
)
在定义后值为
undefined
function myFunc() {
alert(i);
var i = 100;
}
// 输出值总是undefined
myFunc();
myFunc();
//name在函数闭包内被声明,
不会访问到全局变量
name
var name = 'test';
function myFunc() {
// 输出undefined
alert(name);
var name = 100;
// 输出100
alert(name);
}
3、以下函数返回( return 子句)并不导致引用:
function myFunc() {
function foo() {
//...
}
return foo;
}
//
函数
foo()
在返回后立即被执行了,然后就会释放
foo()();
4、引用:
对象属性的引用:
1)对象在构造时,使用
this
引用进入构造器函数
2)对象在调用方法时,使用
this
引用进入函数
3)某个函数使用
call/apply
方法调用,并传入某个对象作为
this
引用
4)调用一个函数时,对象从参数入口传入
被变量引用:
var
func = myFunc(); // <-- 在这里产生一个引用
5、函数闭包间的关联性:
var checker;
function myFunc()
{
if (checker) {
checker();
}
alert('do myFunc: ' + str);
var str = 'test.';
if (!checker) {
checker = function() {
alert('do Check:' + str);
}
}
return arguments.callee;
}
myFunc()();
//
do myFunc:
undefined 第一次调用
//do Check:test. 第二次调用
//
do myFunc:
undefined 第二次调用
6、
范例1:
var obj = new Object();
var events = { m1: "clicked", m2: "changed" };
for (e in events) {
obj[e] = function(){
alert(events[e]);
};
}
// 显示false, 表明是不同的函数实例
alert( obj.m1 === obj.m2 );
// 方法m1()与m2()都输出相同值
// 其原因,在于两个方法都访问全局闭包中的同一个upvalue 值e
obj.m1();
obj.m2();
范例2:
//
范例
2.1
在函数内保存数据
var obj = new Object();
var events = { m1: "clicked", m2: "changed" };
for (e in events) {
obj[e] = function( aValue) { // 闭包 lv1
return function() { // 闭包lv2
alert(events[ aValue]);
}
}(e);
}
// 下面将输出不同的值
obj.m1();
obj.m2();
//
范例
2.2
在闭包内通过局部变量保存数据
for (e in events) {
function() { // 闭包lv1
var aValue = e;
obj[e] = function() { // 闭包lv2
alert(events[ aValue]);
}
}();
}
//
范例
2.3
将值
e
交给函数实例保存
for (e in events) {
(obj[e] = function() {
// arguments.callee 指向匿名函数自身
alert(events[arguments.callee .aValue]);
}
) .aValue = e;
}
//
范例
2.4
Function构造器
var obj = new Object();
var events = {m1: "clicked", m2: "changed"};
for (e in events) {
obj[e] = new Function('alert( events["' + e + '"])');//
变量e被转换为字符串值来使
用
}
7、优先级:argsName(形式参数名) > arguments > funcName(函数名),其中arguments 是语言内定的标识符,无需声明即可使用。
// 示例1:输出值'hi', 而非函数foo.toString()
function foo(foo) {
alert(foo);
}
foo('hi');
// 示例2:输出数值100 的类型'number', 而非参数对象arguments 的类型'object'
function foo2(arguments) {
alert(typeof arguments);
}
foo2(100);
// 示例3:输出参数对象arguments 的类型'object'
// (注:在JScript 中, arguments 作为函数名可以被声明, 但调用该函数导致脚本引擎崩溃)
function arguments () {
alert(typeof arguments);
}
arguments ();
8、局部变量 (varDecls)与函数形式参数:
A.
当形式参数名与未赋值的局部变量名重复时
,
取形式参数值;
B.
当形式参数与有值的局部变量名重复时,取局部变量值。
第一种情况:
function myFunc(str){
var str;
alert(str);
}
myFunc("not undefined");
//not undefined
第二种情况:
function myFun(str){
var str = "hello world";
alert(str);
}
myFun("not undefined"); //hello world
9、使用Function()构造器创建的函数与函数直接量声明、匿名函数不同,它在任意位置创建的实例,都处于全局闭包中。亦即是说, Function()的实例的upvalue 总是指向全局闭包。
var value = "hello world";
function myFunc(arg){
var value = "welcome to here";
var foo = new Function('alert(value)');
foo();
}
myFunc(); //
"hello world"
10、对象闭包:
var aObj = { value: 'hello' };
function foo() {
with (aObj) { // < --对象闭包
with (aObj) { // < --对象闭包
var value = 1000;
alert(aObj.value); // 显示值: 1000
}
alert(value);
}
alert(value);
}
foo(); // 显示'undefined'
11、函数闭包与对象闭包既有相关性,也有各自的独立性。对象闭包总是动态地添加在闭包链的顶端,而函数闭包则依赖于函数声明时的、静态的语法作用域限制。
/**
* 两种闭包的交叉作用
*/
var obj = { value: 200 };
var value = 1000;
with (obj) { // <-- 对象闭包
function foo() { // <-- 具名函数foo()的闭包
value *= 2; // <-- 依赖于函数静态位置所决定的闭包链
}
foo(); //
with
的限定只对这一行有效
}
alert(obj.value);// 显示 200
alert(value); // 显示 2000
12、匿名函数的闭包如同对象闭包一样,动态地添加到当前闭包链的顶端。
var obj = { value: 200 };
var value = 1000;
with (obj) { // <-- 对象闭包
obj.
foo =
function ()
{ // <-- 匿名函数的闭包
value *= 2; //
<-- 依赖于函数闭包所在的当前闭包链:with所打开的obj对象闭包
}
obj.
foo();
}
/**
*
即使该匿名函数没
有添加为对象
obj
的方法
*而仅是即用即声明,那么它所操作的仍然是对象
闭包中的
value
值
*/
with (obj) { // <-- 对象闭包
void
function ()
{ // <-- 匿名函数的闭包
value *= 2; //
<-- 依赖于函数闭包所在的当前闭包链:with所打开的obj对象闭包
}();
}
// 显示 400
alert(obj.value);
// 显示 1000
alert(value);
13、eval:
解决eval作用域的方法:with ( objContext )eval (strScript) 。
如:with ( window )eval (strScript) ; //eval在 全局作用域中执行