如果我们有
var randomname = {};
randomname.attribute = 'something';
function randomname(){
alert(randomname.attribute);
}
randomname();
javascript会抛出任何错误吗?
<小时/>的更新
为什么会这样?
javascript是否无法按照您的方式告诉您的内容?
答案 0 :(得分:19)
它应该给你一个TypeError
异常 - 试图调用一个对象 - 在Firebug的控制台中观察到的行为是不正确的......
FunctionDeclaration
的{{3}}位于其封闭范围的顶部,您的代码实际上按此顺序执行:
// FunctionDeclaration is hoisted
function randomname(){
alert(randomname.attribute);
}
// the var has no observable effect, because
// the randonmane identifier is already defined
randomname = {};
randomname.attribute = 'something';
randomname(); // TypeError, randomname is not callable.
当进入执行上下文时,hoisted进程(在ES5中称为Variable Instantiation)定义Declaration Binding Instantiation上的属性(AO,这是一个不可到达的对象它按以下顺序包含变量,函数声明和函数参数的标识符在本地范围中:
FormalParameterList
个标识符(适用于Activation Object)FunctionDeclaration
标识符VariableDeclaration
标识符 VariableDeclaration
不会覆盖已经在AO中定义的标识符(例如,通过前两个步骤之一),但分配将在运行时进行。
例如:
(function (foo) {
var foo; // doesn't affect the existing `foo` identifier
return typeof foo;
function foo () {}
})('string'); // yields "function"
但如果进行了分配,则将替换标识符的值,例如:
(function (foo) {
var foo = {};
return typeof foo;
function foo () {}
})('string'); // yields "object"!!
在上面的示例中,当调用函数时, - 但在代码执行之前 - 在激活对象(也称为变量对象)上设置foo
标识符。
首先为它分配形参的值,值'string'
,然后检查函数体上的所有FunctionDeclaration
,找到一个名为foo
的函数,然后foo
标识符将指向该函数。
之后,检查所有变量声明,我们有一个标识符为foo
的变量声明,但是在这个时间内它的值被认为是 - 该函数尚未执行 - 。
此时,该函数已准备好执行,其词法和可变环境已设置。
将在函数中执行的第一件事是赋值foo = {};
,它取代了我们之前使用的函数的引用。
为什么它在其他浏览器和Firefox上的行为方式不同?
由于:
由于Firebug通过在with
语句中包装来评估代码,因此会导致在语句上下文中评估FunctionDeclaration
-a Mozilla的函数语句 - 。
要显示Function语句在Mozilla实现上的行为,请考虑以下示例:
if (true) {
function foo () { return 'true!';}
} else {
function foo () { return 'false??!';}
}
foo();
在Mozilla中,您将获得'true!'
,而在其他实现中,您将获得'false??!'
- 即使在IE上也是如此。
那是因为函数定义是在运行时,在Statement上下文中(在if
的真正分支中),而在其他实现中,函数声明是在分析时计算< / em>的
上面的例子实际上应该在任何实现上产生SyntaxError
异常,但是在任何实现上都不会发生...
只应在全局代码中或直接在函数的FunctionBody中允许FunctionDeclaration
。
Function Statement lot of可互换地使用术语函数声明和函数声明,但这完全错误,ECMAScript没有定义函数声明,是people。
规范在这个问题上有一个简短的non-standard feature:
注意:已知几种广泛使用的ECMAScript实现支持将FunctionDeclaration用作Statement。然而,在应用于此类FunctionDeclarations的语义中的实现之间存在显着且不可调和的变化。由于这些不可调和的差异,使用FunctionDeclaration作为Statement会导致代码在实现中无法可靠地移植。建议ECMAScript实现不允许使用FunctionDeclaration,或在遇到此类用法时发出警告。 ECMAScript的未来版本可以定义用于在Statement上下文中声明函数的替代可移植方法。
尝试在全局执行上下文中运行代码 - 在一个简单的<script>
元素中 - 你会看到它在Firefox上崩溃:
<script type="text/javascript">
var randomname = {};
randomname.attribute = 'something';
function randomname(){
alert(randomname.attribute);
}
randomname();
</script>
你可以找到上面的例子note,确保打开Firebug的控制台,你会看到你在其他浏览器上遇到的同样的错误。
答案 1 :(得分:3)
您的function randomname()
正在重新定义randomname
标识符,从而失去对您之前构建的对象的引用。它看起来可能更清晰:
var randomname = {};
randomname.attribute = 'something';
var randomname = function () {
alert(randomname.attribute);
};
randomname();
就像在做:
var a = 5;
var a = [20, 30];
console.log(a); // returns [20, 30]
答案 2 :(得分:3)
功能实际上也是JavaScript中的一个对象(第一类对象)。
所以你可以这样做。
var human = function(){
alert("Hi");
};
// which is perfectly normal
//but then
human.name="Anubhav";
然后你可以做以下事情:
human();//works
alert(human.name);//works
答案 3 :(得分:2)
function randomname(){
alert(randomname.attribute);
}
与此基本相同:
var randomname = function() {
alert(randomname.attribute);
}
它不是100%相同,因为使用第一种语法可以引用“将来”的功能,但这基本上是它的工作原理。函数和变量只有一个命名空间,因为函数被赋值给变量。
答案 4 :(得分:0)
原谅我的迂腐回复。你的问题有点令人困惑,或者这是一个棘手的问题。在你写的第二行
var randomname.attribute....
如果这是你的意思,那么这是一个非法的陈述,肯定会抛出异常。 但是,如果您的观点是关于重用相同名称的第四行。
请注意你写了
function randomname(){...}
而不是
var randomname = function(){...}
我不知道为什么,但因为你使用了未来的功能,你将无法覆盖预先存在的名称。因此,randomname仍然是一个哈希而不是一个函数,因此抛出异常。
我的问题是,那么randomname函数会发生什么?我们怎么称呼它?这是浪费资源吗?作为一般规则,我总是使用
var randomname = function{..}
模板,所以我总是确信姓名冲突不会发生,所以我从来没有遇到过这个。
答案 5 :(得分:0)
我知道这是一篇旧帖子,但我找到了一个如何运作的例子。
事实上,我相信sequelize.js会使用以下代码来完成它:
var STRING = function(length, binary) {
if (this instanceof STRING) {
this._binary = !!binary
if (typeof length === 'number') {
this._length = length
} else {
this._length = 255
}
} else {
return new STRING(length, binary)
}
}
STRING.prototype = {
get BINARY() {
this._binary = true
return this
},
get type() {
return this.toString()
},
toString: function() {
return 'VARCHAR(' + this._length + ')' + ((this._binary) ? ' BINARY' : '')
}
}
Object.defineProperty(STRING, 'BINARY', {
get: function() {
return new STRING(undefined, true)
}
})
您可以在他们的数据类型文档中看到它:http://sequelizejs.com/docs/latest/models#block-2-line-0。请注意Sequelize.STRING
和Sequelize.STRING(1234)