【问题标题】:Get a Backbone Model instance's model/class name获取主干模型实例的模型/类名称
【发布时间】:2012-03-29 23:16:53
【问题描述】:

给定一个Backbone模型的实例,我怎么知道这个实例的“类”(可以这么说)?

例如:

class Car extends Backbone.Model

mycar = new Car()

而我需要的是:

mycar.modelName # => 'Car'

【问题讨论】:

  • 您需要更具体。一个模型可以有多个视图。该视图具有 .el 参考,AFAIK 应该足够了,如果您正在考虑视图。但这可能不是您要问的。
  • 啊,没关系。你是在以编程方式说话。
  • 为什么需要类名?要创建相同类型的新模型或访问类级函数或其他什么?这是一个有趣的问题。
  • @websymphony 我需要它,因为我有一个在某个阶段需要类名的混音。
  • 再过 5 年(ECMAScript 6+?),JavaScript 中不会有类的概念。 CoffeeScript 的对象创建语法给刚熟悉该语言的人带来了很多困惑。使用Object.createextend 方法可能是通过mixins 实现继承的更简单方法。

标签: javascript backbone.js coffeescript


【解决方案1】:

我认为总体上是有问题的。我打算建议这里提到的一些选项(How do I get the name of an object's type in JavaScript?),但我对第一个选项有疑问。您总是可以扩展您的所有模型,使其具有一个返回模型“名称”的函数,但我可以理解为什么您可能会觉得这不太令人满意。

【讨论】:

  • 我同意,要么您按照@JayC 的建议手动解决它,要么您正在谈论一个非常古老的通用 JS 问题仍未解决。
【解决方案2】:

在撰写本文时,您可以通过执行以下操作来获取模型的类名:

model.constructor.name

这适用于我在 Chrome 浏览器中。

【讨论】:

  • 请注意,如果你有像 Jammit 这样的压缩器,这将不起作用,构造函数会在打包后更改。
【解决方案3】:

我尝试了 Mitch 的建议,但在 Chrome 中,model.constructor.name 对我来说始终是 ""

我选择使用约定。我现在使用 extend 的第二个参数创建一个类属性,其工作方式如下:

directory.models.SomeModel = Backbone.Model.extend({ 
    //  usual model instance stuff
}, {
    modelType: "SomeModel"   // class property
});

我发现我总能像这样得到我想要的:

var mt = model.constructor.modelType;

【讨论】:

    【解决方案4】:

    除了 IE 之外的所有浏览器都已经解决了这个问题,但是 polyfill 很容易制作。答案是Function.name

    https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/name

    一定要利用这一点!在 ES6 类中,构造函数的 Function.name 就是类名,所以在 ES6 中:

    class Car { /*...*/ }
    var c = new Car();
    console.log(c.constructor.name); // "Car"
    

    在当前的 ES5 中,并非所有库都利用了这一点。例如,骨干网就没有。 :( Backbone 构造函数是匿名函数,所以

    var m = new Backbone.Model();
    console.log(m.constructor.name); // "undefined" :(
    

    不幸的是。就像其他人所说的那样,如果您使用 Backbone,则必须制作自己的命名系统。

    这是 Function.name 的 polyfill:

    // Polyfill for Function.name on browsers that do not support it (IE):
    // See: http://stackoverflow.com/questions/6903762/function-name-not-supported-in-ie
    if (!(function f() {}).name) {
        Object.defineProperty(Function.prototype, 'name', {
            get: function() {
                var name = this.toString().match(/^\s*function\s*(\S*)\s*\(/)[1];
    
                // For better performance only parse once, and then cache the
                // result through a new accessor for repeated access.
                Object.defineProperty(this, 'name', { value: name });
    
                return name;
            }
        });
    }
    

    【讨论】:

      【解决方案5】:

      您可以像这样查询对象实例的继承树(又名原型链):

      object.__proto__.__proto__.__proto__

      您可以查看可用的内容。您必须手动将任何类型名称属性添加到每个视图和/或模型中。这是最干净的方法。我推荐这个。只需将 'className: "MyCompany.MyProject.MyArea.MyView"' 添加到您的每个视图和/或模型中。

      如果你没有为你的对象添加一个 className 属性,有一个稍微笨拙的方法仍然可以得到它(例如用于调试输出目的):

      假设您执行以下操作:“MyCompany.MyProject.MyArea.MyView = Backbone.View.extend({”视图/模型类名称位于全局命名空间变量名称中。从对象实例我们无法访问该全局变量所以虽然不是很理想,但我们能做的最好的就是遍历命名空间寻找 var:

      function findBackboneClassName(ns, object, prefix, depth) {
          prefix = typeof prefix !== 'undefined' ? prefix : "";
          depth = typeof depth !== 'undefined' ? depth : 0;
          if (depth > 5) return null;
      
          for (i in ns) {
              try { ns[i]; } catch (e) { continue; }
              if (/top|window|document|parent|frames|self|chrome|form|theForm/.test(i)) continue;
              //console.log(">" + prefix + "." + i + " " + typeof(ns[i]));
      
              if (ns[i] == object.constructor) {
                  //console.log("Found:", prefix + "." + i);
                  return prefix + "." + i;
              }
      
              if (typeof (ns[i]) == "object") {
                  var r = findBackboneClassName(ns[i], object, prefix + (prefix != "" ? "." : "") + i, depth + 1);
                  if (r != null) return r;
              }
          }
          return null;
      }
      findBackboneClassName(window, myBackboneViewInstance);
      

      理想情况下,您为“窗口”以外的类型使用命名空间。这使得它更清洁,更容易遍历。您只需将“window”替换为命名空间的基础,并传入所需的前缀(如果您希望它的前缀正确)。您还可以删除几行,例如 try..catch 和 if..continue。

      findBackboneClassName(MyCompany.MyProject, myBackboneViewInstance, "MyCompany.MyProject");
      

      从 objectInstance.constructor 获取类名的技巧不适用于主干,因为它进行继承的方式。所有 ctor 对我来说都一样:“function () { return parent.apply(this, arguments); }”。

      【讨论】:

        猜你喜欢
        • 2016-02-14
        • 1970-01-01
        • 1970-01-01
        • 2018-08-22
        • 1970-01-01
        • 1970-01-01
        • 2011-10-28
        • 2015-08-08
        • 2013-07-09
        相关资源
        最近更新 更多