var foo = function () {
...
};
function foo() {
...
}
(function () {
...
})();
函数声明(缩写为FD)是这样一种函数:
function exampleFunc() {
...
}
foo();
function foo() {
alert('foo');
}
// 函数可以在如下地方声明:
// 1) 直接在全局上下文中
function globalFD() {
// 2) 或者在一个函数的函数体内
function innerFD() {}
}
函数表达式(缩写为FE)是这样一种函数:
var foo = function () {
...
};
var foo = function _foo() {
...
};
// 圆括号(分组操作符)内只能是表达式
(function foo() {});
// 在数组初始化器内只能是表达式
[function bar() {}];
// 逗号也只能操作表达式
1, function baz() {};
// FE在定义阶段之前不可用(因为它是在代码执行阶段创建)
alert(foo); // "foo" 未定义
(function foo() {});
// 定义阶段之后也不可用,因为他不在变量对象VO中
alert(foo); // "foo" 未定义
function foo(callback) {
callback();
}
foo(function bar() {
alert('foo.bar');
});
foo(function baz() {
alert('foo.baz');
});
var foo = function () {
alert('foo');
};
foo();
var foo = {};
(function initialize() {
var x = 10;
foo.bar = function () {
alert(x);
};
})();
foo.bar(); // 10;
alert(x); // "x" 未定义
(function () {
// 初始化作用域
})();
var foo = 10;
var bar = (foo % 2 == 0
? function () { alert(0); }
: function () { alert(1); }
);
bar(); // 0
function () {
...
}();
// 即便有名称
function foo() {
...
}();
// "foo" 是一个函数声明,在进入上下文的时候创建
alert(foo); // 函数
function foo(x) {
alert(x);
}(1); // 这只是一个分组操作符,不是函数调用!
foo(10); // 这才是一个真正的函数调用,结果是10
// 函数声明
function foo(x) {
alert(x);
}
// 一个分组操作符,包含一个表达式1
(1);
// 另外一个操作符,包含一个function表达式
(function () {});
// 这个操作符里,包含的也是一个表达式"foo"
("foo");
// 等等
if (true) function foo() {alert(1)}
(function foo(x) {
alert(x);
})(1); // 这才是调用,不是分组操作符
var foo = {
bar: function (x) {
return x % 2 != 0 ? 'yes' : 'no';
}(1)
};
alert(foo.bar); // 'yes'
因此,”关于圆括号”问题完整的答案如下:当函数不在表达式的位置的时候,分组操作符圆括号是必须的——也就是手工将函数转化成FE。
如果解析器知道它处理的是FE,就没必要用圆括号。
// 注意是1,后面的声明
1, function () {
alert('anonymous function is called');
}();
// 或者这个
!function () {
alert('ECMAScript');
}();
// 其它手工转化的形式
...
if (true) {
function foo() {
alert(0);
}
} else {
function foo() {
alert(1);
}
}
foo(); // 1 or 0 ?实际在上不同环境下测试得出个结果不一样
(function foo(bar) {
if (bar) {
return;
}
foo(true); // "foo" 是可用的
})();
// 在外部,是不可用的
foo(); // "foo" 未定义
specialObject = {};
Scope = specialObject + Scope;
foo = new FunctionExpression;
foo.[[Scope]] = Scope;
specialObject.foo = foo; // {DontDelete}, {ReadOnly}
delete Scope[0]; // 从作用域链中删除定义的特殊对象specialObject
Object.prototype.x = 10;
(function () {
alert(x); // 10
})();
Object.prototype.x = 10;
function foo() {
var x = 20;
// 函数声明
function bar() {
alert(x);
}
bar(); // 20, 从foo的变量对象AO中查询
// 匿名函数表达式也是一样
(function () {
alert(x); // 20, 也是从foo的变量对象AO中查询
})();
}
foo();
AO(bar FD or anonymous FE) -> no ->
AO(bar FD or anonymous FE).[[Prototype]] -> yes - 10
function foo() {
var x = 10;
(function bar() {
alert(x); // 20, 不上10,不是从foo的活动对象上得到的
// "x"从链上查找:
// AO(bar) - no -> __specialObject(bar) -> no
// __specialObject(bar).[[Prototype]] - yes: 20
})();
}
Object.prototype.x = 20;
foo();
// FE 在变量对象里可见
testNFE();
(function testNFE() {
alert('testNFE');
});
// FE 在定义结束以后也可见
// 就像函数声明一样
testNFE();
var foo = function bar() {
alert('foo');
};
alert(typeof bar); // "function",
// 有趣的是
alert(foo === bar); // false!
foo.x = 10;
alert(bar.x); // 未定义
// 但执行的时候结果一样
foo(); // "foo"
bar(); // "foo"
(function bar() {});
var foo = bar;
alert(foo === bar); // true
foo.x = 10;
alert(bar.x); // 10
var foo = function bar() {
alert([
arguments.callee === foo,
arguments.callee === bar
]);
};
foo(); // [true, false]
bar(); // [false, true]
var foo = function bar() {
alert(1);
};
if (false) {
foo = function bar() {
alert(2);
};
}
bar(); // 2
foo(); // 1
(function () {
// 不用var的话,就不是当前上下文的一个变量了
// 而是全局对象的一个属性
foo = function foo() {};
})();
// 但,在匿名函数的外部,foo这个名字是不可用的
alert(typeof foo); // 未定义
var x = 10;
function foo() {
var x = 20;
var y = 30;
var bar = new Function('alert(x); alert(y);');
bar(); // 10, "y" 未定义
}
var a = [];
for (var k = 0; k < 100; k++) {
a[k] = function () {}; // 可能使用了joined objects
}
var a = [];
for (var k = 0; k < 100; k++) {
a[k] = Function(''); // 一直是100个不同的函数
}
function foo() {
function bar(z) {
return z * z;
}
return bar;
}
var x = foo();
var y = foo();
F = new NativeObject();
// 属性[[Class]]是"Function"
F.[[Class]] = "Function"
// 函数对象的原型是Function的原型
F.[[Prototype]] = Function.prototype
// 医用到函数自身
// 调用表达式F的时候激活[[Call]]
// 并且创建新的执行上下文
F.[[Call]] = <reference to function>
// 在对象的普通构造器里编译
// [[Construct]] 通过new关键字激活
// 并且给新对象分配内存
// 然后调用F.[[Call]]初始化作为this传递的新创建的对象
F.[[Construct]] = internalConstructor
// 当前执行上下文的作用域链
// 例如,创建F的上下文
F.[[Scope]] = activeContext.Scope
// 如果函数通过new Function(...)来创建,
// 那么
F.[[Scope]] = globalContext.Scope
// 传入参数的个数
F.length = countParameters
// F对象创建的原型
__objectPrototype = new Object();
__objectPrototype.constructor = F // {DontEnum}, 在循环里不可枚举x
F.prototype = __objectPrototype
return F