I am learning OO programming in Javascript and there seems to be many ways to create a class. I've managed to distill much of what I read into a generic structure, but I feel like I might be missing the purpose of prototyping to save on bloat. Does including the prototype definition in this "class" make them pointless (ie not reducing object size)? Are there any flaws in this overall structure?
Thanks,
var Car = (function () {
//Private fields
var _make;
var _model;
//Constants (protected by encapsulation)
var NUM_OF_WHEELS = 4;
//Private methods
function getDesc() {
return _make + " " + _model;
}
//Public constructor
function thisCar(make, model, color) {
_make = make;
_model = model;
//public properties
thisCar.prototype.color = color;
}
//static properties
thisCar.carsInTheWorld = 50;
//static methods
thisCar.getNumberOfWheels = function () {
return NUM_OF_WHEELS * thisCar.carsInTheWorld;
};
//public properties
thisCar.prototype.color = "";
//public method
thisCar.prototype.startEngine = function () {
console.log(getDesc() + " engine started");
};
return thisCar;
})();
EDIT After reading the ments and the links provided here is what I understand.
Members of the class that require access to private members cannot be added to the prototype and have to be privileged. As well, it is mon practice to not include the prototype in the constructor function.
var Car = function (make, model, color) {//Public constructor
//Private fields
var _make = make;
var _model = model;
//Public fields
this.color = color;
//Private methods
function getDesc() {
return _make + " " + _model;
}
//Privileged functions (requiring private members)
this.startEngine = function () {
console.log(getDesc() + " engine started");
};
};
//public method
Car.prototype.sprayPaint = function (newColor) {
var oldColor = this.color;
this.color = newColor;
console.log("Your car has changed from " + oldColor + " to " + newColor);
};
//Public fields (if not declared in constuctor)
Car.prototype.fuel = 0;
//static properties
Car.carsInTheWorld = 0;
//static methods
Car.getNumberOfWheels = function () {
var NUM_OF_WHEELS = 4;
return NUM_OF_WHEELS * Car.carsInTheWorld;
};
Thanks for all your responses, they really helped.
I am learning OO programming in Javascript and there seems to be many ways to create a class. I've managed to distill much of what I read into a generic structure, but I feel like I might be missing the purpose of prototyping to save on bloat. Does including the prototype definition in this "class" make them pointless (ie not reducing object size)? Are there any flaws in this overall structure?
Thanks,
var Car = (function () {
//Private fields
var _make;
var _model;
//Constants (protected by encapsulation)
var NUM_OF_WHEELS = 4;
//Private methods
function getDesc() {
return _make + " " + _model;
}
//Public constructor
function thisCar(make, model, color) {
_make = make;
_model = model;
//public properties
thisCar.prototype.color = color;
}
//static properties
thisCar.carsInTheWorld = 50;
//static methods
thisCar.getNumberOfWheels = function () {
return NUM_OF_WHEELS * thisCar.carsInTheWorld;
};
//public properties
thisCar.prototype.color = "";
//public method
thisCar.prototype.startEngine = function () {
console.log(getDesc() + " engine started");
};
return thisCar;
})();
EDIT After reading the ments and the links provided here is what I understand.
Members of the class that require access to private members cannot be added to the prototype and have to be privileged. As well, it is mon practice to not include the prototype in the constructor function.
var Car = function (make, model, color) {//Public constructor
//Private fields
var _make = make;
var _model = model;
//Public fields
this.color = color;
//Private methods
function getDesc() {
return _make + " " + _model;
}
//Privileged functions (requiring private members)
this.startEngine = function () {
console.log(getDesc() + " engine started");
};
};
//public method
Car.prototype.sprayPaint = function (newColor) {
var oldColor = this.color;
this.color = newColor;
console.log("Your car has changed from " + oldColor + " to " + newColor);
};
//Public fields (if not declared in constuctor)
Car.prototype.fuel = 0;
//static properties
Car.carsInTheWorld = 0;
//static methods
Car.getNumberOfWheels = function () {
var NUM_OF_WHEELS = 4;
return NUM_OF_WHEELS * Car.carsInTheWorld;
};
Thanks for all your responses, they really helped.
Share Improve this question edited Apr 3, 2012 at 17:02 Phillip asked Apr 2, 2012 at 22:16 PhillipPhillip 2292 silver badges14 bronze badges 7- 3 Personally this kind of coding in JS makes me cringe. It's an incredibly dynamic language and you're right - there are lots of ways to do everything. I would desperately plead to you that you eventually use a class framework (such as JS.Class). – Tony R Commented Apr 2, 2012 at 22:21
- 3 There are lots of problems with your code, too many to go into details here. You can look at my post for types on correct inheritance in JS js-bits.blogspot./2010/08/… – Ruan Mendes Commented Apr 2, 2012 at 22:23
- Frankly upon seeing your code, You should read the MDN guide to get started with Object Oriented Javascript – Starx Commented Apr 2, 2012 at 22:45
- 1 Juan and Starx. Neither of those guides/articles deal with private variables or methods. As well, I have not even though about touching inheritance yet :) I have to agree though, that without private variables this could be written much better. – Phillip Commented Apr 3, 2012 at 16:01
- Tony R: I will look into that framework. It might be better then reinventing the wheel. But I like this problem because it is forcing me to really understand the language. – Phillip Commented Apr 3, 2012 at 16:03
4 Answers
Reset to default 3Instead of using prototype, a mon pattern is to return an object from the constructor that contains your public accessors/mutators:
jsfiddle
function Car() {
var myPrivateVar = "foo";
var myPublicVar = "bar";
function myPrivateFunc() {console.log(myPrivateVar);};
myPrivateFunc();
return {
getMyPublicVar: function() {
return myPublicVar;
}
}
}
var honda = Car();
console.log(honda.getMyPublicVar());
honda.myPrivateFunc(); // fail
Use prototype outside of the class definition to add properties to it. You would use Car.prototype.myFunc = function() {};
after Car
is already defined to add myFunc
to Car
objects instantiated in the future. These added members are public.
Here's a question that should help you
Here's the standard article from Crockford on doing inheritance this way.
I should reiterate that using a class framework such as JS.Class will save you countless headaches when your code grows large.
Think of prototype as a backup repository of methods attached directly to the instance constructor function. If you try to call a property/method on an instance that doesn't have it, the instance's constructor's prototype is then checked for the method. The bummer is that the prototype property can't see inside the instance (to access instance vars).
I encourage you to avoid immediately pouncing on libraries that chain prototypes in order to allow for plex class-like inheritance schemes.
Mostly because this approach tends to stink. It's inflexible, difficult to read and not really a good fit for the sorts of problems JS is good at handling in the first place. (actually such schemes overdone are lousy and remended against in any language). I'm not saying inheritance is bad, just that the holy grail of JavaScript is not to write bad Java and by that I mean 20 layer deep sets of cascading inheritance pletely undecipherable and unalterable by anybody who hasn't spent a couple days looking at them recently.
Don't worry about encapsulation. No really. When is the last time you heard of a front end or UI dev rewriting key innards of jQuery on a plex eCommerce site or changing JQ object methods and other properties directly so it would be useful for something they were working on without a care for all the other stuff that might break? "Trust the user" as the Python kids say. Private instance vars can help clarify what's interface and what's not. Beyond that utility, put it out of your mind and on the internet where everybody can always see our code anyway.
And learn everything you can about functions in JS. There's a lot of stuff going on there that can be useful in JS OOP, where the focus tends to be more on the instances than the constructors. Functions, context and the call/apply methods are keys to ing up with structures that work for you.
You have mixed up a closure and the objectorientated constructor things. Usually, you start without a closure. In JS, you define your "class" by a constructor function:
var Car = function Car(model) { //Public constructor
// Private fields of one instance
// model is an argument
var make;
// Private methods of one instance
function getDesc() {
return make + " " + model;
}
// Public fields of one instance
this.color = "#555";
// Public methods of one instance, privileged the access private fields and functions
this.setMake = function(m) {
make = m;
};
this.desc = function() {
return getDesc();
};
} // end of constructor
/* now the prototype things: */
// public "default" fields, may get overwritten per instance
Car.prototype.color = "";
// public methods, can only access other public things (not "privileged")
thisCar.prototype.startEngine = function () {
console.log(this.desc() + " engine started");
};
That's it. Now, you may add static things. They have nothing to do with the Car
function, but often they get namespaced by beeing properties of the constructor. But they could also be free variables.
var carsInTheWorld = 50;
// or
Car.livingInstances = 50;
// or something
Car.NUM_OF_WHEELS = 4; // constants are uppercase
Only if you need to have static, private variables - e.g. the instances-counter - you may build a closure around everything. Then the unnamespaced variables are only accessible from inside that closure function.
Most of this is fine. This bit is wrong, though:
function thisCar(make, model, color) {
// [ ... ]
//public properties
thisCar.prototype.color = color;
}
Inside the constructor, you should not assign anything to the prototype. That assigns the color property to all Cars created from the constructor.
Instead, do this:
this.color = color;
And to answer the general question, it is not pointless to use the prototype this way. The outer function will only run once, right after the script is parsed. It will assign the internal thisCar constructor to Car
. The prototype properties are properly placed, with the exception noted above.
One other suggestion, though, is that even internally to your IIFE, you should use an uppercase initial letter for the name. I personally would use Car
here too, as it seems clearer.
EDIT:
There is more wrong than I saw at first. This is also wrong
var _make;
var _model;
// [ ... ]
function thisCar(make, model, color) {
_make = make;
_model = model;
}
These are not instance properties.
Moreover, there is no real way that I know of to bine the use of the prototype with closure-based private properties. So I think you're trying to do too much together.
发布者:admin,转转请注明出处:http://www.yc00.com/questions/1744731581a4590497.html
评论列表(0条)