【问题标题】:javascript : function and object...?javascript:函数和对象...?
【发布时间】:2011-08-22 22:32:15
【问题描述】:

你能把函数当作对象来调用吗?例如:

function Tip(txt){      
    this.content = txt;  
    this.shown = false;  
}

还有:

var tip = new Tip(elem.attr('title'));

我的问题:

  1. 您可以为函数调用new 吗?
  2. 之所以可以使用“this”,是因为我们使用那个函数作为一个对象?

【问题讨论】:

    标签: javascript function object


    【解决方案1】:

    您正在寻找constructor 的概念。

    JavaScript 中的所有函数are objects 并可用于创建对象:

    function make_person(firstname, lastname, age) {
        person = {};
        person.firstname = firstname;
        person.lastname = lastname;
        person.age = age;
        return person;
    }
    make_person("Joe", "Smith", 23);
    // {firstname: "Joe", lastname: "Smith", age: 23}
    

    但是,为了创建特定类型的新对象(也就是说,继承原型、具有构造函数等),函数可以引用 this 并且 如果使用new operator 然后它将返回一个对象,该对象具有函数中 this 上定义的所有属性 - 在这种情况下 this 引用我们正在创建的新对象。

    function make_person_object(firstname, lastname, age) {
        this.firstname = firstname;
        this.lastname = lastname;
        this.age = age;
        // Note, we did not include a return statement
    }
    

    make_personmake_person_object 之间需要注意的主要区别是调用new make_person()(而不是简单地make_person())不会做任何不同的事情......两者都会产生相同的对象。但是,在没有 new 运算符的情况下调用 make_person_object() 将在当前 this 对象上定义您的 this 属性(如果您在浏览器中操作,通常是 window。)

    因此:

    var Joe = make_person_object("Joe", "Smith", 23);
    console.log(Joe); // undefined
    console.log(window.firstname) // "Joe" (oops)
    
    var John = new make_person_object("John", "Smith", 45);
    console.log(John); // {firstname: "John", lastname: "Smith", age: 45}
    

    此外,正如@RobG 指出的那样,这种做事方式会在我们创建的每个“Person”上创建对make_person_objectprototype 属性的引用。这使我们能够在事后向人员添加方法和属性:

     // Assuming all that came before
    make_person_object.prototype.full_name = "N/A";
    make_person_object.prototype.greet = function(){ 
        console.log("Hello! I'm", this.full_name, "Call me", this.firstname); 
    };
    John.full_name // "N/A"
    John.full_name = "John Smith"; 
    make_person_object.full_name // Still "N/A"
    John.greet(); // "Hello! I'm John Smith Call me John"
    

    约定像 make_person_object 这样的构造函数是大写、单数和“名词”(因为没有更好的术语)——因此我们将有一个 Person 构造函数,而不是 make_person_object 这可能是被误认为是普通函数。

    另见:

    【讨论】:

    • 您遗漏了最重要的部分:构造函数的this 引用的新对象继承了构造函数原型的属性。
    • @RobG -- 好吧,我做到了!我已经更新了答案以包含一些示例 - 感谢您帮助使其变得更好!
    • 很棒的答案。真的很棒。涵盖了做什么,然后教我如何理解它。我读过的每个问题都在之后的下一节中得到了回答。谢谢!!
    【解决方案2】:

    每个函数都引用了this。如果你调用Tip()this 将引用全局对象。如果您调用 new Tip(),则会创建一个引用 Tip.prototype 的新对象,this 将引用该新对象。

    您不能在对象上使用new,例如new {} 会抛出TypeError: object is not a function。如果您指的是new Object(),那么这是有效的,因为Object 是一个函数。

    【讨论】:

      【解决方案3】:

      是的。在 JavaScript 中,从技术上讲,一切都是对象。当你使用 new 时,它会创建一个 Tip 对象的实例,然后像构造函数一样调用 Tip 函数。

      如果你想向 Tip 对象添加函数,你应该像这样将它们添加到 Tip 的原型中:

      Tip.prototype.getContent = function() {
          return this.content;
      };
      

      如果你有,那么你就这样做:

      var tip = new Tip("this  is my content.");
      alert(tip.getContent());
      

      它会显示一条消息“这是我的内容”。

      但是,如果对象具有功能实现,则只能使用 new。所以这行不通:

      var Tip = { content: txt, show: false };
      var tipObj = new Tip();
      

      【讨论】:

        【解决方案4】:

        近 8 年(2008-2016)我一直在努力理解这些概念(作为对象的函数、原型对象、__proto__ 属性、构造函数属性)。首先,在多次阅读第 6、8、9 章后,我开始使用 David Flanagan “JavaScript Definitive Guide 5/6th ed” 4-5 年;这对我来说没有任何意义,但是在互联网上挣扎之后,我能够将函数(具有属性的典型 C++ 函数)作为对象进行管理;因为对象也可以有方法。幸运的是,在 2015 年的第 7 年,我开始编写 Wrox Nicholas C. Zakas “面向 Web 开发人员的专业 JavaScript 第 3 版”第 6,7 章;理解以上四个概念真的很有帮助。传统上,在 C/C++/C# 中,函数被认为是修改对象;或者换句话说,它们是为“做某事”而设计的,而对象是为了维护全局运行上下文的状态而使用的方法来改变其自身的对象状态。那么如果函数可以是一流的对象,那么为什么对象不能像函数呢?

        这里的主要问题应该是为什么?为什么不是单一的概念实体 像“关联函数”或“链式参数”?这是我的理解: 浏览器 exe 是一个单线程应用程序,这个 exe 控制调用具有预定义范围链的 JS 解释器(有些类似于带参数的命令字符串);现在在运行时,JS 引擎(不是解释器)以提升方式加载代码(因为没有 main 方法,所以提升了定义明确的关键字代码及其调用)。在这个提升的代码中,如果函数不被视为对象,那么它们必须在单独的调用上下文(超出范围链)中维护,这在 c/c++/c#(多线程和无限内存的 bcoz)中很容易实现,但在 JS 中则不然.因此,“链式对象上的待办事项”使 java 脚本功能成为第一类对象。事实上 JS 对象也做同样的事情;唯一的区别是“调用对象”在对象中不存在,因为“调用函数”是有意义的链式上下文。函数也可以被认为是“带有地址链接(链)的汇编语言指令的一组变量”。链接部分是故事的另一面,顶部->底部链接(原型对象)vs底部->顶部链接(__proto__属性)vs对象蓝图->对象实例(构造函数属性)。几个月前,我发现下图有助于理解链接。

        http://judis.me/wordpress/wp-content/uploads/2015/08/JavaScriptDiagram.png“JS 对象模型”

        【讨论】:

          【解决方案5】:

          对于#1:有一个对象叫做 Function (大写 F)

          var f = new Function("x", "y", "return x*y;");

          对于#2:“this”根据调用模式(如 Douglas Crockford 所称)而有所不同。 Crockford 说有 4 种模式(方法模式、函数模式、构造函数模式和“应用”模式)

          【讨论】:

          • 调用 eval 并没有比创建函数通常所做的更强大。似乎也与问题无关。
          • 不确定这与 OP 有什么关系(也许只是我自己)。可能想在反对票涌入之前澄清一下。
          • @Adam :它没有调用 eval 。如果您仔细阅读,答案与他的第一个问题有关。
          • 哦,确实不调用eval。但出于同样的原因,这很糟糕:-)
          【解决方案6】:

          该函数充当类的构造函数。或者,您可以这样做:

          function Tip(txt) {
           return {
           content: txt,
           shown: false
          }
          }
          

          并获得一个新实例:var myTip = new Tip("my epic tip"); 这类似于 c#:

          public class Tip {
          string text = "";
          public Tip(string txt) {
          text = txt;
          }
          }
          

          所以,有点。 1)您调用 new 因为该函数本质上是一个类,并且 2)this 指的是该类的当前实例。

          【讨论】:

          • 该函数未用作对象。使用new 时会创建一个新对象,并在该函数的范围内调用该函数
          • @Adam righto。我浏览了他问题的确切措辞。学过的知识。 ;-)
          • @Adam:创建对象的另一种方法是使用对象字面量语法,就像 Thomas 所做的那样。使用“new”只是创建对象的一种方式。
          • @Adam - 您的评论“使用 new 时创建了一个新对象,并且在该函数的范围内调用了该函数” - 非常具有误导性。当使用new 调用时,函数的this 关键字被设置为一个全新的object,其内部[[prototype]] 属性是对函数公共原型的引用。它是返回的 object (除非明确返回一些其他对象)。使用new always 调用函数会返回一个对象。它与作用域无关,函数的作用域与在没有new 的情况下调用时完全一样。
          • @Thomas - 首先,javascript 中没有类,尽管您可以模拟经典的基于类的继承。其次,如果构造函数返回this 以外的对象,它不会继承构造函数的原型(使用new 毫无意义)。
          【解决方案7】:
          1. 实际上,数组、函数等数据类型都是对象。
          2. 当我们将函数作为类声明时,这是可行的。

          【讨论】:

            猜你喜欢
            • 2012-10-04
            • 2015-12-24
            • 2017-09-13
            • 1970-01-01
            • 2012-07-18
            • 2017-10-08
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多