如何在JavaScript中“正确”创建自定义对象?

如何在JavaScript中“正确”创建自定义对象?,javascript,Javascript,我想知道创建具有属性和方法的JavaScript对象的最佳方法是什么 我见过这样的例子,人们使用var self=this,然后使用self。在所有功能中,确保范围始终正确 然后,我看到了使用.prototype添加属性的示例,而其他人则使用内联方式 有人能给我一个带有一些属性和方法的JavaScript对象的恰当例子吗?当一个人在构造函数调用过程中使用关闭这个对象的技巧时,是为了编写一个函数,该函数可以被其他不想调用对象方法的对象用作回调。这与正确设置范围无关 下面是一个普通的JavaScri

我想知道创建具有属性和方法的JavaScript对象的最佳方法是什么

我见过这样的例子,人们使用var self=this,然后使用self。在所有功能中,确保范围始终正确

然后,我看到了使用.prototype添加属性的示例,而其他人则使用内联方式


有人能给我一个带有一些属性和方法的JavaScript对象的恰当例子吗?

当一个人在构造函数调用过程中使用关闭这个对象的技巧时,是为了编写一个函数,该函数可以被其他不想调用对象方法的对象用作回调。这与正确设置范围无关

下面是一个普通的JavaScript对象:

function MyThing(aParam) {
    var myPrivateVariable = "squizzitch";

    this.someProperty = aParam;
    this.useMeAsACallback = function() {
        console.log("Look, I have access to " + myPrivateVariable + "!");
    }
}

// Every MyThing will get this method for free:
MyThing.prototype.someMethod = function() {
    console.log(this.someProperty);
};
Foo.publicStaticMethod(); //calling a static method
var test = new Foo();     //instantiation
test.publicMethod();      //calling a method

你可能会从阅读JavaScript的文章中得到很多东西。也很精彩。祝你好运

您也可以这样做,使用以下结构:

function createCounter () {
    var count = 0;

    return {
        increaseBy: function(nb) {
            count += nb;
        },
        reset: function {
            count = 0;
        }
    }
}
然后:

var counter1 = createCounter();
counter1.increaseBy(4);
道格拉斯·克罗克福德(Douglas Crockford)在好的部分广泛地讨论了这个话题。他建议避免使用新操作符创建新对象。相反,他建议创建定制的构造函数。例如:

var mammal = function (spec) {     
   var that = {}; 
   that.get_name = function (  ) { 
      return spec.name; 
   }; 
   that.says = function (  ) { 
      return spec.saying || ''; 
   }; 
   return that; 
}; 

var myMammal = mammal({name: 'Herb'});
在Javascript中,函数是一个对象,可以与新操作符一起用于构造对象。按照惯例,打算用作构造函数的函数以大写字母开头。你经常会看到这样的事情:

function Person() {
   this.name = "John";
   return this;
}

var person = new Person();
alert("name: " + person.name);**

如果在实例化一个新对象时忘记使用new操作符,那么得到的是一个普通的函数调用,它被绑定到全局对象而不是新对象。

我非常频繁地使用这种模式,我发现它在我需要时给了我相当大的灵活性。在使用中,它与Java风格的类非常相似

var Foo = function()
{

    var privateStaticMethod = function() {};
    var privateStaticVariable = "foo";

    var constructor = function Foo(foo, bar)
    {
        var privateMethod = function() {};
        this.publicMethod = function() {};
    };

    constructor.publicStaticMethod = function() {};

    return constructor;
}();
它使用一个匿名函数,在创建时调用该函数,并返回一个新的构造函数。因为匿名函数只被调用一次,所以您可以在其中创建私有静态变量—它们位于闭包内,对类的其他成员可见。构造函数基本上是一个标准的Javascript对象——您可以在其中定义私有属性,而公共属性则附加到此变量

基本上,这种方法将Crockfordian方法与标准Javascript对象相结合,以创建一个更强大的类

您可以像使用任何其他Javascript对象一样使用它:

function MyThing(aParam) {
    var myPrivateVariable = "squizzitch";

    this.someProperty = aParam;
    this.useMeAsACallback = function() {
        console.log("Look, I have access to " + myPrivateVariable + "!");
    }
}

// Every MyThing will get this method for free:
MyThing.prototype.someMethod = function() {
    console.log(this.someProperty);
};
Foo.publicStaticMethod(); //calling a static method
var test = new Foo();     //instantiation
test.publicMethod();      //calling a method

在JavaScript中实现类和实例有两种模型:原型方法和闭包方法。两者都有优点和缺点,并且有很多扩展的变体。许多程序员和库都有不同的方法和类处理实用程序函数来掩盖语言中一些丑陋的部分

结果是,在混合公司中,您将有一堆元类,所有元类的行为都略有不同。更糟糕的是,大多数JavaScript教程材料都很糟糕,并且提供了某种折衷方案来覆盖所有基础,这让您非常困惑。也许作者也感到困惑。JavaScript的对象模型与大多数编程语言非常不同,而且在许多地方设计得很糟糕

让我们从原型方式开始。这是您可以获得的最原始的JavaScript:代码开销最小,instanceof将处理此类对象的实例

function Shape(x, y) {
    this.x= x;
    this.y= y;
}
我们可以通过将新形状创建的实例中的方法写入此构造函数的原型查找,将其添加到实例中:

Shape.prototype.toString= function() {
    return 'Shape at '+this.x+', '+this.y;
};
现在来对它进行子类化,尽可能多地调用JavaScript进行子类化。我们通过完全替换奇怪的魔法原型属性来实现这一点:

function Circle(x, y, r) {
    Shape.call(this, x, y); // invoke the base class's constructor function to take co-ords
    this.r= r;
}
Circle.prototype= new Shape();
在向其添加方法之前:

Circle.prototype.toString= function() {
    return 'Circular '+Shape.prototype.toString.call(this)+' with radius '+this.r;
}
这个例子会起作用,你会在很多教程中看到类似的代码。但是,这个新的形状是丑陋的:我们正在实例化基类,即使没有实际的形状被创建。在这种简单的情况下,它正好可以工作,因为JavaScript太草率了:它允许传入零个参数,在这种情况下,x和y变得未定义,并被分配给原型的this.x和this.y。如果构造函数正在做任何更复杂的事情,那么它就会一败涂地

因此,我们需要做的是找到一种方法来创建一个原型对象,其中包含我们想要在类级别上使用的方法和其他成员,而无需调用基类的构造函数。要做到这一点,我们必须开始编写助手代码。这是我所知道的最简单的方法:

function subclassOf(base) {
    _subclassOf.prototype= base.prototype;
    return new _subclassOf();
}
function _subclassOf() {};
这将基类的原型中的成员转移到一个新的构造函数,该构造函数不做任何事情,然后使用该构造函数。现在我们可以简单地写下:

function Circle(x, y, r) {
    Shape.call(this, x, y);
    this.r= r;
}
Circle.prototype= subclassOf(Shape);
而不是新的形状错误。我们现在有了一组可接受的基本体来构建类

<> P>在这个模型下我们可以考虑一些改进和扩展。例如,这里有一个语法上的sugar版本:

Function.prototype.subclass= function(base) {
    var c= Function.prototype.subclass.nonconstructor;
    c.prototype= base.prototype;
    this.prototype= new c();
};
Function.prototype.subclass.nonconstructor= function() {};

...

function Circle(x, y, r) {
    Shape.call(this, x, y);
    this.r= r;
}
Circle.subclass(Shape);
任何一个版本都没有 他的缺点是构造函数不能被继承,因为在许多语言中都是这样。因此,即使您的子类没有向构造过程添加任何内容,它也必须记住使用基所需的任何参数调用基构造函数。这可以使用apply稍微自动化,但您仍然必须写出:

function Point() {
    Shape.apply(this, arguments);
}
Point.subclass(Shape);
因此,一个常见的扩展是将初始化内容分解为它自己的函数,而不是构造函数本身。然后,此函数就可以从基继承了:

function Shape() { this._init.apply(this, arguments); }
Shape.prototype._init= function(x, y) {
    this.x= x;
    this.y= y;
};

function Point() { this._init.apply(this, arguments); }
Point.subclass(Shape);
// no need to write new initialiser for Point!
现在,我们为每个类提供了相同的构造函数样板。也许我们可以把它移到它自己的helper函数中,这样我们就不必一直键入它,例如,不必键入function.prototype.subclass,将它转过来,让基类的函数吐出子类:

Function.prototype.makeSubclass= function() {
    function Class() {
        if ('_init' in this)
            this._init.apply(this, arguments);
    }
    Function.prototype.makeSubclass.nonconstructor.prototype= this.prototype;
    Class.prototype= new Function.prototype.makeSubclass.nonconstructor();
    return Class;
};
Function.prototype.makeSubclass.nonconstructor= function() {};

...

Shape= Object.makeSubclass();
Shape.prototype._init= function(x, y) {
    this.x= x;
    this.y= y;
};

Point= Shape.makeSubclass();

Circle= Shape.makeSubclass();
Circle.prototype._init= function(x, y, r) {
    Shape.prototype._init.call(this, x, y);
    this.r= r;
};
…它开始看起来有点像其他语言,尽管语法有点笨拙。如果愿意,您可以添加一些额外的功能。也许您希望makeSubclass获取并记住一个类名,并使用它提供一个默认的toString。也许您想让构造函数在没有新运算符的情况下意外调用它时进行检测,否则会导致非常烦人的调试:

Function.prototype.makeSubclass= function() {
    function Class() {
        if (!(this instanceof Class))
            throw('Constructor called without "new"');
        ...
也许你想传入所有的新成员,让makeSubclass将它们添加到原型中,这样你就不用编写类了。。。太多了。许多班级制度都是这样做的,例如:

Circle= Shape.makeSubclass({
    _init: function(x, y, z) {
        Shape.prototype._init.call(this, x, y);
        this.r= r;
    },
    ...
});
在一个对象系统中,你可能会考虑很多潜在的特性,而且没有一个在一个特定的公式上真正达成一致。

那么,就用封闭的方式吧。这避免了JavaScript基于原型的继承的问题,根本不使用继承。相反:

function Shape(x, y) {
    var that= this;

    this.x= x;
    this.y= y;

    this.toString= function() {
        return 'Shape at '+that.x+', '+that.y;
    };
}

function Circle(x, y, r) {
    var that= this;

    Shape.call(this, x, y);
    this.r= r;

    var _baseToString= this.toString;
    this.toString= function() {
        return 'Circular '+_baseToString(that)+' with radius '+that.r;
    };
};

var mycircle= new Circle();
现在Shape的每个实例都有它自己的toString方法和我们添加的任何其他方法或其他类成员的副本

每个实例都有自己的类成员副本的缺点是效率较低。如果您正在处理大量子类实例,那么原型继承可能会更好地为您服务。正如您所看到的,调用基类的方法也有点烦人:在子类构造函数重写它之前,我们必须记住该方法是什么,否则它就会丢失

[还因为这里没有继承,instanceof运算符将不起作用;如果需要,您必须提供自己的类嗅探机制。虽然您可以像处理原型继承一样处理原型对象,但这有点棘手,仅仅让instanceof起作用并不值得。]

每个实例都有自己的方法的好处是,该方法可以绑定到拥有它的特定实例。这是很有用的,因为JavaScript在方法调用中绑定这种奇怪的方式,其结果是,如果将方法与其所有者分离:

var ts= mycircle.toString;
alert(ts());
那么,方法内部的这个实例将不会像预期的那样是圆形实例,而是全局窗口对象,从而导致广泛的调试问题。实际上,通常在采用方法并将其分配给setTimeout、onclick或EventListener时会发生这种情况

使用原型方式,您必须为每个此类任务包含一个闭包:

setTimeout(function() {
    mycircle.move(1, 1);
}, 1000);
或者,将来或现在,如果您破解Function.prototype,也可以使用Function.bind:

如果您的实例是通过闭包方式完成的,那么绑定是通过闭包免费完成的,闭包的实例变量通常称为that或self,尽管我个人建议不要使用self,因为self在JavaScript中已经有了另一个不同的含义。但是,在上面的代码段中,您并没有免费获得参数1,1,因此,如果需要这样做,您仍然需要另一个闭包或绑定

闭包方法也有很多变体。您可能希望完全忽略此项,创建一个新的that并返回它,而不是使用new运算符:

function Shape(x, y) {
    var that= {};

    that.x= x;
    that.y= y;

    that.toString= function() {
        return 'Shape at '+that.x+', '+that.y;
    };

    return that;
}

function Circle(x, y, r) {
    var that= Shape(x, y);

    that.r= r;

    var _baseToString= that.toString;
    that.toString= function() {
        return 'Circular '+_baseToString(that)+' with radius '+r;
    };

    return that;
};

var mycircle= Circle(); // you can include `new` if you want but it won't do anything
哪种方式是“适当的”?二者都哪一个是“最好的”?这取决于你的情况。FWIW当我做强OO的东西时,我倾向于为真正的JavaScript继承设计原型,并为简单的一次性页面效果设计闭包

但是这两种方法对大多数程序员来说都是非常违反直觉的。两者都有许多潜在的混乱变化。如果您使用其他人的代码/库,您将同时遇到这两种方案,以及许多中间方案和通常被破坏的方案。没有一个普遍接受的答案。欢迎来到JavaScript对象的奇妙世界

[这就是为什么JavaScript不是我最喜欢的编程语言的第94部分。]

另一种方法是 我不知道这种处理对象创建和显示功能是否遵循任何特定模式

// Build-Reveal

var person={
create:function(_name){ // 'constructor'
                        //  prevents direct instantiation 
                        //  but no inheritance
    return (function() {

        var name=_name||"defaultname";  // private variable

        // [some private functions]

        function getName(){
            return name;
        }

        function setName(_name){
            name=_name;
        }

        return {    // revealed functions
            getName:getName,    
            setName:setName
        }
    })();
   }
  }

  // … no (instantiated) person so far …

  var p=person.create(); // name will be set to 'defaultname'
  p.setName("adam");        // and overwritten
  var p2=person.create("eva"); // or provide 'constructor parameters'
  alert(p.getName()+":"+p2.getName()); // alerts "adam:eva"
闭包是多功能的。bobince在创建对象时很好地总结了原型与闭包的方法。但是,您可以通过函数式编程方式使用闭包来模拟OOP的某些方面。记住函数是JavaScript中的对象;所以使用 以不同的方式充当对象

下面是一个闭包示例:

function outer(outerArg) {
    return inner(innerArg) {
        return innerArg + outerArg; //the scope chain is composed of innerArg and outerArg from the outer context 
    }
}
不久前,我看到了Mozilla关于闭包的文章。以下是我所看到的:闭包可以让您将环境中的一些数据与操作这些数据的函数关联起来。这与面向对象编程有明显的相似之处,在面向对象编程中,对象允许我们将对象属性中的一些数据与一个或多个方法相关联。这是我第一次读到闭包和经典OOP之间的并行性,没有提及原型

怎么做

假设您要计算某些项目的增值税。增值税可能在应用程序的生命周期内保持稳定。在OOP伪代码中执行此操作的一种方法:

public class Calculator {
    public property VAT { get; private set; }
    public Calculator(int vat) {
        this.VAT = vat;
    }
    public int Calculate(int price) {
        return price * this.VAT;
    }
}
基本上,您将VAT值传递给构造函数,并且您的计算方法可以通过闭包对其进行操作。 现在,不要使用类/构造函数,而是将VAT作为参数传递到函数中。因为您感兴趣的只是计算本身,所以返回一个新函数,即calculate方法:

function calculator(vat) {
    return function(item) {
        return item * vat;
    }
}
var calculate = calculator(1.10);
var jsBook = 100; //100$
calculate(jsBook); //110
在您的项目中,确定顶级值,这些值是计算增值税的最佳候选值。根据经验,每当您不断地传递相同的参数时,有一种方法可以使用闭包来改进它。无需创建传统对象


基本上,JS中没有类的概念,所以我们使用函数作为与现有设计模式相关的类构造函数

//Constructor Pattern
function Person(name, age, job){
 this.name = name;
 this.age = age;
 this.job = job;
 this.doSomething = function(){
    alert('I am Happy');
}
}
到目前为止,JS还不知道你想要创建一个对象,所以这里有一个新的关键字

var person1 = new Person('Arv', 30, 'Software');
person1.name //Arv
参考:面向web开发人员的专业JS-Nik Z继续

var Person = function (lastname, age, job){
this.name = name;
this.age = age;
this.job = job;
this.changeName = function(name){
this.lastname = name;
}
}
var myWorker = new Person('Adeola', 23, 'Web Developer');
myWorker.changeName('Timmy');

console.log("New Worker" + myWorker.lastname);
在es6中,您现在可以实际创建一个类

现在你可以做:

class Shape {
    constructor(x, y) {
        this.x = x;
        this.y = y;
    }

    toString() {
        return `Shape at ${this.x}, ${this.y}`;
    }
}
class Circle extends Shape {
    constructor(x, y, r) {
        super(x, y);
        this.r = r;
    }

    toString() {
        let shapeString = super.toString();
        return `Circular ${shapeString} with radius ${this.r}`;
    }
}
因此,延伸到一个圆圈,就像在另一个答案中,你可以做的那样:

class Shape {
    constructor(x, y) {
        this.x = x;
        this.y = y;
    }

    toString() {
        return `Shape at ${this.x}, ${this.y}`;
    }
}
class Circle extends Shape {
    constructor(x, y, r) {
        super(x, y);
        this.r = r;
    }

    toString() {
        let shapeString = super.toString();
        return `Circular ${shapeString} with radius ${this.r}`;
    }
}
最终在es6中变得更干净,更易于阅读

下面是一个很好的例子:

阶级形态{ 构造器X,y{ 这个.x=x; 这个。y=y; } 托斯特林{ 返回`Shape at${this.x},${this.y}`; } } 类圆形延伸形状{ 构造器x,y,r{ superx,y; 这个。r=r; } 托斯特林{ 设shapeString=super.toString; 返回半径为${this.r}的`圆形${shapeString}`; } } 设c=新的圆圈1,2,4;
console.log+c,c 除了2009年的公认答案之外。如果可以针对现代浏览器,就可以使用Object.defineProperty

Object.defineProperty方法直接在 对象,或修改对象上的现有属性,并返回 物体。 资料来源:

要查看桌面和移动设备兼容性列表,请参阅。是的,IE9+支持它和Safari mobile

你也可以试试这个

    function Person(obj) {
    'use strict';
    if (typeof obj === "undefined") {
        this.name = "Bob";
        this.age = 32;
        this.company = "Facebook";
    } else {
        this.name = obj.name;
        this.age = obj.age;
        this.company = obj.company;
    }

}

Person.prototype.print = function () {
    'use strict';
    console.log("Name: " + this.name + " Age : " + this.age + " Company : " + this.company);
};

var p1 = new Person({name: "Alex", age: 23, company: "Google"});
p1.print();
创建对象 在JavaScript中创建对象的最简单方法是使用以下语法:

var测试={ a:5, b:10, f:功能C{ 返回这个.a+这个.b+c; } } 控制台日志测试; console.logtest.f3;一个适合我的模式
var Klass = function Klass() {
    var thus = this;
    var somePublicVariable = x
      , somePublicVariable2 = x
      ;
    var somePrivateVariable = x
      , somePrivateVariable2 = x
      ;

    var privateMethod = (function p() {...}).bind(this);

    function publicMethod() {...}

    // export precepts
    this.var1 = somePublicVariable;
    this.method = publicMethod;

    return this;
};
首先,您可以更改向实例而不是构造函数的原型对象添加方法的首选项。我几乎总是在构造函数内部声明方法,因为我经常使用构造函数劫持来实现有关继承和装饰器的目的

var Super = function Super() {
    ...
    this.inherited = true;
    ...
};
var Klass = function Klass() {
    ...
    // export precepts
    Super.apply(this);  // extends this with property `inherited`
    ...
};
以下是我如何决定哪些声明是书面的:

永远不要直接在该上下文对象上声明方法 让var声明优先于函数声明 让原语优先于对象{}和[] 让公共声明优先于私有声明 更喜欢Function.prototype.bind而不是self、vm等 避免在另一个类中声明类,除非: 显然,这两者是不可分割的 内部类实现命令模式 内部类实现了Singleton模式 内部类实现状态模式 内部类实现了另一种设计模式,可以保证这一点 始终在闭包空间的词法范围内返回此值。 以下是这些帮助的原因:

构造函数劫持
var Super = function Super() {
    ...
    this.inherited = true;
    ...
};
var Klass = function Klass() {
    ...
    // export precepts
    Super.apply(this);  // extends this with property `inherited`
    ...
};
模型设计 设计模式
var Singleton = new (function Singleton() {
    var INSTANCE = null;

    return function Klass() {
        ...
        // export precepts
        ...

        if (!INSTANCE) INSTANCE = this;
        return INSTANCE;
    };
})();
var a = new Singleton();
var b = new Singleton();
(a === b === true);  // > true
正如您所看到的,我确实不需要这样做,因为我更喜欢Function.prototype.bind或.call或.apply。在我们的单例类中,我们甚至不这样命名它,因为实例传递了更多的信息。对于模型,我们返回它,这样我们就可以使用.call调用构造函数来返回传递给它的实例。我们冗余地将其分配给变量updated,尽管它在其他场景中很有用

除此之外,我更喜欢在{方括号}上使用new关键字构造对象文字:

首选 不喜欢
var klass = Super.apply({
    override: x
});
Klass.prototype.method = function m() {...};
如您所见,后者无法重写其超类的override属性

如果我向类的prototype对象添加方法,我更喜欢对象文字-使用或不使用new关键字:

首选 不喜欢
var klass = Super.apply({
    override: x
});
Klass.prototype.method = function m() {...};

我想提到的是,我们可以使用标题或字符串来声明对象。 有 对每种类型的调用都有不同的方式。见下文:

var测试={ useTitle:这里我们使用“标题”来声明一个对象, “useString”:这里我们使用“字符串”来声明对象, onttitle:函数{ 返回此.usetTitle; }, onString:functiontype{ 返回此[类型]; } } console.logtest.onTitle;

console.logtest.onString'useString';呃,结束这一切都是为了使范围正确。乔纳森是对的。js函数的作用域是您设计的。self=这个技巧是将它与特定实例绑定在一起的一种方法,这样在另一个上下文中调用它时就不会改变。但有时这才是你真正想要的。取决于上下文。我想你们实际上都在说同样的话。self=this虽然不强制保持,但可以通过闭包轻松地允许正确的作用域。这样做的原因是,当它存在于构造函数中时,让嵌套函数访问它的作用域。当嵌套函数位于构造函数内时,它们的this作用域将恢复为全局作用域。没有最佳方法。self不是保留字吗?若否,应是;;因为self是指当前窗口的预定义变量。自我===window@Shaz:与浏览器对象模型中窗口的其他属性(如文档或框架)相比,它不是保留字;您当然可以将标识符重新用作变量名。虽然,是的,在风格上我更喜欢var that=这个,以避免任何可能的混淆。即使window.self最终毫无意义,所以几乎没有任何理由去碰它。当JS被缩小时,将其分配给局部变量(例如self)会减少文件大小。Classjs新链接:是我还是我认为Crockford对新操作符的抨击毫无意义?@meder:不仅仅是你。至少,我认为新接线员没有问题。在var中有一个隐式的新变量={};不管怎样。克罗克福德是个脾气暴躁的老头,我在很多方面都不同意他的观点,但他至少提倡对JavaScript进行批判性的研究,值得听听他说的话。@bobince:同意。他在闭包上的写作让我看到了大约5年前的很多东西,他鼓励一种深思熟虑的方法。我同意Crockford的观点。新操作符的问题是JavaScript会使其上下文与调用函数时的上下文非常不同。尽管有适当的case约定,但在更大的代码基础上仍会出现一些问题,因为开发人员忘记使用new、忘记大写等。为了实用起见,您可以在不使用new关键字的情况下执行所有需要执行的操作-那么为什么要使用它并在代码中引入更多的故障点呢?JS是一种原型语言,而不是基于类的语言。那么,为什么我们希望它像一种静态类型的语言一样工作呢?我当然不喜欢。我不喜欢那样,因为空格很重要。返回后的卷发必须位于同一行,以实现跨浏览器兼容性。这看起来很有趣,因为它离我的主领地C相当近。我也认为我开始理解为什么privateStaticVariable是真正私有的,因为它是在函数的范围内定义的,并且只要有对它的引用,它就会保持活动状态?这里的问题是,每个对象都有它自己的所有私有和公共函数的副本。@virtualnobi:这个模式不会阻止您编写protytpe方法:constructor.prototype.myMethod=函数{…}。ECMA5方法在哪里?函数类{}函数子类{Class.applythis,参数;}子类.prototype=Object.createClass.prototype;从类def到对象实例化的一个非常好的渐进步骤。在绕过新的方面也有不错的表现。JavaScript似乎不是你最喜欢的语言,因为你想像使用类一样使用它。当然,我喜欢,每个人都喜欢:对于程序员今天面临的大多数常见问题,类和实例模型更自然。我确实同意,从理论上讲,基于原型的继承可能提供更灵活的工作方式,但JavaScript完全没有实现这一承诺。它笨重的构造函数系统给了我们两个世界中最糟糕的一面,使得类继承变得很困难,同时也无法提供原型所能提供的灵活性和简单性。简言之,这是poo。Bob我认为这是一个很棒的答案-我已经研究了这两种模式一段时间了,我认为你编写的代码比Resig更简洁,解释的也比Crockford更透彻。我想不出更高的赞誉了……在我看来,将经典继承范例绘制到javascript之类的原型语言上是一个方钉和圆孔。有时这真的是必要的吗?或者这只是一种让人们将语言变成他们想要的方式而不是简单地使用语言的方式吗?接受否决票:如果有一个合理的理由,会更具信息性,并且会
在JS中有一个类的概念,就像你在标题中提到的使用function关键字一样。这不是一种设计模式,而是语言的一种有意的特征。我没有在这个问题上投你反对票,但看起来像是其他人投了反对票,因为这个问题简洁明了,几乎与问题无关。希望这个反馈能有所帮助。这对已经提供的大量答案有什么补充?我喜欢这个答案,因为它简洁明了,并展示了实现的三个部分:1定义对象,2实例化对象实例,3使用实例-它一眼就能显示所有内容,而不是解析所有详细的答案,当然,上面的答案都是非常好的答案,包含了所有需要的相关细节-这里有一个简单的总结