我想知道创建具有属性和方法的JavaScript对象的最佳方法是什么。
我见过这个人使用var self = this
然后在所有函数中使用self.
以确保范围始终正确的示例。
然后我看到了使用.prototype
添加属性的示例,而其他人则是内联的。
有人可以给我一个带有一些属性和方法的JavaScript对象的正确示例吗?
答案 0 :(得分:871)
答案 1 :(得分:90)
我经常使用这种模式 - 我发现它在我需要它时给了我非常大的灵活性。在使用中,它与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对象 - 您在其中定义私有属性,公共属性附加到this
变量。
基本上,这种方法将Crockfordian方法与标准Javascript对象相结合,以创建更强大的类。
您可以像使用任何其他Javascript对象一样使用它:
Foo.publicStaticMethod(); //calling a static method
var test = new Foo(); //instantiation
test.publicMethod(); //calling a method
答案 2 :(得分:24)
Douglas Crockford 在 The Good Parts 中广泛讨论了该主题。他建议避免使用 new 运算符来创建新对象。相反,他建议创建自定义构造函数。例如:
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中,函数是一个对象,可以用于与 new 运算符一起构造对象。按照惯例,旨在用作构造函数的函数以大写字母开头。你经常会看到类似的东西:
function Person() {
this.name = "John";
return this;
}
var person = new Person();
alert("name: " + person.name);**
如果您在实例化新对象时忘记使用 new 运算符,则获得的是普通函数调用,此绑定到全局对象到了新的对象。
答案 3 :(得分:13)
在es6中,您现在可以实际创建class
现在你可以这样做:
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中结束一点清洁,更容易阅读。
这是一个很好的例子:
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}`;
}
}
let c = new Circle(1, 2, 4);
console.log('' + c, c);

答案 4 :(得分:6)
你也可以这样做,使用结构:
function createCounter () {
var count = 0;
return {
increaseBy: function(nb) {
count += nb;
},
reset: function {
count = 0;
}
}
}
然后:
var counter1 = createCounter();
counter1.increaseBy(4);
答案 5 :(得分:5)
另一种方式是http://jsfiddle.net/nnUY4/ (我不知道这种处理对象创建和显示功能是否遵循任何特定模式)
// 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"
答案 6 :(得分:4)
当在构造函数调用期间使用关闭“this”的技巧时,它是为了编写一个函数,该函数可以被一些不想在对象上调用方法的其他对象用作回调。这与“使范围正确”无关。
这是一个vanilla 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);
};
您可能会阅读Douglas Crockford关于JavaScript的内容。 John Resig也很棒。祝你好运!
答案 7 :(得分:4)
Closure
是多才多艺的。 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关于Closure的文章。以下是我的观点:“闭包允许您将一些数据(环境)与对该数据进行操作的函数相关联。这与面向对象编程有明显的相似之处,其中对象允许我们关联某些数据(对象的属性)使用一个或多个方法“。这是我第一次阅读闭包和经典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值传递给构造函数,并且您的calculate方法可以通过 closure 对其进行操作。 现在,不要使用类/构造函数,将VAT作为参数传递给函数。因为您感兴趣的唯一内容是计算本身,所以返回一个新函数,即计算方法:
function calculator(vat) {
return function(item) {
return item * vat;
}
}
var calculate = calculator(1.10);
var jsBook = 100; //100$
calculate(jsBook); //110
在您的项目中,确定最适合计算增值税的顶级值。根据经验,无论何时打开和打开相同的参数,都有一种方法可以使用闭包来改进它。无需创建传统对象。
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Closures
答案 8 :(得分:3)
在JavaScript中创建对象的最简单方法是使用以下语法:
var test = {
a : 5,
b : 10,
f : function(c) {
return this.a + this.b + c;
}
}
console.log(test);
console.log(test.f(3));
这非常适合以结构化方式存储数据。
但是,对于更复杂的用例,创建函数实例通常更好:
function Test(a, b) {
this.a = a;
this.b = b;
this.f = function(c) {
return this.a + this.b + c;
};
}
var test = new Test(5, 10);
console.log(test);
console.log(test.f(3));
这允许您创建共享相同“蓝图”的多个对象,类似于您在例如中使用类的方式。 Java的。
然而,通过使用原型,这仍然可以更有效地完成。
每当函数的不同实例共享相同的方法或属性时,您可以将它们移动到该对象的原型。这样,函数的每个实例都可以访问该方法或属性,但不需要为每个实例复制它。
在我们的例子中,将方法f
移动到原型是有意义的:
function Test(a, b) {
this.a = a;
this.b = b;
}
Test.prototype.f = function(c) {
return this.a + this.b + c;
};
var test = new Test(5, 10);
console.log(test);
console.log(test.f(3));
在JavaScript中进行继承的一种简单但有效的方法是使用以下两行:
B.prototype = Object.create(A.prototype);
B.prototype.constructor = B;
这类似于这样做:
B.prototype = new A();
两者之间的主要区别在于A
的构造函数在使用Object.create
时未运行,Function.prototype.apply()
更直观,更类似于基于类的继承。
您可以选择在创建A
的新实例时选择性地运行B
的构造函数,方法是将其添加到B
的构造函数中:
function B(arg1, arg2) {
A(arg1, arg2); // This is optional
}
如果您想将B
的所有参数传递给A
,您还可以使用Object.assign
:
function B() {
A.apply(this, arguments); // This is optional
}
如果要将另一个对象混合到B
的构造函数链中,可以将Object.create
与polyfill结合使用:
B.prototype = Object.assign(Object.create(A.prototype), mixin.prototype);
B.prototype.constructor = B;
function A(name) {
this.name = name;
}
A.prototype = Object.create(Object.prototype);
A.prototype.constructor = A;
function B() {
A.apply(this, arguments);
this.street = "Downing Street 10";
}
B.prototype = Object.create(A.prototype);
B.prototype.constructor = B;
function mixin() {
}
mixin.prototype = Object.create(Object.prototype);
mixin.prototype.constructor = mixin;
mixin.prototype.getProperties = function() {
return {
name: this.name,
address: this.street,
year: this.year
};
};
function C() {
B.apply(this, arguments);
this.year = "2018"
}
C.prototype = Object.assign(Object.create(B.prototype), mixin.prototype);
C.prototype.constructor = C;
var instance = new C("Frank");
console.log(instance);
console.log(instance.getProperties());
Object.create
可以在每个现代浏览器中安全使用,包括IE9 +。 Object.assign
在任何版本的IE或某些移动浏览器中都不起作用。如果您想使用它们并支持不实现它们的浏览器,建议here Object.create
和/或Object.assign
。
您可以找到Object.create
here的填充物
和Object.assign
{{3}}一个。
答案 9 :(得分:0)
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);
答案 10 :(得分:0)
除了2009年接受的答案外。如果您可以定位现代浏览器,可以使用 Object.defineProperty 。
Object.defineProperty()方法直接定义一个新属性 对象,或修改对象上的现有属性,然后返回 物体。 资料来源:Mozilla
var Foo = (function () {
function Foo() {
this._bar = false;
}
Object.defineProperty(Foo.prototype, "bar", {
get: function () {
return this._bar;
},
set: function (theBar) {
this._bar = theBar;
},
enumerable: true,
configurable: true
});
Foo.prototype.toTest = function () {
alert("my value is " + this.bar);
};
return Foo;
}());
// test instance
var test = new Foo();
test.bar = true;
test.toTest();
要查看桌面和移动兼容性列表,请参阅Mozilla's Browser Compatibility list。是的,IE9 +支持它以及Safari移动。
答案 11 :(得分:0)
你也可以尝试这个
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();
答案 12 :(得分:0)
我想提一下,我们可以使用标题或字符串来声明对象。
调用每种类型的方法有不同的方法。见下文:
var test = {
useTitle : "Here we use 'a Title' to declare an Object",
'useString': "Here we use 'a String' to declare an Object",
onTitle : function() {
return this.useTitle;
},
onString : function(type) {
return this[type];
}
}
console.log(test.onTitle());
console.log(test.onString('useString'));

答案 13 :(得分:-1)
基本上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
参考:适用于网页开发人员的专业JS - Nik Z