我想知道创建具有属性和方法的JavaScript对象的最佳方法是什么。
我见过有人用var self = this然后用self的例子。在所有函数中确保作用域总是正确的。
然后我看到了使用.prototype来添加属性的例子,而其他人则是内联的。
谁能给我一个适当的例子,一个JavaScript对象的一些属性和方法?
我想知道创建具有属性和方法的JavaScript对象的最佳方法是什么。
我见过有人用var self = this然后用self的例子。在所有函数中确保作用域总是正确的。
然后我看到了使用.prototype来添加属性的例子,而其他人则是内联的。
谁能给我一个适当的例子,一个JavaScript对象的一些属性和方法?
当前回答
创建对象
在JavaScript中创建对象最简单的方法是使用以下语法:
Var检验= { A: 5, B: 10, F:函数(c) { 返回。A +这个。B + c; } } console.log(测试); console.log (test.f (3));
这对于以结构化的方式存储数据非常有用。
然而,对于更复杂的用例,创建函数的实例通常更好:
函数测试(a, b) { 这一点。A = A; 这一点。B = B; 这一点。F =函数(c) { 返回。A +这个。B + c; }; } var test = new test (5,10); console.log(测试); console.log (test.f (3));
这允许你创建多个对象共享相同的“蓝图”,类似于你如何使用类在eg。Java。
然而,通过使用原型,这仍然可以更有效地完成。
当一个函数的不同实例共享相同的方法或属性时,您可以将它们移动到该对象的原型中。这样,函数的每个实例都可以访问该方法或属性,但不需要为每个实例复制该方法或属性。
在我们的例子中,将方法f移动到原型中是有意义的:
函数测试(a, b) { 这一点。A = A; 这一点。B = B; } Test.prototype.f =函数(c) { 返回。A +这个。B + c; }; var test = new test (5,10); console.log(测试); console.log (test.f (3));
继承
在JavaScript中进行继承的一个简单而有效的方法是使用以下两行代码:
B.prototype = Object.create(A.prototype);
B.prototype.constructor = B;
这类似于这样做:
B.prototype = new A();
两者之间的主要区别是,A的构造函数在使用Object时不运行。创建,这更直观,更类似于基于类的继承。
你总是可以选择在创建B的新实例时运行A的构造函数,方法是将它添加到B的构造函数中:
function B(arg1, arg2) {
A(arg1, arg2); // This is optional
}
如果你想将B的所有参数传递给A,你也可以使用Function.prototype.apply():
function B() {
A.apply(this, arguments); // This is optional
}
如果你想在B的构造函数链中混合另一个对象,你可以combine object。用Object创建。分配:
B.prototype = Object.assign(Object.create(A.prototype), mixin.prototype);
B.prototype.constructor = B;
Demo
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());
Note
对象。create可以在包括IE9+在内的所有现代浏览器中安全使用。对象。assign不能在任何版本的IE和一些移动浏览器中工作。建议对对象进行填充。创建和/或对象。如果您希望使用它们并支持未实现它们的浏览器,则分配。
你可以为Object找到一个polyfill。建立在这里 还有一个是Object。分配。
其他回答
除了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的浏览器兼容性列表。是的,IE9+和Safari手机版一样支持。
基本上在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
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;
};
首先,您可以更改向实例添加方法的偏好,而不是向构造函数的原型对象添加方法。我几乎总是在构造函数内部声明方法,因为我经常使用构造函数劫持来实现继承和装饰。
以下是我如何决定哪些声明应该写在哪里:
Never declare a method directly on the context object (this) Let var declarations take precedence over function declarations Let primitives take precedence over objects ({} and []) Let public declarations take precedence over private declarations Prefer Function.prototype.bind over thus, self, vm, etc Avoid declaring a Class within another Class, unless: It should be obvious that the two are inseparable The Inner class implements The Command Pattern The Inner class implements The Singleton Pattern The Inner class implements The State Pattern The Inner Class implements another Design Pattern that warrants this Always return this from within the Lexical Scope of the Closure Space.
以下是为什么这些方法有帮助:
Constructor Hijackingvar Super = function Super() {
...
this.inherited = true;
...
};
var Klass = function Klass() {
...
// export precepts
Super.apply(this); // extends this with property `inherited`
...
};
Model Design
var Model = function Model(options) {
var options = options || {};
this.id = options.id || this.id || -1;
this.string = options.string || this.string || "";
// ...
return this;
};
var model = new Model({...});
var updated = Model.call(model, { string: 'modified' });
(model === updated === true); // > true
Design Patterns
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
正如你所看到的,我真的不需要thus,因为我更喜欢Function.prototype.bind(或.call或.apply)而不是thus。在我们的Singleton类中,我们甚至不这样命名它,因为INSTANCE传递了更多的信息。对于Model,我们返回这个,这样就可以使用.call调用构造函数来返回传递给它的实例。多余的是,我们将它分配给变量updated,尽管它在其他场景中很有用。
此外,我更喜欢使用new关键字而不是{括号}来构造对象文字:
Preferredvar klass = new (function Klass(Base) {
...
// export precepts
Base.apply(this); //
this.override = x;
...
})(Super);
Not Preferred
var klass = Super.apply({
override: x
});
如您所见,后者无法覆盖其超类的“override”属性。
如果我确实向类的原型对象添加了方法,我更喜欢对象文字——不管是否使用new关键字:
PreferredKlass.prototype = new Super();
// OR
Klass.prototype = new (function Base() {
...
// export precepts
Base.apply(this);
...
})(Super);
// OR
Klass.prototype = Super.apply({...});
// OR
Klass.prototype = {
method: function m() {...}
};
Not Preferred
Klass.prototype.method = function m() {...};
闭包是万能的。Bobince已经很好地总结了创建对象时的原型与闭包方法。但是,您可以用函数式编程的方式使用闭包来模拟OOP的某些方面。记住,函数在JavaScript中是对象;所以用另一种方式使用function作为对象。
这里有一个闭包的例子:
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之间的相似之处。
How?
假设您想要计算某些项目的增值税。增值税可能在应用程序的生命周期内保持稳定。在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作为参数传递到函数中。因为你唯一感兴趣的东西是计算本身,返回一个新函数,这是计算方法:
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
当一个人在构造函数调用期间使用关闭“this”的技巧时,是为了编写一个函数,可以被其他不希望调用对象上的方法的对象用作回调。这与“使范围正确”无关。
这是一个普通的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的文章,您可能会学到很多东西。约翰·瑞西格也很出色。好运!