对象名称是一个函数名称?

时间:2010-09-08 00:37:59

标签: javascript

如果我们有

var randomname = {};
randomname.attribute = 'something';

function randomname(){
  alert(randomname.attribute);
}
randomname();

javascript会抛出任何错误吗?

<小时/>的更新
所以,我们知道我们不能让一个对象与一个函数具有相同的名称。

为什么会这样?

javascript是否无法按照您的方式告诉您的内容?

6 个答案:

答案 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,这是一个不可到达的对象它按以下顺序包含变量,函数声明和函数参数的标识符在本地范围中:

  1. FormalParameterList个标识符(适用于Activation Object
  2. FunctionDeclaration标识符
  3. VariableDeclaration标识符
  4. 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上的行为方式不同?

    由于:

    1. Firebug的控制台Function Code在评估之前。
    2. Mozilla实现定义了wraps your code
    3. 由于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.STRINGSequelize.STRING(1234)