草庐IT

javascript - JavaScript 中 "class"定义的这三种模式有什么区别?

coder 2024-05-07 原文

在选择使用这四种模式之一而不是其他模式时,引擎盖下是否有任何重要/微妙/显着差异?并且,当通过 Object.create()“实例化”时,它们之间有什么区别吗?对比 new运算符(operator)?

1) CoffeeScript 的模式在翻译“类”定义时使用:

Animal = (function() {

  function Animal(name) {
    this.name = name;
  }

  Animal.prototype.move = function(meters) {
    return alert(this.name + (" moved " + meters + "m."));
  };

  return Animal;

})();



2)Knockout的模式似乎促进:
var DifferentAnimal = function(name){

    var self = this;

    self.name = name;

    self.move = function(meters){
        return alert(this.name + (" moved " + meters + "m."));
    };

}



3)我经常看到的一个类似的简单模式:
var DifferentAnimalWithClosure = function(name){

    var name = name;

    var move = function(meters){

    };

    return {name:name, move:move};

}



4)Backbone的模式促进:
var OneMoreAnimal= ClassThatAlreadyExists.extend({

    name:'',
    move:function(){}

});

更新 1:更改了模式 #2 并添加了模式 #3 以响应 Elias 的响应//次要格式

最佳答案

需要明确的是:JS 不知道类,只知道对象和自定义的、自定义的构造函数,但这不是重点。
简而言之,回答您的问题:是的,您在此处发布的创建新对象的各种方法之间存在一些小的甚至一些相当大的差异。

咖啡脚本:
这实际上是创建自己的构造函数的最清晰和传统的方法,但它已经“优化”了,因为它已经准备好使用(可选)闭包变量。
基本上,这段代码的作用是使用 IIFE,将构造函数定义和 proptotype 方法赋值包装在它们自己的私有(private)范围内,返回对新构造函数的引用。它只是干净、简单的 JS,与您自己编写的内容没有什么不同。

昏死:
现在这让我有点困惑,因为至少对我来说,你提供的代码片段看起来像是模块模式的一部分,或者是一个强大的构造函数。但是由于您没有使用 strict mode ,省略 new仍然会导致危险的情况,因为整个函数都会遇到创建 DifferentAnimal 的新实例的麻烦。 ,然后构造第二个对象字面量,分配 DifferentAnimal 的所有属性对于那个次要对象,我会说你错过了一些东西。因为,说实话,省略了最后一个 return {};在这里声明,可能根本没有区别。另外:正如您所看到的,您在本质上是一个构造函数中声明了一个方法( move )。这意味着每个实例都将被分配自己的函数对象 move ,而不是从原型(prototype)中获取它。
简而言之:再仔细看看你从哪里得到这个片段,并仔细检查这是否是完整版本,因为如果是,我只能看到反对这一点的论据。

使用在构造函数中定义的变量很简单:一个闭包,假设你的属性有一个不同的初始状态,由一些参数决定,传递给该构造函数:

function MyConstructor(param)
{
     var paramInit = param/2;//or something
     this.p = paramInit;//this property can change later on, so:
     this.reInit = function()
     {//this method HAS to be inside constructor, every instance needs its own method
         this.p = paramInit;//var paramInit can't, it's local to this scope
     };
}
var foo = new MyConstructor(10);
console.log(foo.p);//5
foo.p = 'hi';
console.log(foo.p);//hi
foo.reInit();
console.log(foo.p);//5
console.log(foo.paramInit);//undefined, not available outside object: it's a pseudo-private property

这就是全部了,真的。当你看到 ppl 使用 var that = this;什么的,那通常就是创建一个在任何地方都可用的主对象的引用,而不必处理this的头疼问题。 (this 引用什么?该方法应用于对象而不是它最初打算用于的对象时应该做什么?等等......)

Backbone :
在这里,我们正在处理另一种情况:扩展对象(即:使用现有“类”(构造函数)或特定实例的方法、属性)与简单地创建对象不同。
众所周知,JS 对象可以在任何给定时间分配新属性。这些属性也可以删除。有时,原型(prototype)属性可以在实例本身上重新定义(掩盖原型(prototype)行为)等等......所以这一切都取决于你想要结果对象(新创建的对象,扩展给定实例)看起来像:你希望它从实例中获取所有属性,还是希望两个对象都在某处使用相同的原型(prototype)?
这两件事也可以通过使用简单的 JS 来实现,但它们只是需要更多的努力来自己编写。但是,如果您编写,例如:
function Animal(name)
{
    this.name = name;
}
Animal.prototype.eat= function()
{
    console.log(this.name + ' is eating');
};

这可以被视为等同于写作:
var Animal = Object.extend({name:'',eat:function()
{
    console.log(this.name + ' is eating');
}});

短很多,但缺少构造函数。
new对比 Object.create嗯,这很简单:Object.create只是比 new 强大得多:您可以在需要创建对象的时候定义原型(prototype)方法、属性(包括天气与否,它们是否可枚举、可写等...),而不必编写构造函数和原型(prototype),或创建对象字面量和所有这些人混在一起 Object.defineProperty线。
缺点:有些人仍然没有使用符合 ECMA5 的浏览器(IE8 还没有完全消亡)。根据我的经验:一段时间后,调试相当大的脚本确实变得非常困难:尽管与常规构造函数相比,我更倾向于使用 power-constructors,但我仍然将它们定义在我的脚本的最顶部,清晰明了非常具有描述性的名称,而对象文字是我“即时”创建的东西。使用 Object.create ,我注意到我倾向于创建的对象确实有点太复杂而无法作为实际的对象文字,就好像它们是对象文字:
//fictional example, old:
var createSomething = (function()
{
    var internalMethod = function()
    {//method for new object
        console.log(this.myProperty || '');
    };
    return function(basedOn)
    {
        var prop, returnVal= {};
        returnVal.myProperty = new Date();
        returnVal.getCreated = internalMethod;//<--shared by all instances, thx to closure
        if (!basedOn || !(basedOn instanceof Object))
        {//no argument, or argument is not an object:
            return returnVal;
        }
        for (prop in basedOn)
        {//extend instance, passed as argument
            if (basedOn.hasOwnProperty(prop) && prop !== '_extends')
            {
                returnVal[prop] = basedOn[prop];
            }
        }
        returnVal._extends = basedOn;//<-- ref as sort-of-prototype
        return returnVal;
    };
}());

现在这很冗长,但我已经准备好了基本的构造函数,我也可以用它来扩展现有的实例。简单地写下似乎不那么冗长:
var createSomething = Object.create(someObject, {getCreated:function()
{
    console.log(this.myProperty);
},
myProperty:new Date()});

但是 IMO,这让您很难跟踪在何处创建了什么对象(主要是因为 Object.create 是一个表达式,并且不会被提升。嗯,当然,这远不是一个决定性的论点:两者都有他们的专业人士和缺点:我更喜欢使用模块模式、闭包和电源构造函数,如果你不这样做就好了。

希望这可以为您解决一两件事。

关于javascript - JavaScript 中 "class"定义的这三种模式有什么区别?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13789559/

有关javascript - JavaScript 中 "class"定义的这三种模式有什么区别?的更多相关文章

  1. ruby - 为什么我可以在 Ruby 中使用 Object#send 访问私有(private)/ protected 方法? - 2

    类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc

  2. ruby - Facter::Util::Uptime:Module 的未定义方法 get_uptime (NoMethodError) - 2

    我正在尝试设置一个puppet节点,但ruby​​gems似乎不正常。如果我通过它自己的二进制文件(/usr/lib/ruby/gems/1.8/gems/facter-1.5.8/bin/facter)在cli上运行facter,它工作正常,但如果我通过由ruby​​gems(/usr/bin/facter)安装的二进制文件,它抛出:/usr/lib/ruby/1.8/facter/uptime.rb:11:undefinedmethod`get_uptime'forFacter::Util::Uptime:Module(NoMethodError)from/usr/lib/ruby

  3. ruby-on-rails - rails : "missing partial" when calling 'render' in RSpec test - 2

    我正在尝试测试是否存在表单。我是Rails新手。我的new.html.erb_spec.rb文件的内容是:require'spec_helper'describe"messages/new.html.erb"doit"shouldrendertheform"dorender'/messages/new.html.erb'reponse.shouldhave_form_putting_to(@message)with_submit_buttonendendView本身,new.html.erb,有代码:当我运行rspec时,它失败了:1)messages/new.html.erbshou

  4. ruby-on-rails - 由于 "wkhtmltopdf",PDFKIT 显然无法正常工作 - 2

    我在从html页面生成PDF时遇到问题。我正在使用PDFkit。在安装它的过程中,我注意到我需要wkhtmltopdf。所以我也安装了它。我做了PDFkit的文档所说的一切......现在我在尝试加载PDF时遇到了这个错误。这里是错误:commandfailed:"/usr/local/bin/wkhtmltopdf""--margin-right""0.75in""--page-size""Letter""--margin-top""0.75in""--margin-bottom""0.75in""--encoding""UTF-8""--margin-left""0.75in""-

  5. ruby-on-rails - Rails - 子类化模型的设计模式是什么? - 2

    我有一个模型:classItem项目有一个属性“商店”基于存储的值,我希望Item对象对特定方法具有不同的行为。Rails中是否有针对此的通用设计模式?如果方法中没有大的if-else语句,这是如何干净利落地完成的? 最佳答案 通常通过Single-TableInheritance. 关于ruby-on-rails-Rails-子类化模型的设计模式是什么?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.co

  6. ruby - 什么是填充的 Base64 编码字符串以及如何在 ruby​​ 中生成它们? - 2

    我正在使用的第三方API的文档状态:"[O]urAPIonlyacceptspaddedBase64encodedstrings."什么是“填充的Base64编码字符串”以及如何在Ruby中生成它们。下面的代码是我第一次尝试创建转换为Base64的JSON格式数据。xa=Base64.encode64(a.to_json) 最佳答案 他们说的padding其实就是Base64本身的一部分。它是末尾的“=”和“==”。Base64将3个字节的数据包编码为4个编码字符。所以如果你的输入数据有长度n和n%3=1=>"=="末尾用于填充n%

  7. ruby - 解析 RDFa、微数据等的最佳方式是什么,使用统一的模式/词汇(例如 schema.org)存储和显示信息 - 2

    我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i

  8. ruby - 为什么 4.1%2 使用 Ruby 返回 0.0999999999999996?但是 4.2%2==0.2 - 2

    为什么4.1%2返回0.0999999999999996?但是4.2%2==0.2。 最佳答案 参见此处:WhatEveryProgrammerShouldKnowAboutFloating-PointArithmetic实数是无限的。计算机使用的位数有限(今天是32位、64位)。因此计算机进行的浮点运算不能代表所有的实数。0.1是这些数字之一。请注意,这不是与Ruby相关的问题,而是与所有编程语言相关的问题,因为它来自计算机表示实数的方式。 关于ruby-为什么4.1%2使用Ruby返

  9. ruby - 检查 "command"的输出应该包含 NilClass 的意外崩溃 - 2

    为了将Cucumber用于命令行脚本,我按照提供的说明安装了arubagem。它在我的Gemfile中,我可以验证是否安装了正确的版本并且我已经包含了require'aruba/cucumber'在'features/env.rb'中为了确保它能正常工作,我写了以下场景:@announceScenario:Testingcucumber/arubaGivenablankslateThentheoutputfrom"ls-la"shouldcontain"drw"假设事情应该失败。它确实失败了,但失败的原因是错误的:@announceScenario:Testingcucumber/ar

  10. ruby-on-rails - Rails 3.2.1 中 ActionMailer 中的未定义方法 'default_content_type=' - 2

    我在我的项目中添加了一个系统来重置用户密码并通过电子邮件将密码发送给他,以防他忘记密码。昨天它运行良好(当我实现它时)。当我今天尝试启动服务器时,出现以下错误。=>BootingWEBrick=>Rails3.2.1applicationstartingindevelopmentonhttp://0.0.0.0:3000=>Callwith-dtodetach=>Ctrl-CtoshutdownserverExiting/Users/vinayshenoy/.rvm/gems/ruby-1.9.3-p0/gems/actionmailer-3.2.1/lib/action_mailer

随机推荐