可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
There seem to be many different ways of doing OO in JavaScript.
I like:
function ClassA(){};
ClassA.prototype={
someFunc:function(a,b,c){},
otherFunc:function(){}
}
var c=new ClassA();
and have never used features beyond what this provides (despite being a proficient OOer). I suspect this is old fashioned, because every so often I see new spangled variants, and it makes me wonder if I'm choosing the best approach. For instance, you can do magic in the constructor method to create private variables and accessor methods, something I believed (until relatively recently) to be impossible. What about subclassing? I wouldn't know how to achieve this, but it must have some sort of common pattern by now.
How do you do it and why?
回答1:
function foo() {
var bar = function() { console.log("i'm a private method"); return 1; };
var iAmAPrivateVariable = 1;
return {
publicMethod: function() { alert(iAmAPrivateVariable); },
publicVariable: bar()
}
}
//usage
var thing = foo()
This is known as a functional appoach, since you are actually leveraging closures for encapsulation (which is the only way to do it in javascript).
In a general way, you shouldn't be doing OO in javascript, it isn't that great a language for it for a great many reasons. Think scheme with squiggly brackets and semi-colons, and you will start writing the language like the pros do. That being said, sometime OO is a better fit. In those cases, the above is typically the best bet
EDIT: to bring inheritance into the mix
function parent() {
return { parentVariable: 2 };
}
function foo() {
var bar = function() { console.log("i'm a private method"); return 1; };
var iAmAPrivateVariable = 1;
me = parent();
me.publicMethod = function() { alert(iAmAPrivateVariable); };
me.publicVariable = bar();
return me;
}
This makes things a tad more complected, but accomplishes the desired end result while still taking a functional approach to OO concepts (in this case, using decorator functions instead of real inheritance). What I like about the whole approach is we are still really treating objects the way they are intended to be in this kind of language -- a property bag you can attach stuff to at will.
EDIT2:
Just wanted to give credit where credit is due, this approach is a very slight simplification to what doug crockford suggests in Javascript: The Good Parts. If you want to take your js skills to the next level, I would highly suggest starting there. I don't think I have ever learned so much from such a small book.
Another note is this is wildly different then what you will see most of the time in most of the jobs you will ever work at, and often is very hard to explain a) what is going on, and b) why it is a good idea to coworkers.
回答2:
Simple JavaScript Inheritance
Because John Resig said so.
回答3:
"Subclassing" in JavaScript generally refers to prototype-based inheritance, which basically follows this pattern:
function Superclass() { }
Superclass.prototype.someFunc = function() { };
function Subclass() { }
Subclass.prototype = new Superclass();
Subclass.prototype.anotherFunc = function() { };
var obj = new Subclass();
This builds a "prototype chain" from obj -> Subclass.prototype -> Superclass.prototype -> Object.prototype
.
Pretty much every OOP library for JavaScript builds upon this technique, providing functions that abstract most of the prototype "magic".
回答4:
I think joose is a pretty cool way to do OOP in javascript
http://code.google.com/p/joose-js/
回答5:
Objects in JavaScript are unlike almost all the other high-profile languages. Instead of being class-based (like in Java, C++, PHP, etc etc), they are prototype-based. As such, the basic paradigm of object-oriented programming has to be considerably modified. People who can't or don't want to re-think this and insist on using class-based thinking have to build class-based logic in JavaScript or use code from someone else who has already built it.
回答6:
I like to do something like
// namespace "My"
var My = new function {
// private methods
/**
* Create a unique empty function.
* @return {Function} function(){}
*/
function createFn () {return function(){}}
/** A reusable empty function. */
function emptyFn () {}
/**
* Clone an object
* @param {Object} obj Object to clone
* @return {Object} Cloned object
*/
function clone (obj) { emptyFn.prototype=obj; return new emptyFn() }
// public methods
/**
* Merge two objects
* @param {Object} dst Destination object
* @param {Object} src Source object
* @param {Object} [options] Optional settings
* @return {Object} Destination object
*/
this.merge = function (dst, src, options) {
if (!options) options={};
for (var p in src) if (src.hasOwnProperty(p)) {
var isDef=dst.hasOwnProperty(p);
if ((options.noPrivate && p.charAt(0)=='_') ||
(options.soft && isDef) ||
(options.update && !isDef)) continue;
dst[p]=src[p];
}
return dst;
}
/**
* Extend a constructor with a subtype
* @param {Function} superCtor Constructor of supertype
* @param {Function} subCtor Constructor of subtype
* @param {Object} [options] Optional settings
* @return {Function} Constructor of subtype
*/
this.extend = function (superCtor, subCtor, options) {
if (!subCtor) subCtor=createFn();
if (!options) options={};
if (!options.noStatic) this.merge(subCtor, superCtor, options);
var oldProto=subCtor.prototype;
subCtor.prototype=clone(superCtor.prototype);
this.merge(subCtor.prototype, oldProto);
if (!options.noCtor) subCtor.prototype.constructor=subCtor;
return subCtor;
}
}
And then something like...
// namespace "My.CoolApp"
My.CoolApp = new function(){
// My.CoolApp.ClassA
this.ClassA = new function(){
// ClassA private static
var count=0;
// ClassA constructor
function ClassA (arg1) {
count++;
this.someParam=arg1;
}
// ClassA public static
My.merge(ClassA, {
create: function (arg1) {
return new ClassA(arg1);
}
}
// ClassA public
My.merge(ClassA.prototype, {
doStuff : function (arg1) {
alert('Doing stuff with ' + arg1);
},
doOtherStuff : function (arg1) {
alert('Doing other stuff with ' + arg1);
}
}
return ClassA;
}
// My.CoolApp.ClassB
this.ClassB = new function(){
My.extend(My.CoolApp.ClassA, ClassB);
// ClassB constructor
function ClassB () {
ClassA.apply(this, arguments);
}
return ClassB;
}
}
...the clone
function is the key to inheritance. In short:
- Clone an object by making it the prototype of a throwaway function and calling the function with 'new'.
- Clone the parent constructor's prototype, and set it the result as the prototype of the child class.
回答7:
OOP in Javascript for Canvas
Check out how useful OOP in js can be in a different situation... This lets you draw squares and circles as objects
so that you can go back and loop over or manipulate them as you like.
function Shape(x,y,color){
this.x = x
this.y = y
this.color = color
}
function Square(height,width,color){
Shape.call(this, event.x, event.y, color)
this.height = height
this.width = width
this.x -= canvas.offsetLeft + (this.height/2)
this.y -= canvas.offsetTop + (this.width/2)
}
Square.prototype = new Shape();
Square.prototype.draw = function(color){
ctx.fillStyle = color
ctx.fillRect(this.x,this.y,this.height,this.width)
}
function Circle(color, width){
Shape.call(this)
this.x = event.x -60
this.y = event.y -60
this.width = width
}
Circle.prototype = new Shape();
Circle.prototype.draw = function(color){
ctx.beginPath()
ctx.arc(this.x,this.y,this.width,0,2*Math.PI, false);
ctx.fillStyle = color
ctx.fill()
}