一篇关于javascript面向对象开发的论文
2009-10-25 22:28
585 查看
from:
http://mckoss.com/jscript/object.htm
January 14, 2006
google_hints = "javascript, ajax, programming, object oriented, firefox, internet explorer, action script, flash, web development";
google_ad_client = "pub-5601944029322846";
google_ad_width = 336;
google_ad_height = 280;
google_ad_format = "336x280_as";
google_ad_type = "text_image";
//2007-04-14: Jscript.Square
google_ad_channel = "6459224279";
google_protectAndRun("ads_core.google_render_ad", google_handleError, google_render_ad);
, written in 2003, had several shortcomings, not the
least of which was that the techniques described were specific to Internet Explorer.
I've updated and improved on the original, to document the current state of the art,
especially in light of the extensive interest in AJAX technology and the increasing adoption
of the FireFox browser. All the examples presented here will follow the ECMA language
standards and can be applied to Internet Explorer, FireFox, and ActionScript (in Macromedia Flash).
While early adopters of JavaScript used it as a simple scripting engine to create dynamic
web pages, modern web designers have come to use more sophisticated object oriented
techniques in building their code. I will present here, both the common paradigms used
in object oriented JavaScript programming, and also suggest some helper functions that you
can use in your code to streamline the process.
It should be noted that the current design of the JavaScript language, did not fully anticipate
or fully implement an object oriented system. That is why the subject is somewhat mysterious
and there are various implementations of object oriented programming techniques being used
on the web today. I will describe what I believe to be the most main-stream and compatible implementation
that fits most naturally into the design of the language.
basic tenets of object oriented programming. I consider the three primary goals of object oriented programming to be:
Encapsulation
- Support for method calls on a JavaScript object as a member of a Class.
Polymorphism
- The ability for two classes to respond to the same (collection of) methods.
Inheritance
- The ability to define the behavior of one object in terms of another by sub-classing
.
Through a series of examples (which, for the curious reader, are actually
snippets of live JavaScript code embedded within this page), I will demonstrate
how objects can be used in JavaScript and how these object oriented paradigms
can be best implemented. I will cover techniques for:
Defining a Class
Defining and calling Methods in a Class
Defining a Sub-Class
Calling the Super-Class constructor from a Sub-Class
Overriding Methods of a Super-Class in a Sub-Class
Calling a Super-Class method from a Sub-Class
Doug Crockford's book explains of the best parts of the JavaScript language.
-- Mike Koss
The simplest object oriented construct in JavaScript is the built-in Object
data type.
In JavaScript, objects are implemented as a collection of named properties. Being an
interpreted language, JavaScript allows for the creation of any number of properties
in an object at any time (unlike C++, properties can be added to an object at any time;
they do not have to be pre-defined in an object declaration or constructor).
So, for example, we can create a new object and add several ad-hoc properties to it with the following code:
CodeSample("/
obj = new Object;/n/
obj.x = 1;/n/
obj.y = 2;/
");
obj = new Object;
obj.x = 1;
obj.y = 2;
Which creates a JavaScript object which I will represent graphically like this:
obj.Dump("obj");
delete obj;
The left hand column displays the property name of each available
property on the object, while the right hand column displays it's
value. Note that in addition to the x
and y
properties that we created,
our object has an additional property called constructor
that points (in
this case) to an internal JavaScript function. I will explain prototype
properties, below.
the new
operator, the function serves as the constructor
for that class. Internally,
JavaScript creates an Object
, and then calls the constructor function. Inside the constructor,
the variable this
is initialized to point to the just created Object. This code snippet
defines a new class, Foo
, and then creates a single object of that class.
CodeSample("/
function Foo()/n/
{/n/
this.x = 1;/n/
this.y = 2;/n/
}/n/
/n/
obj = new Foo;/n/
", false, "RegisterConstructor(Foo);");
obj.Dump("obj");
delete obj;
function Foo()
{
this.x = 1;
this.y = 2;
}
obj = new Foo;
Note that we can now create as many Foo
type objects as we want, all of
whom will be properly initialized to have their x
and y
properties
set to 1 and 2, respectively.
. When evaluating an expression
to retrieve a property, JavaScript first looks to see if the property is defined directly in the object. If it is not, it then
looks at the object's prototype to see if the property is defined there. This continues up the prototype chain
until
reaching the root prototype. Each object is associated with a prototype
which comes from the constructor function from which it is created.
For example, if we want to create an object, X, from constructor
function B, whose prototype chain is: B.prototype, A.prototype,
Object.prototype:
We would use the following code:
var g;
CodeSample("/
Object.prototype.inObj = 1;/n/
/n/
function A()/n/
{/n/
this.inA = 2;/n/
}/n/
/n/
A.prototype.inAProto = 3;/n/
/n/
B.prototype = new A; // Hook up A into B's prototype chain/n/
B.prototype.constructor = B;/n/
function B()/n/
{/n/
this.inB = 4;/n/
}/n/
/n/
B.prototype.inBProto = 5;/n/
/n/
x = new B;/n/
document.write(x.inObj + ', ' + x.inA + ', ' + x.inAProto + ', ' + x.inB + ', ' + x.inBProto);/n/
", true, "RegisterConstructor(A);RegisterConstructor(B)");
x.Dump("x");
delete x;
delete Object.prototype.inObj;
Object.prototype.inObj = 1;
function A()
{
this.inA = 2;
}
A.prototype.inAProto = 3;
B.prototype = new A; // Hook up A into B's prototype chain
B.prototype.constructor = B;
function B()
{
this.inB = 4;
}
B.prototype.inBProto = 5;
x = new B;
document.write(x.inObj + ', ' + x.inA + ', ' + x.inAProto + ', ' + x.inB + ', ' + x.inBProto);
1, 2, 3, 4, 5
In FireFox and in ActionScript, an object's prototype can be
explicitly referenced via the non-standard __proto__ property. But in
standard JavaScript a prototype
object can only by directly referenced through the object's constructor
function object.
object. When you call that function using obj.Function()
syntax, it
will execute the function with this
defined as a reference to the object
(just as it was in the constructor).
The standard paradigm for defining methods is to assign functions to a constructor's prototype. That way,
all objects created with the constructor automatically inherit the function references via the prototype chain.
CodeSample("/
function Foo()/n/
{/n/
this.x = 1;/n/
}/n/
/n/
Foo.prototype.AddX = function(y) // Define Method/n/
{/n/
this.x += y;/n/
}/n/
/n/
obj = new Foo;/n/
/n/
obj.AddX(5); // Call Method/n/
", false, "RegisterConstructor(Foo);");
obj.Dump("obj");
delete obj;
function Foo()
{
this.x = 1;
}
Foo.prototype.AddX = function(y) // Define Method
{
this.x += y;
}
obj = new Foo;
obj.AddX(5); // Call Method
Polymorphism
is achieved by simply having different object classes implement a collection of methods
that use the same names. Then, a caller, need just use the correctly named function property to invoke
the appropriate function for each object type.
CodeSample("/
function A()/n/
{/n/
this.x = 1;/n/
}/n/
/n/
A.prototype.DoIt = function() // Define Method/n/
{/n/
this.x += 1;/n/
}/n/
/n/
function B()/n/
{/n/
this.x = 1;/n/
}/n/
/n/
B.prototype.DoIt = function() // Define Method/n/
{/n/
this.x += 2;/n/
}/n/
/n/
a = new A;/n/
b = new B;/n/
/n/
a.DoIt();/n/
b.DoIt();/n/
document.write(a.x + ', ' + b.x);/n/
", true, "RegisterConstructor(A);RegisterConstructor(B);");
a.Dump("a");
b.Dump("b");
delete a;
delete b;
function A()
{
this.x = 1;
}
A.prototype.DoIt = function() // Define Method
{
this.x += 1;
}
function B()
{
this.x = 1;
}
B.prototype.DoIt = function() // Define Method
{
this.x += 2;
}
a = new A;
b = new B;
a.DoIt();
b.DoIt();
document.write(a.x + ', ' + b.x);
2, 3
inheritance of methods from a super class. Any methods defined on the
sub-class
will supersede those defined on the super-class.
CodeSample("/
function A() // Define super class/n/
{/n/
this.x = 1;/n/
}/n/
/n/
A.prototype.DoIt = function() // Define Method/n/
{/n/
this.x += 1;/n/
}/n/
/n/
B.prototype = new A; // Define sub-class/n/
B.prototype.constructor = B;/n/
function B()/n/
{/n/
A.call(this); // Call super-class constructor (if desired)/n/
this.y = 2;/n/
}/n/
/n/
B.prototype.DoIt = function() // Define Method/n/
{/n/
A.prototype.DoIt.call(this); // Call super-class method (if desired)/n/
this.y += 1;/n/
}/n/
/n/
b = new B;/n/
/n/
document.write((b instanceof A) + ', ' + (b instanceof B) + '<BR/>');/n/
b.DoIt();/n/
document.write(b.x + ', ' + b.y);/n/
", true, "RegisterConstructor(A);RegisterConstructor(B);");
b.Dump("b");
delete b;
function A() // Define super class
{
this.x = 1;
}
A.prototype.DoIt = function() // Define Method
{
this.x += 1;
}
B.prototype = new A; // Define sub-class
B.prototype.constructor = B;
function B()
{
A.call(this); // Call super-class constructor (if desired)
this.y = 2;
}
B.prototype.DoIt = function() // Define Method
{
A.prototype.DoIt.call(this); // Call super-class method (if desired)
this.y += 1;
}
b = new B;
document.write((b instanceof A) + ', ' + (b instanceof B) + '<BR/>');
b.DoIt();
document.write(b.x + ', ' + b.y);
true, true
2, 3
Something to keep in mind is that each time a sub-class is defined,
we explicitly call the constructor of the super-class in order
to insert it into our prototype chain. So it is important to ensure
that no undesirable side-effects will occur when this call is made.
Conversely, if the super-class constructor should be called for each
instance of every sub-class, code must be explicitly added
to the sub-class's constructor to make this call (as is done in the
above example).
method which avoids calling the constructor of a super class when each
sub-class
is defined. Three methods are added to the Function object:
document.write("<LISTING>Function.prototype.DeriveFrom = "+StHTML(Function.prototype.DeriveFrom)+"</LISTING>");
document.write("<LISTING>Function.prototype.StName = "+StHTML(Function.prototype.StName)+"</LISTING>");
document.write("<LISTING>Function.prototype.Override = "+StHTML(Function.prototype.Override)+"</LISTING>");
Function.prototype.DeriveFrom = function (fnSuper) {
var prop;
if (this == fnSuper) {
alert("Error - cannot derive from self");
return;
}
for (prop in fnSuper.prototype) {
if (typeof fnSuper.prototype[prop] == "function" &&
!this.prototype[prop]) {
this.prototype[prop] = fnSuper.prototype[prop];
}
}
this.prototype[fnSuper.StName()] = fnSuper;
}Function.prototype.StName = function () {
var st;
st = this.toString();
st = st.substring(st.indexOf(" ") + 1, st.indexOf("("));
if (st.charAt(0) == "(") {
st = "function ...";
}
return st;
}Function.prototype.Override = function (fnSuper, stMethod) {
this.prototype[fnSuper.StName() + "_" + stMethod] = fnSuper.prototype[stMethod];
}
Repeating the sub-classing example using this new paradigm:
CodeSample("/
function A() // Define super class/n/
{/n/
this.x = 1;/n/
}/n/
/n/
A.prototype.DoIt = function() // Define Method/n/
{/n/
this.x += 1;/n/
}/n/
/n/
B.DeriveFrom(A); // Define sub-class/n/
function B()/n/
{/n/
this.A(); // Call super-class constructor (if desired)/n/
this.y = 2;/n/
}/n/
/n/
B.Override(A, 'DoIt');/n/
B.prototype.DoIt = function() // Define Method/n/
{/n/
this.A_DoIt(); // Call super-class method (if desired)/n/
this.y += 1;/n/
}/n/
/n/
b = new B;/n/
/n/
document.write((b instanceof A) + ', ' + (b instanceof B) + '<BR/>');/n/
b.DoIt();/n/
document.write(b.x + ', ' + b.y);/n/
", true, "RegisterConstructor(A);RegisterConstructor(B);");
b.Dump("b");
delete b;
function A() // Define super class
{
this.x = 1;
}
A.prototype.DoIt = function() // Define Method
{
this.x += 1;
}
B.DeriveFrom(A); // Define sub-class
function B()
{
this.A(); // Call super-class constructor (if desired)
this.y = 2;
}
B.Override(A, 'DoIt');
B.prototype.DoIt = function() // Define Method
{
this.A_DoIt(); // Call super-class method (if desired)
this.y += 1;
}
b = new B;
document.write((b instanceof A) + ', ' + (b instanceof B) + '<BR/>');
b.DoIt();
document.write(b.x + ', ' + b.y);
false, true
2, 3
Unfortunately, this technique does not allow for the use of the instanceof
operator to test
for membership of a super-class. But, we have the added benefit that we
can derive from more than one super class (multiple inheritance).
constructor is called, variables declared in the function scope of the
constructor will actually persist beyond the lifetime of the construction
function itself. To access these variables, you need only create local functions
within the scope of the constructor. They may reference local
variables in the constructor.
CodeSample("/
function A()/n/
{/n/
var x = 7;/n/
/n/
this.GetX = function() { return x;}/n/
this.SetX = function(xT) { x = xT; }/n/
}/n/
/n/
obj = new A;/n/
obj2 = new A;/n/
document.write(obj.GetX() + ' ' + obj2.GetX());/n/
obj.SetX(14);/n/
document.write(' ' + obj.GetX() + ' ' + obj2.GetX());/n/
", true, "RegisterConstructor(A);");
obj.Dump("obj");
obj2.Dump("obj2");
delete obj;
delete obj2;
function A()
{
var x = 7;
this.GetX = function() { return x;}
this.SetX = function(xT) { x = xT; }
}
obj = new A;
obj2 = new A;
document.write(obj.GetX() + ' ' + obj2.GetX());
obj.SetX(14);
document.write(' ' + obj.GetX() + ' ' + obj2.GetX());
7 7 14 7
I believe, however, that each instance of an object created in this way, has
it's own copy of each local function. The local copy of the function can
maintain a copy of the local scope (a
closure
) of the constructor.
This would be rather inefficient for object classes that construct many
instances. Experiments with a single (shared) reference to a function
reveal that they can only reference variables from a single instance of the
class. Since the benefits of using private members is rather limited in
the context of JavaScript (which is already lacking any form of type safety), I
would not recommend making extensive use of the private member
paradigm.
Update (June 2009):
I've developed a simple library for building JavaScript
Namespaces (public domain source code)
- for a description see my blog
.
. You may select one to log into:
Logged in as
Logout from DISQUS
Logged in as
using Facebook Connect (Logout)
66
Sort by Popular now
Best Rating
Newest first
Oldest first
Community Page
Subscribe by email
Vamshee
1 year ago
Good piece. I really appreciate it. I have been looking for something like this for a long time...Thank you.
-V
Like
Report
Reply
More ▼
Optional:
Login
or
Connect
mckoss
1 year ago
My
pleasure. A lot's happened in the JavaScript world, even since the
re-write of this article in 2006. My next version should probably show
some of the other commonly used paradigms for defining classes (e.g.,
those used in prototype.js or jQuery.js).
Like
Report
Reply
More ▼
Optional:
Login
or
Connect
phatlikebudda
12 months ago
First
I want to say thanks for the article, it was quite good. It seems so
much of the internet I've seen on javascript is not for programmers.
I'm
quite familiar with the class paradigm in prototype but from what I've
seen there's not much about classes in the sense of OOD for jQuery.
Care to elaborate or point me in a good piece about the jQuery class
paradigm?
Like
Report
Reply
More ▼
Optional:
Login
or
Connect
Bill
11 months ago
Agreed.
I'd also love to see something about how the methods discussed above
can be used in concert with jQuery. I've found nothing worth reading
about OOD alongside jQuery.
Like
Report
Reply
More ▼
Optional:
Login
or
Connect
hhh
6 months ago
ccc
Like
Report
Reply
More ▼
Optional:
Login
or
Connect
Welkin
1 year ago
Thanks
a lot. I've a question though, what's the significance of
"B.prototype.constructor = B;"? (I tried removing this line from the
sample code but didn't see any difference in the results.)
Like
Report
Reply
More ▼
Optional:
Login
or
Connect
mckoss
1 year ago
Without
"B.prototype.constructor = B", any object created from "new B()" will
have the wrong "constructor" value. This could come in to play if code
is explicitly testing what type of object it is. For example, "b
instanceof B" would return false, even though the object was created
from "b = new B();".
Like
Report
Reply
More ▼
Optional:
Login
or
Connect
Joe
11 months ago
This
doesn't seem to be true. If "B.prototype.constructor = B" is commented
out in your code, "b instanceof B" still returns true.
Like
Report
Reply
More ▼
Optional:
Login
or
Connect
mckoss
10 months ago
I think I mis-spoke on the example. If you do this:
x = new B;
document.write(x.constructor == B)
it
will return false instead of true. It's pretty minor, but if there is
some code that is doing some inspection, or want's to clone the object
by calling it's constructor, it will have a reference the superclasses
constructore instead of its own.
Like
Report
Reply
More ▼
Optional:
Login
or
Connect
yuan
9 months ago
thanks, this piece help a lot
Like
Report
Reply
More ▼
Optional:
Login
or
Connect
Aks
2 months ago
Thanks , I too was confused with line B.prototype.constructor = B ;
Like
Report
Reply
More ▼
Optional:
Login
or
Connect
phani
1 month ago
i was also thinking why do we need B.prototype.constructor=B;
this was very helpful...
thanx mckoss
Like
Report
Reply
More ▼
Optional:
Login
or
Connect
oops in java script
1 year ago
a very good article
Like
Report
Reply
More ▼
Optional:
Login
or
Connect
Shaked
1 year ago
As
a Java and Actionscript developer i never really understood OO in
javascript , but this article is very helpful and nicely written .
Thanks a lot !
Like
Report
Reply
More ▼
Optional:
Login
or
Connect
Nitin Jain
1 year ago
good article
thanks
Like
Report
Reply
More ▼
Optional:
Login
or
Connect
Henry
1 year ago
What a lovely tutorial! Thanks so much for taking the time to put this amazing piece of work online.
Nice site by the way...
Like
Report
Reply
More ▼
Optional:
Login
or
Connect
ospx
11 months ago
good stuff, particularly your first kind of creating classes because of the proper usability of the instanceof operator.
Edit: deleted, There was a stupid mistakes on my proposal on entering protected behavior ... sorry
Like
Report
Reply
More ▼
Optional:
Login
or
Connect
Prosunjit
11 months ago
This is really a nice tutorial. I liked it. I think it is very conducive for the neophyte.
Like
Report
Reply
More ▼
Optional:
Login
or
Connect
ChanHan Hy
11 months ago
For beginner of Javascript OOP, it is very good explaination.
Good article!
Like
Report
Reply
More ▼
Optional:
Login
or
Connect
antoniojl
11 months ago
Great
tutorial!!! It sure helped me figure out EXACTLY how JS handles
classing! Very, very, very, very simple and powerful, I say!!!
Like
Report
Reply
More ▼
Optional:
Login
or
Connect
robertmarkbram
10 months ago
Excellent article - thank you for this Mike. It is very helpful.
Two questions.
1) In the section starting "Polymorphism is achieved by simply ..." you have this:
a = new A;
b = new B;
Shouldn't it be this:
a = new A();
b = new B();
2) Is there any difference between these two techniques?
function A() {
this.x = 1;
}
A.prototype.DoIt = function() {
this.x += 1;
}
and
function A() {
this.x = 1;
this.DoIt = DoIt;
}
function DoIt() {
this.x += 1;
}
Like
Report
Reply
More ▼
Optional:
Login
or
Connect
mckoss
10 months ago
1.
"new A" is identical to "new A()". Both will call the constructor with
no arguments [note that all the code on this page is LIVE - you can
view source and see that these examples are executing, and then output
the results inline].
2. Yes, there is a difference between
assigning a function in the constructor or using a prototype. The
former is more efficient to create objects - you don't allocate
additional storage for the function references inside of each instance
- they are all just created once in the prototype, and then referred to
as needed. Functionally, both will work nearly the same; though there
are differences in how functions would be "inherited" if you want to
subclass this constructor.
Like
Report
Reply
More ▼
Optional:
Login
or
Connect
Joaquín L. Robles
10 months ago
excellent!!!
this is what I was looking for...!
thanks!
Like
Report
Reply
More ▼
Optional:
Login
or
Connect
t03
10 months ago
Greatest article I have ever read for JavaScript.
Like
Report
Reply
More ▼
Optional:
Login
or
Connect
mckoss
10 months ago
**blush** - Thanks!
Like
Report
Reply
More ▼
Optional:
Login
or
Connect
janaka
10 months ago
It's Cool - http://janaka077.blogspot.com
Like
Report
Reply
More ▼
Optional:
Login
or
Connect
kasun
9 months ago
This is good. We expect next lesson from you
Like
Report
Reply
More ▼
Optional:
Login
or
Connect
kasun
9 months ago
Advandec things - http://kamatha.blogspot.com/
Like
Report
Reply
More ▼
Optional:
Login
or
Connect
sharie
9 months ago
Can
I save this site??..I haven't reading the informations yet but I think
this is an interesting aand very helpful site for me since I am a
programmer student..
aAAhmm... May I know other helpful site that
contains information like this?....Anyways I want to ask about the
attributes of an object?? can you give me an example????
This site is good!!!
Like
Report
Reply
More ▼
Optional:
Login
or
Connect
slightlymore
9 months ago
Excellent,
thanks a lot! Had to learn about OOJS at university, but through lack
of use, had forgotten most of it as there are a lot of subtleties to
think about (which you don't in C and PHP which I use on a daily
basis). This was a brilliant article, helped me remember a lot, and
which I have delicioused to help again in the future when.
Like
Report
Reply
More ▼
Optional:
Login
or
Connect
don
9 months ago
porque no haces una mejor documentación, digamos, que sea más actualizada,
salu2 y que la chela sea
Like
Report
Reply
More ▼
Optional:
Login
or
Connect
Morgan Cheng
9 months ago
Awesome description about Javascript object modeling.
Like
Report
Reply
More ▼
Optional:
Login
or
Connect
Anthony
8 months ago
In Defining a Subclass, why
B.prototype = new A;
instead of
X=new A; // Once
B.protoype = X
Ie. is it possible to share Xs?
And what does a constructor really do anyway? Is it just assigning function values to slots or is it messing with a prototype.
Like
Report
Reply
More ▼
Optional:
Login
or
Connect
Will
8 months ago
Wish
I had found your site a week ago. Could have really saved some time.
This is the clearest explanation I've found thus far of doing OO in
javascript.
Like
Report
Reply
More ▼
Optional:
Login
or
Connect
Ben nadel
8 months ago
This
is a really great explanation of the prototype chain and how it can be
used in OOP stlye programming. I have read other articles out there on
the subject that make it seem so much more complex.
Like
Report
Reply
More ▼
Optional:
Login
or
Connect
codemeit
8 months ago
Good combination of prototype and OOP. Thanks for the time
Like
Report
Reply
More ▼
Optional:
Login
or
Connect
Roy
7 months ago
Many thanks this is now bookmarked :)
Like
Report
Reply
More ▼
Optional:
Login
or
Connect
jonze
7 months ago
many thanks to your kind of people that make this n00b->semi-n00b transition much much easier :D
Like
Report
Reply
More ▼
Optional:
Login
or
Connect
sj
7 months ago
Great article.
Is
there a function in javascript that can be used to inspect object. for
example in ruby, we can do object.inspect to see internal details of
object
Most of the time I can use JSON, but sometimes it fails.
Thanks
Like
Report
Reply
More ▼
Optional:
Login
or
Connect
Vanya
6 months ago
Use Firebug in Firefox.
Like
Report
Reply
More ▼
Optional:
Login
or
Connect
mckoss
6 months ago
I'd agree. Do a 'console.log(obj)' and you'll be able to manually inspect the object in Firebug; it's quite nice.
Like
Report
Reply
More ▼
Optional:
Login
or
Connect
Jonathan Hawkes, TECHHEAD
6 months ago
To
learn more about the 'new' operator, constructors, and prototype-based
programming, see my article on building the Proto framework (http://devblog.techhead.biz/2009/04/prototype-b...
).
Like
Report
Reply
More ▼
Optional:
Login
or
Connect
Freelance web designer
5 months ago
i read your article on the link you provided, it was usefull, thank you Jonathan.
Like
Report
Reply
More ▼
Optional:
Login
or
Connect
Pete Ford
5 months ago
One
use of the private member paradigm that I find useful is when defining
callbacks which use the object. There I assign "this" to "me" and I can
use "me" in the callbacks to refer to the instance. The following works:
function A(element)
{
this.element = element;
this.message = 'Hello';
var me = this;
this.element.onclick = function(ev)
{
alert(me.message);
}
}
I
was always worried that the "me" was being created in the global scope,
and there might be conflicts when more than one class declared "me" in
this way, but your page has given me comfort about that...
Like
Report
Reply
More ▼
Optional:
Login
or
Connect
batigol
5 months ago
This tutorial is way too brilliant. Many thanks for the effort...
Like
Report
Reply
More ▼
Optional:
Login
or
Connect
mckoss
5 months ago
Thanks!
Like
Report
Reply
More ▼
Optional:
Login
or
Connect
Masih
5 months ago
Thank a lot for your perfect article.
Is there any way to copy local (private) variables to new class in inheritance?
Like
Report
Reply
More ▼
Optional:
Login
or
Connect
Robert Stevens
4 months ago
As a long time practitioner (and promoter) of OOP, using Java and Javascript,
I would like to complement you on your excellent Javascript OOP presentation.
Now three years retired, I enjoy hearing about what's happening in the programming
world -- and to read your page. VERY well done, indeed!
And may I just add, as a retiree who pays probably too much attention to the
current political scene: it's most unfortunate that something like an OO world
view is not available to politicians. It is truly bizarre that we live in a world
in which such estimable things like OOP AND 18th century political practices are
BOTH present. It's a funny old world, isn't it.
Like
Report
Reply
More ▼
Optional:
Login
or
Connect
maxpert
3 months ago
Nice :D
Like
Report
Reply
More ▼
Optional:
Login
or
Connect
hudz
3 months ago
Thanks for the tutorial :)
I have a question, I don't know whether it suit here, but here goes.
var pencilBox = pencilBox || {};
pencilBox = {
sideA: {},
sideB: {},
}
pencilBox.sideA = {
pencil: function(){
this.getSharp = sharpness;
}
}
pencilBox.sideB = {
sharpener: function(){
this.sharpen = sharpen;
}
}
Why this piece of code got error in IE but not in other browsers? and how should I do appropriately in JavaScript or OO manner.
p/s: omit the getSharp() and sharpen method, it’s just for beautify. :p
Thanks.
Like
Report
Reply
More ▼
Optional:
Login
or
Connect
mckoss
3 months ago
The
reason for the IE error is simple - they don't support the "trailing
comma" in object intializers. I wrote a blog post about this here:
http://blog.pageforest.com/2008/07/back-from-pa...
If
you're trying to create a "class" for pencilBox, you should define the
methods in the pencilBox.prototype (see above). That way, all instances
will
have the methods available to them.
Like
Report
Reply
More ▼
Optional:
Login
or
Connect
Juan
3 months ago
This
tutorial is very good. Many thanks for the effort but… I don't
understand the example of Polymorphism. You say: "Polymorphism is
achieved by simply having different object classes implement a
collection of methods that use the same names. Then, a caller, need
just use the correctly named function property to invoke the
appropriate function for each object type" … but the polymorphism ( in
Java, Delphi, and others OOP languages ) has methods with the same name
between a class and a superclass. In the example, the method doIt()
exists in a different classes ( class A and class B ) and they casually
have the same name ( doIt ), I don't see the polymorphism. The
polymorphism in Java ( by example ) is a little more complex ( http://en.wikipedia.org/wiki/Polymorphism_in_ob...
).
Thanks
Like
Report
Reply
More ▼
Optional:
Login
or
Connect
mckoss
3 months ago
In
a strongly typed language, the only way to achieve polymorphism is to
derive different implementations from the same base class. This is to
avoid the sort of accidental name-collision that you describe. Also
note that in modern languages, a polymorphic object need not derive
from an actual base class, but can simply declare that it implements a
particular "abstract interface".
But the underlying concept of
polymorphism more basically, getting two different "types" of objects
to behave the same in some respect. In dynamic languages, like
Javascript (and Python), this is acheived via "Duck Typing" (if it
walks like a duck, quacks like a duck, .... it's a duck). The
"contract" is simply a collection of methods that each of the objects
supports that are sufficient for some piece of code to interact with
them. Note that there need not be a formal base class or abstract
interface defined for this to occur. Simply by implmenting methods, A,
B, and, C, my object can conform to the contract and be used.
While
this is a looser system, it is also more flexible. For example,
contracts can consists of subsets or even overlapping collections of
methods from other contracts (one contract may us methods, A and B,
while another uses B and C).
Note that you can achieve
EVERYTHING you can in this dynamic form or polymorphism as you can in
the strongly typed languages (with the exception of type safety imposed
by the language). So I don't have any qualms about using the term
"polymorphism" in the JavaScript case.
(I also note the first line of the Wikipedia article you quote says exactly what I have:
"Type
polymorphism in object-oriented programming is the ability of one type,
A, to appear as and be used like another type, B. In strongly typed
languages, this usually means that type A somehow derives from type B,
or type A implements an interface that represents type B. In weakly
typed languages types are implicitly polymorphic." -- mike)
Like
Report
Reply
More ▼
Optional:
Login
or
Connect
linjava
2 months ago
Wow,
good question and great answer. I had no idea that Polymorphism had
slightly different definitions with the same underlying them for
dynamic and static languages. Both your article and answers to comments
are very useful Mr. Koss. Thank you for donating so much of your
valuable time to the rest of us!
Like
Report
Reply
More ▼
Optional:
Login
or
Connect
aacv
3 months ago
// Why this is not working?
//
Object.prototype.objSayHello = function(){alert('Hello,from OBJECT
prototype')}; // this one works as I expected, when objSayHello()
Object.prototype ={objSayHello: function(){alert('Hello,from OBJECT prototype')}}; // NOT working !
objSayHello();
// Please email me if you know, thank you! cr7cr8@126.com
Like
Report
Reply
More ▼
Optional:
Login
or
Connect
rick
2 months ago
Your the man! , Best article so far! , you should be a teacher , cant wait to get my coding organized
Like
Report
Reply
More ▼
Optional:
Login
or
Connect
leisulin
2 months ago
Referring
to your example near the beginning where you explain prototypes, I was
not understanding how the interpreter digs up the property values from
the prototype objects when the time comes. But now I think I see what's
really going on:
inB: it's actually attached to x as a property directly (x.inB)
inBProto:
it's not found on x directly, but the interpreter knows to look on
B.prototype to find it; it needs to know the identity of B, which is
its own constructor, and then it looks on that object's prototype
object and finds it like this:
x.constructor.prototype.inBProto
inA: again not a member of x, but it's also a member of B.prototype, and will be found here:
x.constructor.prototype.inA
inAProto: this one's in A's prototype, so we should have to look here:
x.constructor.prototype.constructor.prototype.inAProto
inObj: found on
x.constructor.prototype.constructor.prototype.constructor.prototype.inObj
I
typed all of those expressions in in place of the shorter versions, and
they all still displayed the same result: 1, 2, 3, 4, 5. So somewhere
internally, when the interpreter is looking up a property name, it
probably does something like this: try finding it on the object, no
dice?, try it on theObject.constructor.prototype, no dice?, keep
inserting another constructor.prototype in the middle there until that
newly added prototype object itself is undefined, meaning of course
that the property can't possibly be attached to it, so the ultimate
result is undefined. Am I finally getting this?
What I DON'T get is the code on page 33 of Javascript: The Good Parts, which is heavily related to this discussion:
Function.prototype.method = function(name,func) {
this.prototype[name] = func;
return this;
}
This
is designed to let you add methods without the "ugliness" of the
prototype keyword in there. So, Function now has a new method method
added to its prototype. But next, Mr. Crockford immediately shows how
to define an integer method of Number:
Number.method('integer', function() {
return Math[this < 0 ? 'ceiling' : 'floor'](this);
});
which he puts into use immediately with:
document.writeln((-10/3).integer());
which prints "-3".
I'm
having some major mental block here. We seem to be executing a method
of Number called "method", and the implication is that Number got this
method from the Function.prototype's method method. Does Number
"inherit" from Function? It surely inherits from Object, but from
Function? Would someone please help me out here?
Like
Report
Reply
More ▼
Optional:
Login
or
Connect
manjeet
2 months ago
Great stuff - simple and precise
Like
Report
Reply
More ▼
Optional:
Login
or
Connect
dipak
1 month ago
simply awesome.. thanks for such a nice tutorial.
Like
Report
Reply
More ▼
Optional:
Login
or
Connect
vikram12
1 month ago
Its interesting................
How to inherit a class present in the head of script into div class present in the body.....
Like
Report
Reply
More ▼
Optional:
Login
or
Connect
vikram12
1 month ago
Its interesting................
How to inherit a class present in the head of script into div class present in the body.....
Like
Report
Reply
More ▼
Optional:
Login
or
Connect
anonymous41
3 weeks ago
can any one send me a program in java that is associated with OOP...I need atleast 1 example that works
Like
Report
Reply
More ▼
Optional:
Login
or
Connect
kahenahi
3 weeks ago
kahe
Like
Report
Reply
More ▼
Optional:
Login
or
Connect
shake178
3 weeks ago
thanks for the code, however the "prototype" you were adding to your code is confussing, is it okay to not use them?
Like
Report
Reply
More ▼
Optional:
Login
or
Connect
Ian Lesser
2 weeks ago
I
still tend to write a lot of procedural code in JavaScript, and I
notice that trend is changing. I like your straightforward way of
explaining how JS can actually be used very flexibly for OOP. It
definitely makes for prettier code.
Like
Report
Reply
More ▼
Optional:
Login
or
Connect
Bikash
1 week ago
In
your defining a subclass example, the diagram shows x twice first time
directly under the object and second time under the prototype object.
The values are also different (2 & 1). I think x should appear only
once under the prototype object. Please correct me if I am wrong.
Like
Report
Reply
More ▼
Optional:
Login
or
Connect
#disqus_thread { margin-bottom: 10px; } .dsq-brlink { font-size: 10px; } .logo-disqus { font-family: Arial, sans-serif; text-transform: uppercase; font-size: 9px; font-weight: bold; } #dsq-content .dsq-alert-message { background-color:#FDF1D0; border:1px solid #FAD163; line-height: 1.25; padding: 5px 8px; color: #817134; margin: 10px 0; } #dsq-content iframe, #dsq-popup-alert iframe { border: 0; overflow-y: auto; overflow-x: hidden; *overflow-x: visible; width: 100%; background-color: transparent; height: 355px; <!--[if IE 7]> width: 0px; <![endif]--> } #dsq-content iframe.dsq-post-reply, #dsq-popup-alert iframe.dsq-post-reply { height: 300px; } #dsq-content iframe.dsq-post-reply-authenticated, #dsq-popup-alert iframe.dsq-post-reply-authenticated { height: 170px; } #dsq-content #dsq-comments .dsq-header-avatar .dsq-drop-profile { color: #333; font-size: 11px; font-family: Arial, Helvetica, sans-serif; float: left; left: 0px; position: relative; background: #f0f0f0; z-index: 2; border-left: 1px solid #888; border-right: 1px solid #888; border-bottom: 1px solid #888; -moz-border-radius: 0px 5px 5px 5px; -webkit-border-top-right-radius: 5px; -webkit-border-bottom-right-radius: 5px; -webkit-border-bottom-left-radius: 5px; display: none; min-width: 64px; /* IE6 */ _position: absolute; _top: 32px; _z-index: 9000; } /** * Popup */ .dsq-overlay { display: block; position:absolute; top:0; left:0; width:100%; height:100%; z-index:5000; background-color:#000; -moz-opacity: 0.8; opacity:.80; filter: alpha(opacity=80); } .dsq-overlay[id] { position:fixed; } .dsq-popup h4, .dsq-popup ul, .dsq-popup li, .dsq-popup ol, .dsq-popup div, .dsq-popup table, .dsq-popup td, .dsq-popup th, .dsq-popup p, .dsq-popup a, .dsq-popup cite, .dsq-popup img { border: 0; padding: 0; margin: 0; float: none; text-indent: 0; background: none; } .dsq-popup table { border-collapse: separate; border-spacing: 0; } .dsq-popup { font-size: 13px; color: #333; display: none; position: absolute; z-index: 9999; padding: 0; border: 0; text-align: left; font-family: Arial, Helvetica, sans-serif; } .dsq-popup[id] { position: fixed; } .dsq-popup img { max-width: none; } .dsq-popup ul, .dsq-popup li, .dsq-popup ol { list-style-type: none; list-style-image: none; background: none; display: block; } .dsq-popup li:before { content: ""; } .dsq-popup p, .dsq-popup ul { color: #333; line-height: 1.22em; } .dsq-popup a { color: #1C5392; } .dsq-popup a:hover { color: #869AAD; } .dsq-popup .dsq-popup-top { position: relative; text-align: right; width: 520px; height: 20px; background: transparent url(http://media.disqus.com/images/embed/popup-top.png) no-repeat; } .dsq-popup .dsq-popup-top img { margin: 12px 13px 0 0; *margin: 12px 13px 0 0; } .dsq-popup .dsq-popup-bottom { text-align: right; width: 520px; height: 20px; background: transparent url(http://media.disqus.com/images/embed/popup-bottom.png) no-repeat; } .dsq-popup .powered-by{ font-size: 90%; text-align: right; margin-top: 10px; padding-top: 10px; border-top: 1px solid #ddd; } .dsq-popup .dsq-popup-body div.powered-by a { color: #888; text-decoration:none; } .dsq-popup .dsq-popup-body { width: 520px; background: transparent url(http://media.disqus.com/images/embed/popup-body.png) repeat-y; } .dsq-popup .dsq-popup-body .dsq-popup-header a.dsq-close-link { color:#7aa5d5; position: absolute; top:-8px; right: 5px; text-decoration:none; } .dsq-popup .dsq-popup-body .dsq-popup-header a.dsq-close-link img { width: 23px; height: 24px; border: 0; } .dsq-popup .dsq-subscribe-submit { margin: 0 auto; padding: 0 10px; color: #222; } .dsq-popup .dsq-subscribe-submit input { font-size: 110%; width: 200px; } .dsq-popup p.dsq-popup-notice { padding: 5px; margin: 20px 0 0 0; background-color: #fdf1d0; border: 1px solid #fad163; } /** * New popup */ .dsq-popup .dsq-popup-container { position: relative; } .dsq-popup-container .dsq-popup-b { background:url(http://media.disqus.com/images/facebox/b.png); } .dsq-popup-container .dsq-popup-tl { background:url(http://media.disqus.com/images/facebox/tl.png); } .dsq-popup-container .dsq-popup-tr { background:url(http://media.disqus.com/images/facebox/tr.png); } .dsq-popup-container .dsq-popup-bl { background:url(http://media.disqus.com/images/facebox/bl.png); } .dsq-popup-container .dsq-popup-br { background:url(http://media.disqus.com/images/facebox/br.png); } .dsq-popup-container table { border-collapse: collapse; } .dsq-popup-container td { border-bottom: 0; padding: 0; } .dsq-popup-container .dsq-popup-body { padding: 10px; background: #fff; width: 370px; } .dsq-popup-container .dsq-popup-tl, .dsq-popup-container .dsq-popup-tr, .dsq-popup-container .dsq-popup-bl, .dsq-popup-container .dsq-popup-br { height: 10px; width: 10px; overflow: hidden; padding: 0; } .dsq-popup-container .dsq-popup-title { position: static; text-align: left; background: none; height: auto; width: auto; background-color: #E5EBED; margin: -10px -10px 10px; padding: 10px; border-bottom: 1px solid #2F414B; } .dsq-popup-container .dsq-popup-title img { margin: 0; } .dsq-popup-container .dsq-popup-title h3 { font-size: 18px; font-weight: bold; margin: 0; } .dsq-popup-container h4 { font-size: 14px; font-weight: bold; margin: 0; } /** * Popup : Blacklist */ .dsq-popup .dsq-blacklist-option { padding: 5px 10px; border-bottom: 1px dotted #E5EBED; } /** * Popup : Help */ .dsq-popup ul.dsq-popup-help { margin: 0 10px; } #dsq-popup-message.dsq-popup ul.dsq-popup-help li { margin: 0 0 15px 0; padding: 0 0 10px 0; border-bottom: 1px dotted #E5EBED; } .dsq-popup ul.dsq-popup-help li.dsq-help-otheraccts { font-weight: bold; font-size: 110%; border-bottom-width: 2px; border-bottom-style: solid; } #dsq-popup-message ul.dsq-list-tick li { list-style: none inside url(http://media.disqus.com/images/tick.png) !important; display: list-item; } #dsq-popup-message ul.dsq-list-bluebullet li { list-style: none inside url(http://media.disqus.com/images/bullet_blue.png); display: list-item; } #dsq-popup-message li { margin: 10px 0; padding: 0 10px; border-bottom: 1px dotted #E5EBED; } #dsq-popup-message li li { padding-left: 10px; } /* * Popup : Login */ .dsq-popup iframe#dsq-popup-login { margin-top: 10px; height:310px; width: 100%; } .dsq-popup-login .dsq-popup-content { width: 420px; } /** * Popup : Lightbox : Authenticate */ .dsq-lightbox .dsq-popup-content { width: 550px; } .dsq-lightbox .powered-by { display: none; } .dsq-lightbox img { border: 0 !important; height: auto !important; width: auto !important; } .dsq-lightbox .dsq-lightbox-register-reasons { padding: 0 10px !important; } .dsq-lightbox .dsq-lightbox-register-reasons li { background: url(http://media.disqus.com/images/small-tick.png) no-repeat; padding-left: 12px !important; margin: 0 0 0 6px !important; display: inline !important; font-size: 11px !important; color: #555; } .dsq-lightbox .dsq-lightbox-register-reasons li img { margin-bottom: -1px !important; } .dsq-lightbox .dsq-lightbox-auth-fields { } .dsq-lightbox .dsq-lightbox-submit { height: 1%; overflow: auto; padding: 0 5px; margin-top: 20px; } .dsq-lightbox .dsq-lightbox-auth-post { float: right; padding: 4px; background-color: #EAFFCD; -moz-border-radius: 4px; -webkit-border-radius: 4px; -webkit-border-radisu: 4px; } .dsq-lightbox .dsq-lightbox-auth-skip { float: left; margin-top: 5px; padding: 2px; } .dsq-lightbox .dsq-lightbox-switch-auth { width: 400px; font-size: 11px; text-align: right; margin: 0 auto; } .dsq-lightbox .dsq-lightbox-auth-fields table { padding: 8px; background-color: #EDFFC9; border: 1px solid #A5C469; -moz-border-radius: 4px; -webkit-border-radius: 4px; -webkit-border-radius: 4px; width: 400px; margin: 10px auto; } .dsq-lightbox .dsq-lightbox-auth-fields table td { padding: 4px; } .dsq-lightbox .errorlist { color: #c03000 !important; font-size: 11px; font-weight: bold; margin: 0; padding: 0; } .dsq-lightbox .errorlist li { margin: 5px 0 !important; padding: 0 !important; } .dsq-lightbox-errors p { color: #c03000 !important; font-size: 11px; font-weight: bold; } .dsq-lightbox .dsq-lightbox-auth-fields table td input { font-size: 13px; padding: 2px; } .dsq-lightbox-recognized table { width: 400px; margin: 10px auto; } .dsq-lightbox-recognized table td { padding: 4px; } /* * Popup : Profile */ .dsq-popup-profile .dsq-popup-content { width: 500px; } .dsq-popup-profile .dsq-popup-title { height: 1%; overflow: auto; } .dsq-popup-profile .dsq-popup-title td { vertical-align: top; } .dsq-popup-profile .dsq-popup-title img.dsq-popup-profile-avatar { width: 48px; height: 48px; } .dsq-popup-profile .dsq-popup-profile-user { padding: 0 10px; } .dsq-popup-profile .dsq-popup-profile-user h3 { font-size: 20px; font-weight: bold; margin: 0; } .dsq-popup-profile .dsq-popup-profile-user-stats span { margin-right: 10px; } .dsq-popup-profile .dsq-popup-profile-user-stats big { font-weight: bold; font-size: 16px; } .dsq-popup-profile .dsq-popup-profile-state { clear: both; padding: 15px; background-color: #f0f0f0; border-bottom: 1px solid #aaa; height: auto; overflow: hidden; margin: -10px -10px 0px; border-bottom: 1px solid #B2B2B2; } .dsq-popup-profile .dsq-popup-profile-status { padding: 10px; margin: 0 -10px 0; background-color: #EEF9FD; border-bottom: 1px solid #9FCDE3; } .dsq-popup-profile .dsq-popup-profile-snapshot { padding: 15px 0; } .dsq-popup-profile .dsq-popup-profile-snapshot table { width: 100%; } .dsq-popup-profile .dsq-popup-profile-snapshot table td { width: 50%; vertical-align: top; } .dsq-popup-profile .dsq-popup-profile-snapshot table td h4 { margin-bottom: 5px; } .dsq-popup-profile .dsq-popup-profile-snapshot table td ul { margin-bottom: 15px; max-height: 200px; overflow: auto; } .dsq-popup-profile .dsq-popup-profile-snapshot table td ul img { vertical-align: text-top; margin-right: 5px; } .dsq-popup-profile .dsq-popup-profile-snapshot table td ul li { margin-bottom: 5px; } .dsq-popup-profile .dsq-popup-profile-snapshot table td ul li a { font-size: 12px; text-decoration: none; text-transform: capitalize; } .dsq-popup .dsq-popup-body div.show-more{ padding-left: 10px; font-size: 95%; color:#7aa5d5; } .dsq-popup .dsq-popup-body .dsq-popup-body-padding { padding: 0 10px; font-size: 13px; } .dsq-popup .dsq-popup-body .dsq-popup-header { background-color: #e5ebed; padding: 0 10px; position: relative; padding-bottom: 10px; border-bottom: 1px solid #445460; } .dsq-popup .dsq-popup-body .dsq-popup-header img { border: 1px solid #fff; width: 32px; height: 32px; vertical-align: middle; } .dsq-popup .dsq-popup-body .dsq-popup-body-padding cite { margin-left: 5px; /* top: 8px; position: absolute;*/ font-style: normal; vertical-align: middle; } .dsq-popup .dsq-popup .dsq-popup-body .dsq-popup-body-padding cite { position: static; margin: 0; } .dsq-popup .dsq-popup-body .dsq-popup-body-padding cite span { font-weight: bold; font-size: 150%; font-style: normal; margin-right: 10px; vertical-align: middle; } .dsq-popup .dsq-popup-body .dsq-popup-body-padding .dsq-popuplink { margin: 0 0 0 5px; font-size: 90%; } .dsq-popup .dsq-clout { float: left; width: 72px; height: 32px; line-height: 32px; background: url('http://media.disqus.com/images/embed/clout-background.png') no-repeat top left; } .dsq-popup .dsq-clout.unverified { background: url('http://media.disqus.com/images/embed/unverified-background.png') no-repeat top left; line-height: 24px; } .dsq-popup .dsq-clout a{ float: left; width: 100%; text-align: center; color: #FFF; font-size: 16px; font-weight: bold; text-decoration: none; } .dsq-popup .dsq-clout.unverified a{ font-size: 11px; font-weight: normal; } .dsq-popup .dsq-clout a:hover { color: #fff; } .dsq-popup .dsq-profile-services { padding: 10px; background-color: #f0f0f0; border-bottom: 1px solid #aaa; height: auto; overflow: hidden; } .dsq-popup .dsq-profile-services .dsq-profile-userlvl { padding-bottom: 10px; margin-bottom: 15px; border-bottom: 1px solid #ddd; } .dsq-popup .dsq-profile-services span.dsq-profile-ontheweb { float: left; font-family: Trebuchet MS, Trebuchet, Verdana, sans-serif; font-size: 95%; color: #aaa; } .dsq-popup .dsq-profile-services ul { margin-left: 15px; display: inline; } .dsq-popup .dsq-profile-services ul li{ display: inline; margin-right: 15px; } .dsq-popup .dsq-profile-services ul li.dsq-service-labeltxt{ margin: 0; } .dsq-popup .dsq-profile-services ul li.dsq-service-labeltxt{ margin: 0; } .dsq-popup .dsq-profile-services span.dsq-services-description { font-size: 85%; color: #555; position: absolute; top: 25px; left: 5px; display: none; white-space: nowrap; } .dsq-popup .dsq-profile-services img { border:2px solid #fff; } .dsq-popup a.dsq-profile-follow { color:#7aa5d5; } .dsq-popup .dsq-profile-status, .dsq-popup .dsq-profile-recentcomments { clear: both; padding: 10px; } .dsq-popup .dsq-profile-status p, .dsq-popup .dsq-profile-recentcomments p{ padding: 0; } .dsq-popup .dsq-profile-status h4, .dsq-popup .dsq-profile-recentcomments h4 { font-size: 110%; border-bottom: 2px solid #D7DBDD; margin-bottom: 10px; } .dsq-popup .dsq-profile-status h4 span, .dsq-popup .dsq-profile-recentcomments h4 span { background-color: #D7DBDD; padding: 2px 5px; color: #555; font-weight: bold; } .dsq-popup p.dsq-profile-label { font-family: Trebuchet MS, Trebuchet, Verdana, sans-serif; font-size: 95%; color: #aaa; } .dsq-popup ul.dsq-profile-commentlist { margin-top: 10px; } .dsq-popup .dsq-profile-commentlist li{ padding: 5px 0; border-bottom: 2px solid #e9ebed; } .dsq-popup .dsq-profile-commentlist li img.avatar-small { width: 24px; height: 24px; border: 1px solid #DDD; float: left; } .dsq-popup .dsq-profile-commentlist li .comment-message { margin-left: 30px !important; *float: left !important; *margin-left: 5px !important; } .dsq-popup .dsq-profile-commentlist li span.comment-meta { clear: both !important; margin-left: 30px !important; display: block !important; font-size: 90% !important; background: none !important; float: none !important; width: auto !important; } .dsq-popup .dsq-profile-commentlist span{ color: #666; font-size: 95%; } /** * Menu */ .dsq-menu{ margin: 0 !important; left: 0px; position: absolute; _position: absolute; _left:; background: #f0f0f0 !important; z-index: 2 !important; border-width: 1px !important; border-color: #888 !important; border-style: solid !important; -moz-border-radius: 0px 0px 4px 4px; -webkit-border-bottom-right-radius: 4px; -webkit-border-bottom-left-radius: 4px; display: inline; padding: 5px 10px 5px 0 !important; list-style: none !important; } .dsq-menu li{ margin: 0 !important; padding: 0 !important; clear: both; line-height: 1.3em !important; font-size: 12px !important; margin-bottom: 2px !important; margin-left: 4px !important; white-space: nowrap !important; list-style: none !important; float: none; background: none; text-align: left; } .dsq-menu li:before { content: ""; } .dsq-menu li a.dsq-admin-toggle { font-weight: bold; } .dsq-menu li.dsq-admin-email, .dsq-menu li.dsq-admin-ip { color: #555; font-style: italic; cursor: default; } .dsq-menu li.dsq-menu-sep { border-bottom: 1px dotted #aaa; font-size: 1pt !important; } .dsq-menu li a{ text-decoration: none; color: #333; } .dsq-menu li a:hover { color: #869AAD; } /** * Drop profile */ #dsq-content #dsq-comments .dsq-header-avatar:hover .dsq-drop-profile { display: inline; } #dsq-content #dsq-comments .dsq-drop-profile li{ float: none; clear: both; line-height: 1.3em; padding: 2px 4px; white-space: nowrap; } #dsq-content #dsq-comments .dsq-drop-profile li img { float: none; height: 12px; width: 12px; margin: 0px 4px 0px 0; vertical-align: middle; } #dsq-content #dsq-comments .dsq-drop-profile li a { color: #1C5392; vertical-align: middle; } #dsq-content #dsq-comments .dsq-drop-profile li a:hover { font-weight: bold; } #dsq-content #dsq-comments .dsq-drop-profile li.dsq-drop-services { height: 16px; padding: 4px 4px; } #dsq-content #dsq-comments .dsq-drop-profile li.dsq-drop-services:hover { background-color: #ddd; outline-top: 1px solid #ccc; outline-bottom: 1px solid #ccc; } #dsq-content #dsq-comments .dsq-drop-profile li.dsq-drop-services a { display: block; width: 100%; height: 16px; } #dsq-content #dsq-comments .dsq-drop-profile li.dsq-drop-sep { border-bottom: 1px dotted #aaa; } #dsq-content #dsq-comments .dsq-drop-profile li.dsq-drop-showlnk { padding: 4px 2px; border-bottom: 1px solid #ccc; text-align: center; height: 16px; -moz-border-radius: 0px 5px 0px 0px; -webkit-border-top-right-radius: 5px; } #dsq-content #dsq-comments .dsq-drop-profile li.dsq-drop-showlnk a { font-weight: bold; font-size: 95%; display: block; width: 100%; height: 16px; } #dsq-content #dsq-comments .dsq-drop-profile li.dsq-drop-badge { padding: 6px 2px; text-align: center; font-size: 95%; cursor: help; border-bottom: 1px solid #ddd; } #dsq-content #dsq-comments .dsq-drop-profile li.dsq-drop-badge span { padding: 1px 3px; } #dsq-content #dsq-comments .dsq-drop-profile li.dsq-drop-more { height:16px; background: url(http://media.disqus.com/images/drop-more.gif); background-position: 0px 0px; background-repeat: repeat-x; background-color: #fff; text-align: center; border-top: 1px solid #ddd; -moz-border-radius: 0px 0px 5px 5px; -webkit-border-bottom-right-radius: 5px; -webkit-border-bottom-left-radius: 5px; } #dsq-content #dsq-comments .dsq-drop-profile li.dsq-drop-more:hover { background-position: 0px -20px; border-top: 1px solid #ccc; } #dsq-content #dsq-comments .dsq-drop-profile li.dsq-drop-more a { font-size: 95%; height: 16px; width: 100%; display: block; } #dsq-content #dsq-comments .dsq-drop-profile li.dsq-drop-hidden { display: none; padding: 0; } /*----- Classic Theme -----*/ #disqus_thread #dsq-content iframe.dsq-post-video { height: 370px; overflow: hidden; } #dsq-content #dsq-comments .dsq-header-avatar img{ float: left; margin: 4px; width: 32px; height: 32px; } #dsq-content #dsq-comments .dsq-comment-body{ padding-top: 5px; } #dsq-content #dsq-comments .dsq-header-avatar { width: 32px; height: 34px; height: 43px; width: 40px; } #dsq-content #dsq-comments .dsq-comment:hover .dsq-header-avatar{ background: url('http://media.disqus.com/images/embed/avatar-frame-32.png') no-repeat top left; } #dsq-content #dsq-comments .dsq-comment-header { background: url('http://media.disqus.com/images/embed/header-grey.png') repeat-x; height: 30px; line-height: 30px; height: 38px; line-height: 38px; } #dsq-content { font-size: 13px; } img.dsq-record-img { border: 0; padding: 0; margin: 0; float: none; text-indent: 0; background: none; vertical-align: text-bottom; } a.dsq-brlink { font-size: 10px; color: #666; text-decoration: none; font-family: Trebuchet MS, Trebuchet, Verdana, Arial, sans-serif; } span.disqus { font-family: Trebuchet MS, Trebuchet, Verdana, Arial, sans-serif; font-size: 90%; text-transform: uppercase; color: #64747d; } span.logo-disqus { font-family: Trebuchet MS, Trebuchet, Verdana, Arial, sans-serif; font-size: 95%; text-transform: uppercase; font-weight: bold; } span.logo-disqus.color { color: #64747d; } span.logo-disq { font-family: Trebuchet MS, Trebuchet, Verdana, Arial, sans-serif; font-size: 95%; text-transform: uppercase; color: #64747d; font-weight: bold; } span.logo-us { font-family: Trebuchet MS, Trebuchet, Verdana, Arial, sans-serif; font-size: 95%; text-transform: uppercase; color: #ff9300; font-weight: bold; } span.dsq-downtri { font-size: 70%; } a.dsq-help { color: inherit; text-decoration: none !important; border-color: inherit !important; border-bottom-width: 1px !important; border-bottom-style: dotted !important; cursor: help !important; } #dsq-content #dsq-comments .dsq-editedtxt { margin-top: 15px; font-style: italic; font-size: 85%; opacity: .80; filter: alpha(opacity=80); } #dsq-content #dsq-comments .dsq-likedtxt { font-size: 85%; text-align: right; opacity: .80; filter: alpha(opacity=80); } #dsq-content small { font-size: .7em; } #disqus_thread #dsq-content iframe.dsq-post-reply, #dsq-popup-alert iframe.dsq-post-reply { height: 300px; } #disqus_thread #dsq-content iframe.dsq-post-reply-authenticated, #dsq-popup-alert iframe.dsq-post-reply-authenticated { height: 170px; } .clearfix:after { content:"."; display: block; height: 0; clear: both; visibility: hidden; } #dsq-content #dsq-comments img.icon-adjust { margin-bottom: -3px; } #dsq-content #dsq-comments img.dsq-mod-star { vertical-align: middle; _float: left; _margin-top: 5px; } #disqus_thread #dsq-content ul, #disqus_thread #dsq-content li, #disqus_thread #dsq-content ol, #disqus_thread #dsq-content cite, #disqus_thread #dsq-content img, /* dsq-content */ #dsq-content #dsq-comments ul, #dsq-content #dsq-comments li, #dsq-content #dsq-comments ol, #dsq-content #dsq-comments div, #dsq-content #dsq-comments p, #dsq-content #dsq-comments a, #dsq-content #dsq-comments cite, #dsq-content #dsq-comments img { border: 0; padding: 0; margin: 0; float: none; text-indent: 0; background: none; } #disqus_thread #dsq-content cite, #dsq-content #dsq-comments cite { font-style: normal; } #dsq-content #dsq-comments img { max-width: none; } #disqus_thread #dsq-content li, #disqus_thread #dsq-content ul, #disqus_thread #dsq-content ol, #dsq-content #dsq-extra-links li, #dsq-content #dsq-comments ul, #dsq-content #dsq-comments li, #dsq-content #dsq-comments ol { list-style-type: none; list-style-image: none; background: none; display: block; } #dsq-content #dsq-extra-links li:before, #dsq-content #dsq-comments li:before { content: ""; } #dsq-content #dsq-comments { width: 100%; list-style-type: none; padding: 0; border: 0; } #dsq-content #dsq-comments .dsq-remove-message { color: #555; list-style-type: none; margin: 10px 0; padding: 5px; border: 1px solid #c03000; background-color: #FDDFD0; } #dsq-content #dsq-comments .dsq-comment-alert, #dsq-content #dsq-alerts p { font-weight: bold; color: #555; margin: 15px 0; padding: 5px; background-color: #fdf1d0; border: 1px solid #fad163; } #dsq-content #dsq-comments .dsq-comment-header .dsq-hl-up { background-color: #92C72A; color: #fff; margin:0pt 5px; padding:0 2px; } #dsq-content #dsq-comments .dsq-comment-header .dsq-hl-down { background-color: #c03000; color: #fff; margin:0pt 5px; padding:0 2px; } #dsq-content #dsq-comments .dsq-hl-anchor { background-color: #ffff99 !important; color: #000 !important; } #dsq-content #dsq-comments .dsq-hl-anchor p { color: #000 !important; } #dsq-content #dsq-comments .dsq-hl-anchor a { color: #000 !important; } #dsq-content h3#dsq-comments-count { width: 99%; } /** * Misc Items */ #dsq-content .dsq-item-feed a { text-decoration: none; } /** * Auth Header */ #dsq-content #dsq-auth .dsq-auth-header{ margin-bottom: 10px; width: 99%; } #dsq-content #dsq-auth .dsq-authenticated { margin-bottom: 10px; display: none; height: auto; overflow: hidden; } #dsq-content #dsq-auth .dsq-authenticated-pic { float: left; } #dsq-content #dsq-auth .dsq-authenticated-pic img { height: 48px; width: 48px; } #dsq-content #dsq-auth .dsq-authenticated-info { float: left; } #dsq-content #dsq-auth .dsq-authenticated-info ul { padding: 0 0 0 5px; margin: 0; list-style-type:none; } #dsq-content #dsq-auth .dsq-authenticated-info ul li { margin-bottom: 5px; } #dsq-content #dsq-auth .dsq-authenticated-info ul li.logout { font-size: 0.8em; } #dsq-content #dsq-auth .dsq-authenticated-info ul li.logout a { text-decoration: none; } #dsq-content #dsq-auth .dsq-authenticated-info ul li.logout img { margin-bottom: -2px; } #dsq-content h3 { margin: 10px 0; } #disqus_thread #dsq-content h3 { font-weight: bold; } #dsq-content #dsq-auth.dsq-auth-bottom { margin-top: 20px; } #dsq-content .dsq-by { float: right; } #dsq-content #dsq-login { float: none; } #dsq-content #dsq-login .dsq-login-message { margin-bottom: 10px; } #dsq-content #dsq-comments .dsq-login-icon { margin-bottom: -2px; } #dsq-content .dsq-auth-header img, #dsq-content #dsq-options-toggle img { border: 0; margin: 0; padding: 0; max-width: none; float: none; } #dsq-content #dsq-options { margin-bottom: 20px; } #dsq-options .dsq-extra-meta { background: transparent url('http://media.disqus.com/images/embed/transp-line-10.png') repeat-x top center; margin-top:10px; padding-top:10px; } #dsq-extra-links { margin-top: 15px; font-size: 90%; } #dsq-extra-links img { margin-bottom: -3px; } /** * Reply bar */ #dsq-content #dsq-comments .dsq-reply-bar { margin: 15px 0; } #dsq-content #dsq-comments .dsq-reply-bar img { margin-bottom: -2px; } #dsq-content #dsq-comments a.dsq-reply-req-opt { font-size: 100%; margin-right: 5px; opacity: .80; filter: alpha(opacity=80); } #dsq-content #dsq-comments .dsq-reply-bar-items { float: right; } #dsq-content #dsq-comments .dsq-reply-bar-auth { font-size: .9em; } #dsq-content #dsq-comments .dsq-reply-bar-auth .dsq-no-anon-msg { margin: 5px 0 2px 0; } #dsq-content #dsq-comments .dsq-reply-bar-auth img.dsq-post-avatar { height: 24px; width: 24px; } #dsq-content #dsq-auth ul.dsq-media-items li, #dsq-content #dsq-comments ul.dsq-media-items li { display: inline; font-size: .90em; } /** * Pagination */ #dsq-content #dsq-pagination { margin: 20px 0; } #dsq-content #dsq-pagination a { font-weight: bold; } #dsq-content #dsq-pagination a, #dsq-content #dsq-pagination span { margin-right: 5px; } #dsq-content #dsq-pagination span.dsq-paginate-ellipsis { font-size: 110%; } #dsq-content #dsq-pagination a.dsq-paginate-arrows span { margin: 0; padding: 0; font-family: Lucida Sans Unicode, sans-serif; } #dsq-content .dsq-paginate-append-text { display: inline; } #dsq-content .dsq-paginate-append-button { display: none; } /** * Badges */ span.dsq-badge { font-family: Optima, Lucida Grande, Lucida Sans, Helvetica, Arial, sans-serif; padding: 2px 4px; -moz-border-radius: 0px 5px 0px 5px; -webkit-border-top-right-radius: 5px; -webkit-border-bottom-left-radius: 5px; vertical-align: middle; } span.dsq-badge.dsq-badge-verified { background-color: #92C72A; border: 1px solid #6ca300; color: #fff; } span.dsq-badge.dsq-badge-registered { background-color: #fffe98; border: 1px solid #eae800; color: #000; } span.dsq-badge-verified, span.dsq-badge-registered, span.dsq-badge-guest, span.dsq-badge-facebook, span.dsq-badge-twitter, span.dsq-badge-openid { font-family: Optima, Lucida Grande, Lucida Sans, Helvetica, Arial, sans-serif; padding: 2px 4px; -moz-border-radius: 0px 5px 0px 5px; -webkit-border-top-right-radius: 5px; -webkit-border-bottom-left-radius: 5px; vertical-align: middle; } span.dsq-badge-verified { background-color: #92C72A; border: 1px solid #6ca300; color: #fff; } span.dsq-badge-registered { background-color: #fffe98; border: 1px solid #eae800; color: #000; } span.dsq-badge-guest { background-color: #ddd; border: 1px solid #ccc; color: #333; } span.dsq-badge-facebook { background-color: #46639d; color: #fff; } span.dsq-badge-twitter { background-color: #31ceff; color: #fff; } span.dsq-badge-openid { background-color: #f9f9f9; border: 1px solid #aaa; color: #f7931e; } /** * OpenID */ table.dsq-openid-form { margin-left: 10px; margin-bottom: 20px; } table.dsq-openid-form img { width: 50px; height: 50px; margin-right: 10px; } table.dsq-openid-form td.dsq-openid-submit { padding-top: 5px; text-align: right; } /** * Linkbacks */ #dsq-content span.dsq-item-trackback { margin: 15px 0; } #dsq-content input.dsq-trackback-url { width: 150px; font-size: 10px; color: #666; } #disqus_thread #dsq-content ul#dsq-references li { margin-bottom: 20px; display: list-item; list-style: disc; margin-left: 15px; } #disqus_thread #dsq-content ul#dsq-references cite { margin-bottom: 0px; padding-bottom: 0px; font-weight: bold; } #disqus_thread #dsq-content ul#dsq-references p.dsq-meta { margin-top: 0px; padding-top: 0px; font-size: 95%; } /* Reactions */ #disqus_thread #dsq-content li.dsq-reaction { padding: 0; margin: 0; border: 0; list-style-type: none; margin-left: 0px; color: #000; margin-bottom: 20px; } #disqus_thread #dsq-content li.dsq-reaction:before { content: ""; } #disqus_thread #dsq-content .dsq-reaction-header { background: url('http://media.disqus.com/images/embed/header-grey.png') repeat-x; } #disqus_thread #dsq-content .dsq-reaction-header a { text-decoration: none; } #disqus_thread #dsq-content .dsq-reaction .dsq-header-avatar { position: relative; margin-top: 2px; float: left; height: 32px; width: 32px; } #disqus_thread #dsq-content .dsq-reaction .dsq-header-avatar img { float: left; width: 32px; height: 32px; } #disqus_thread #dsq-content .dsq-reaction .dsq-header-avatar img.dsq-service-icon { width: 12px; height: 12px; position: relative; margin-top: -12px; margin-left: 20px; } #disqus_thread #dsq-content .dsq-reaction-header cite { float: left; font-style: normal; font-weight: bold; margin: 0 5px; line-height: inherit; cursor: pointer; } #disqus_thread #dsq-content .dsq-reaction-header cite a { line-height: inherit; } #disqus_thread #dsq-content .dsq-reaction-header .dsq-header-meta { font-size: 90%; line-height: inherit; } #disqus_thread #dsq-content .dsq-reaction a.dsq-header-time { margin: 0 5px; color: inherit; line-height: inherit; } #disqus_thread #dsq-content .dsq-reaction-body { clear: left; padding-top: 5px; } #disqus_thread #dsq-content .dsq-reaction-footer { opacity: .35; filter: alpha(opacity=35); font-size: 90%; margin: 5px 0 0 0px; } #disqus_thread #dsq-content .dsq-reaction-footer a { color: inherit; text-decoration: none; } #disqus_thread #dsq-content .dsq-reaction-footer a:hover { text-decoration: underline; } #disqus_thread #dsq-content .dsq-reaction-retweets { border-left: solid 5px #666; margin-top: 10px; padding-left: 5px; } #disqus_thread #dsq-content .dsq-service-name { text-transform: capitalize; } #disqus_thread #dsq-content li#dsq-show-more-reactions { text-align: center; } /** * Introduced in Embed 2.0 */ #dsq-content #dsq-comments .dsq-comment-footer { height: auto; overflow: hidden; } #dsq-content #dsq-comments .dsq-comment-options { float: right; list-style: none; } #dsq-content #dsq-comments ul.dsq-list-style li { display: inline; background-image: url(http://media.disqus.com/images/middot.png); _background-image: url(http://media.disqus.com/images/middot.gif); background-repeat: no-repeat; background-position: 0 50%; padding-left: 1.6em; } #dsq-content #dsq-comments ul.dsq-list-style li.dsq-list-first { background: none; padding: 0; } /** * Reactions */ #disqus_thread #dsq-content ul#dsq-reactions li.dsq-reaction { padding: 0; margin: 0; border: 0; list-style-type: none; margin-left: 0px; color: #000; margin-bottom: 20px; } #dsq-content ul#dsq-reactions .dsq-reaction-header { background: url('http://media.disqus.com/images/embed/header-grey.png') repeat-x; height: 38px; line-height: 38px; *overflow-y: hidden; } #dsq-content ul#dsq-reactions .dsq-reaction-header a { text-decoration: none; } #dsq-content ul#dsq-reactions .dsq-header-avatar { position: relative; float: left; margin-top: 2px; height: 35px; width: 40px; } #dsq-content ul#dsq-reactions .dsq-header-avatar img { float: left; width: 32px; height: 32px; } #dsq-content ul#dsq-reactions .dsq-header-avatar img.dsq-service-icon { width: 12px; height: 12px; position: relative; margin-top: -12px; margin-left: 20px; } #dsq-content ul#dsq-reactions .dsq-reaction-header cite { float: left; font-style: normal; font-weight: bold; margin: 0 3px 0 5px; line-height: inherit; cursor: pointer; } #dsq-content ul#dsq-reactions .dsq-reaction-header cite a { line-height: inherit; } #dsq-content ul#dsq-reactions .dsq-reaction-header .dsq-header-meta { font-size: 90%; float: left; line-height: inherit; } #dsq-content ul#dsq-reactions a.dsq-header-time { margin: 0 5px; color: inherit; line-height: inherit; } #dsq-content ul#dsq-reactions .dsq-reaction-body { clear: both; padding-top: 5px; } #dsq-content ul#dsq-reactions .dsq-reaction-footer { font-size: 90%; margin: 5px 0 0 0px; } /*----- Comments (comments-1.css) -----*/ #dsq-content #dsq-comments .dsq-comment { list-style-type: none; padding: 0; margin: 0; border: 0; } #dsq-content #dsq-comments .dsq-comment { margin-bottom: 20px; } #dsq-content #dsq-comments .dsq-comment-rate { float: left; line-height: 1.22em; *margin-top: 15px; } #dsq-content #dsq-comments .dsq-comment-rate a, #dsq-content #dsq-comments .dsq-comment-rate img { border: 0; margin: 0; padding: 0; background-color: transparent; } #dsq-content #dsq-comments .dsq-arrows, #dsq-content #dsq-comments .not-votable .dsq-arrows:hover { opacity: .25; filter: alpha(opacity=25); _width: 16px; _height: 14px; }/ #dsq-content #dsq-comments .dsq-arrows.voted { opacity: .5; filter: alpha(opacity=50); } #dsq-content #dsq-comments .dsq-arrows:hover { opacity: 1; filter: alpha(opacity=100); } #dsq-content #dsq-comments .dsq-arrows img { _width: 16px; _height: 14px; } #disqus_thread #dsq-content #dsq-comments .dsq-header-avatar { position: relative; float: left; margin-top: -2px; } #dsq-content #dsq-comments .dsq-comment.special .dsq-comment-header { background: url('http://media.disqus.com/images/embed/header-blue.png') repeat-x; } #dsq-content #dsq-comments .dsq-comment-header a { text-decoration: none; } #dsq-content #dsq-comments .dsq-comment-header cite { float: left; font-style: normal; font-weight: bold; margin: 0 3px; line-height: inherit; } #dsq-content #dsq-comments .dsq-comment-header cite a { line-height: inherit; } #dsq-content #dsq-comments .dsq-comment-header .dsq-header-meta { font-size: 90%; line-height: inherit; } #dsq-content #dsq-comments a.dsq-header-time{ margin: 0 5px; color: inherit; line-height: inherit; } #dsq-content #dsq-comments span.dsq-header-points{ margin: 0 5px; color: inherit; line-height: inherit; } #dsq-content #dsq-comments .dsq-comment-footer { font-size: 90%; margin: 10px 0 0 0; } #dsq-content #dsq-comments .dsq-footer-alert { text-align: right; }
blog comments powered by Disqus
(PDF)
- ECMAScript Standard Documentation
JavaScript Closures
- Detailed (if lengthy) explanation of JavaScript closures, along with
efficiency concerns especially with the inability of the garbage collector to
clean up function calls in the presence of possible closures.
google_ad_client = "pub-5601944029322846";
google_ad_width = 728;
google_ad_height = 15;
google_ad_format = "728x15_0ads_al";
//2007-04-14: JScript.Links
google_ad_channel = "7327752269";
google_protectAndRun("ads_core.google_render_ad", google_handleError, google_render_ad);
_uacct = "UA-177353-1";
urchinTracker();
http://mckoss.com/jscript/object.htm
Object Oriented Programming in JavaScript
by Mike KossJanuary 14, 2006
google_hints = "javascript, ajax, programming, object oriented, firefox, internet explorer, action script, flash, web development";
google_ad_client = "pub-5601944029322846";
google_ad_width = 336;
google_ad_height = 280;
google_ad_format = "336x280_as";
google_ad_type = "text_image";
//2007-04-14: Jscript.Square
google_ad_channel = "6459224279";
google_protectAndRun("ads_core.google_render_ad", google_handleError, google_render_ad);
Introduction
The first version of this paper, written in 2003, had several shortcomings, not the
least of which was that the techniques described were specific to Internet Explorer.
I've updated and improved on the original, to document the current state of the art,
especially in light of the extensive interest in AJAX technology and the increasing adoption
of the FireFox browser. All the examples presented here will follow the ECMA language
standards and can be applied to Internet Explorer, FireFox, and ActionScript (in Macromedia Flash).
While early adopters of JavaScript used it as a simple scripting engine to create dynamic
web pages, modern web designers have come to use more sophisticated object oriented
techniques in building their code. I will present here, both the common paradigms used
in object oriented JavaScript programming, and also suggest some helper functions that you
can use in your code to streamline the process.
It should be noted that the current design of the JavaScript language, did not fully anticipate
or fully implement an object oriented system. That is why the subject is somewhat mysterious
and there are various implementations of object oriented programming techniques being used
on the web today. I will describe what I believe to be the most main-stream and compatible implementation
that fits most naturally into the design of the language.
Object Oriented Programming Goals
I assume that the reader has a basic familiarity with JavaScript, function calls, and thebasic tenets of object oriented programming. I consider the three primary goals of object oriented programming to be:
Encapsulation
- Support for method calls on a JavaScript object as a member of a Class.
Polymorphism
- The ability for two classes to respond to the same (collection of) methods.
Inheritance
- The ability to define the behavior of one object in terms of another by sub-classing
.
Through a series of examples (which, for the curious reader, are actually
snippets of live JavaScript code embedded within this page), I will demonstrate
how objects can be used in JavaScript and how these object oriented paradigms
can be best implemented. I will cover techniques for:
Defining a Class
Defining and calling Methods in a Class
Defining a Sub-Class
Calling the Super-Class constructor from a Sub-Class
Overriding Methods of a Super-Class in a Sub-Class
Calling a Super-Class method from a Sub-Class
Simple Objects
Doug Crockford's book explains of the best parts of the JavaScript language.
-- Mike Koss
The simplest object oriented construct in JavaScript is the built-in Object
data type.
In JavaScript, objects are implemented as a collection of named properties. Being an
interpreted language, JavaScript allows for the creation of any number of properties
in an object at any time (unlike C++, properties can be added to an object at any time;
they do not have to be pre-defined in an object declaration or constructor).
So, for example, we can create a new object and add several ad-hoc properties to it with the following code:
CodeSample("/
obj = new Object;/n/
obj.x = 1;/n/
obj.y = 2;/
");
obj = new Object;
obj.x = 1;
obj.y = 2;
Which creates a JavaScript object which I will represent graphically like this:
obj.Dump("obj");
delete obj;
obj | |
x | 1 |
y | 2 |
Object.prototype | |
constructor | Object |
property on the object, while the right hand column displays it's
value. Note that in addition to the x
and y
properties that we created,
our object has an additional property called constructor
that points (in
this case) to an internal JavaScript function. I will explain prototype
properties, below.
Defining a Class - Object Constructors
A new JavaScript class is defined by creating a simple function. When a function is called withthe new
operator, the function serves as the constructor
for that class. Internally,
JavaScript creates an Object
, and then calls the constructor function. Inside the constructor,
the variable this
is initialized to point to the just created Object. This code snippet
defines a new class, Foo
, and then creates a single object of that class.
CodeSample("/
function Foo()/n/
{/n/
this.x = 1;/n/
this.y = 2;/n/
}/n/
/n/
obj = new Foo;/n/
", false, "RegisterConstructor(Foo);");
obj.Dump("obj");
delete obj;
function Foo()
{
this.x = 1;
this.y = 2;
}
obj = new Foo;
obj | |
x | 1 |
y | 2 |
Foo.prototype | |
constructor | Foo |
Object.prototype | |
(constructor) | Object |
type objects as we want, all of
whom will be properly initialized to have their x
and y
properties
set to 1 and 2, respectively.
Prototypes Explained
In JavaScript, each Object can inherit properties from another object, called it's prototype. When evaluating an expression
to retrieve a property, JavaScript first looks to see if the property is defined directly in the object. If it is not, it then
looks at the object's prototype to see if the property is defined there. This continues up the prototype chain
until
reaching the root prototype. Each object is associated with a prototype
which comes from the constructor function from which it is created.
For example, if we want to create an object, X, from constructor
function B, whose prototype chain is: B.prototype, A.prototype,
Object.prototype:
We would use the following code:
var g;
CodeSample("/
Object.prototype.inObj = 1;/n/
/n/
function A()/n/
{/n/
this.inA = 2;/n/
}/n/
/n/
A.prototype.inAProto = 3;/n/
/n/
B.prototype = new A; // Hook up A into B's prototype chain/n/
B.prototype.constructor = B;/n/
function B()/n/
{/n/
this.inB = 4;/n/
}/n/
/n/
B.prototype.inBProto = 5;/n/
/n/
x = new B;/n/
document.write(x.inObj + ', ' + x.inA + ', ' + x.inAProto + ', ' + x.inB + ', ' + x.inBProto);/n/
", true, "RegisterConstructor(A);RegisterConstructor(B)");
x.Dump("x");
delete x;
delete Object.prototype.inObj;
Object.prototype.inObj = 1;
function A()
{
this.inA = 2;
}
A.prototype.inAProto = 3;
B.prototype = new A; // Hook up A into B's prototype chain
B.prototype.constructor = B;
function B()
{
this.inB = 4;
}
B.prototype.inBProto = 5;
x = new B;
document.write(x.inObj + ', ' + x.inA + ', ' + x.inAProto + ', ' + x.inB + ', ' + x.inBProto);
1, 2, 3, 4, 5
x | |
inB | 4 |
B.prototype | |
constructor | B |
inA | 2 |
inBProto | 5 |
A.prototype | |
(constructor) | A |
inAProto | 3 |
Object.prototype | |
(constructor) | Object |
inObj | 1 |
explicitly referenced via the non-standard __proto__ property. But in
standard JavaScript a prototype
object can only by directly referenced through the object's constructor
function object.
Defining and Calling Methods in a Class
JavaScript allows you to assign any function to a property of anobject. When you call that function using obj.Function()
syntax, it
will execute the function with this
defined as a reference to the object
(just as it was in the constructor).
The standard paradigm for defining methods is to assign functions to a constructor's prototype. That way,
all objects created with the constructor automatically inherit the function references via the prototype chain.
CodeSample("/
function Foo()/n/
{/n/
this.x = 1;/n/
}/n/
/n/
Foo.prototype.AddX = function(y) // Define Method/n/
{/n/
this.x += y;/n/
}/n/
/n/
obj = new Foo;/n/
/n/
obj.AddX(5); // Call Method/n/
", false, "RegisterConstructor(Foo);");
obj.Dump("obj");
delete obj;
function Foo()
{
this.x = 1;
}
Foo.prototype.AddX = function(y) // Define Method
{
this.x += y;
}
obj = new Foo;
obj.AddX(5); // Call Method
obj | |
x | 6 |
Foo.prototype | |
constructor | Foo |
AddX | |
Object.prototype | |
(constructor) | Object |
is achieved by simply having different object classes implement a collection of methods
that use the same names. Then, a caller, need just use the correctly named function property to invoke
the appropriate function for each object type.
CodeSample("/
function A()/n/
{/n/
this.x = 1;/n/
}/n/
/n/
A.prototype.DoIt = function() // Define Method/n/
{/n/
this.x += 1;/n/
}/n/
/n/
function B()/n/
{/n/
this.x = 1;/n/
}/n/
/n/
B.prototype.DoIt = function() // Define Method/n/
{/n/
this.x += 2;/n/
}/n/
/n/
a = new A;/n/
b = new B;/n/
/n/
a.DoIt();/n/
b.DoIt();/n/
document.write(a.x + ', ' + b.x);/n/
", true, "RegisterConstructor(A);RegisterConstructor(B);");
a.Dump("a");
b.Dump("b");
delete a;
delete b;
function A()
{
this.x = 1;
}
A.prototype.DoIt = function() // Define Method
{
this.x += 1;
}
function B()
{
this.x = 1;
}
B.prototype.DoIt = function() // Define Method
{
this.x += 2;
}
a = new A;
b = new B;
a.DoIt();
b.DoIt();
document.write(a.x + ', ' + b.x);
2, 3
a | |
x | 2 |
A.prototype | |
constructor | A |
DoIt | |
Object.prototype | |
(constructor) | Object |
b | |
x | 3 |
B.prototype | |
constructor | B |
DoIt | |
Object.prototype | |
(constructor) | Object |
Defining a Sub-Class
The standard paradigm, is to use the prototype chain to implement theinheritance of methods from a super class. Any methods defined on the
sub-class
will supersede those defined on the super-class.
CodeSample("/
function A() // Define super class/n/
{/n/
this.x = 1;/n/
}/n/
/n/
A.prototype.DoIt = function() // Define Method/n/
{/n/
this.x += 1;/n/
}/n/
/n/
B.prototype = new A; // Define sub-class/n/
B.prototype.constructor = B;/n/
function B()/n/
{/n/
A.call(this); // Call super-class constructor (if desired)/n/
this.y = 2;/n/
}/n/
/n/
B.prototype.DoIt = function() // Define Method/n/
{/n/
A.prototype.DoIt.call(this); // Call super-class method (if desired)/n/
this.y += 1;/n/
}/n/
/n/
b = new B;/n/
/n/
document.write((b instanceof A) + ', ' + (b instanceof B) + '<BR/>');/n/
b.DoIt();/n/
document.write(b.x + ', ' + b.y);/n/
", true, "RegisterConstructor(A);RegisterConstructor(B);");
b.Dump("b");
delete b;
function A() // Define super class
{
this.x = 1;
}
A.prototype.DoIt = function() // Define Method
{
this.x += 1;
}
B.prototype = new A; // Define sub-class
B.prototype.constructor = B;
function B()
{
A.call(this); // Call super-class constructor (if desired)
this.y = 2;
}
B.prototype.DoIt = function() // Define Method
{
A.prototype.DoIt.call(this); // Call super-class method (if desired)
this.y += 1;
}
b = new B;
document.write((b instanceof A) + ', ' + (b instanceof B) + '<BR/>');
b.DoIt();
document.write(b.x + ', ' + b.y);
true, true
2, 3
b | |
x | 2 |
y | 3 |
B.prototype | |
constructor | B |
(x) | 1 |
DoIt | |
A.prototype | |
(constructor) | A |
(DoIt) | |
Object.prototype | |
(constructor) | Object |
we explicitly call the constructor of the super-class in order
to insert it into our prototype chain. So it is important to ensure
that no undesirable side-effects will occur when this call is made.
Conversely, if the super-class constructor should be called for each
instance of every sub-class, code must be explicitly added
to the sub-class's constructor to make this call (as is done in the
above example).
An Alternate Sub-Classing Paradigm
As an alternate to using the prototype chain, I've developed amethod which avoids calling the constructor of a super class when each
sub-class
is defined. Three methods are added to the Function object:
document.write("<LISTING>Function.prototype.DeriveFrom = "+StHTML(Function.prototype.DeriveFrom)+"</LISTING>");
document.write("<LISTING>Function.prototype.StName = "+StHTML(Function.prototype.StName)+"</LISTING>");
document.write("<LISTING>Function.prototype.Override = "+StHTML(Function.prototype.Override)+"</LISTING>");
Function.prototype.DeriveFrom = function (fnSuper) {
var prop;
if (this == fnSuper) {
alert("Error - cannot derive from self");
return;
}
for (prop in fnSuper.prototype) {
if (typeof fnSuper.prototype[prop] == "function" &&
!this.prototype[prop]) {
this.prototype[prop] = fnSuper.prototype[prop];
}
}
this.prototype[fnSuper.StName()] = fnSuper;
}Function.prototype.StName = function () {
var st;
st = this.toString();
st = st.substring(st.indexOf(" ") + 1, st.indexOf("("));
if (st.charAt(0) == "(") {
st = "function ...";
}
return st;
}Function.prototype.Override = function (fnSuper, stMethod) {
this.prototype[fnSuper.StName() + "_" + stMethod] = fnSuper.prototype[stMethod];
}
Repeating the sub-classing example using this new paradigm:
CodeSample("/
function A() // Define super class/n/
{/n/
this.x = 1;/n/
}/n/
/n/
A.prototype.DoIt = function() // Define Method/n/
{/n/
this.x += 1;/n/
}/n/
/n/
B.DeriveFrom(A); // Define sub-class/n/
function B()/n/
{/n/
this.A(); // Call super-class constructor (if desired)/n/
this.y = 2;/n/
}/n/
/n/
B.Override(A, 'DoIt');/n/
B.prototype.DoIt = function() // Define Method/n/
{/n/
this.A_DoIt(); // Call super-class method (if desired)/n/
this.y += 1;/n/
}/n/
/n/
b = new B;/n/
/n/
document.write((b instanceof A) + ', ' + (b instanceof B) + '<BR/>');/n/
b.DoIt();/n/
document.write(b.x + ', ' + b.y);/n/
", true, "RegisterConstructor(A);RegisterConstructor(B);");
b.Dump("b");
delete b;
function A() // Define super class
{
this.x = 1;
}
A.prototype.DoIt = function() // Define Method
{
this.x += 1;
}
B.DeriveFrom(A); // Define sub-class
function B()
{
this.A(); // Call super-class constructor (if desired)
this.y = 2;
}
B.Override(A, 'DoIt');
B.prototype.DoIt = function() // Define Method
{
this.A_DoIt(); // Call super-class method (if desired)
this.y += 1;
}
b = new B;
document.write((b instanceof A) + ', ' + (b instanceof B) + '<BR/>');
b.DoIt();
document.write(b.x + ', ' + b.y);
false, true
2, 3
b | |
x | 2 |
y | 3 |
B.prototype | |
constructor | B |
DoIt | |
A | A |
A_DoIt | |
Object.prototype | |
(constructor) | Object |
operator to test
for membership of a super-class. But, we have the added benefit that we
can derive from more than one super class (multiple inheritance).
Private Members
Amazingly, JavaScript also can support private members in an object. When theconstructor is called, variables declared in the function scope of the
constructor will actually persist beyond the lifetime of the construction
function itself. To access these variables, you need only create local functions
within the scope of the constructor. They may reference local
variables in the constructor.
CodeSample("/
function A()/n/
{/n/
var x = 7;/n/
/n/
this.GetX = function() { return x;}/n/
this.SetX = function(xT) { x = xT; }/n/
}/n/
/n/
obj = new A;/n/
obj2 = new A;/n/
document.write(obj.GetX() + ' ' + obj2.GetX());/n/
obj.SetX(14);/n/
document.write(' ' + obj.GetX() + ' ' + obj2.GetX());/n/
", true, "RegisterConstructor(A);");
obj.Dump("obj");
obj2.Dump("obj2");
delete obj;
delete obj2;
function A()
{
var x = 7;
this.GetX = function() { return x;}
this.SetX = function(xT) { x = xT; }
}
obj = new A;
obj2 = new A;
document.write(obj.GetX() + ' ' + obj2.GetX());
obj.SetX(14);
document.write(' ' + obj.GetX() + ' ' + obj2.GetX());
7 7 14 7
obj | |
GetX | |
SetX | |
A.prototype | |
constructor | A |
Object.prototype | |
(constructor) | Object |
obj2 | |
GetX | |
SetX | |
A.prototype | |
constructor | A |
Object.prototype | |
(constructor) | Object |
it's own copy of each local function. The local copy of the function can
maintain a copy of the local scope (a
closure
) of the constructor.
This would be rather inefficient for object classes that construct many
instances. Experiments with a single (shared) reference to a function
reveal that they can only reference variables from a single instance of the
class. Since the benefits of using private members is rather limited in
the context of JavaScript (which is already lacking any form of type safety), I
would not recommend making extensive use of the private member
paradigm.
Update (June 2009):
I've developed a simple library for building JavaScript
Namespaces (public domain source code)
- for a description see my blog
.
Add New Comment
You are commenting as a Guest. You may select one to log into:
Logged in as
Logout from DISQUS
Logged in as
using Facebook Connect (Logout)
66
Comments
Sort by Popular nowBest Rating
Newest first
Oldest first
Community Page
Subscribe by email
Vamshee
1 year ago
Good piece. I really appreciate it. I have been looking for something like this for a long time...Thank you.
-V
Like
Report
Reply
More ▼
Optional:
Login
or
Connect
mckoss
1 year ago
My
pleasure. A lot's happened in the JavaScript world, even since the
re-write of this article in 2006. My next version should probably show
some of the other commonly used paradigms for defining classes (e.g.,
those used in prototype.js or jQuery.js).
Like
Report
Reply
More ▼
Optional:
Login
or
Connect
phatlikebudda
12 months ago
First
I want to say thanks for the article, it was quite good. It seems so
much of the internet I've seen on javascript is not for programmers.
I'm
quite familiar with the class paradigm in prototype but from what I've
seen there's not much about classes in the sense of OOD for jQuery.
Care to elaborate or point me in a good piece about the jQuery class
paradigm?
Like
Report
Reply
More ▼
Optional:
Login
or
Connect
Bill
11 months ago
Agreed.
I'd also love to see something about how the methods discussed above
can be used in concert with jQuery. I've found nothing worth reading
about OOD alongside jQuery.
Like
Report
Reply
More ▼
Optional:
Login
or
Connect
hhh
6 months ago
ccc
Like
Report
Reply
More ▼
Optional:
Login
or
Connect
Welkin
1 year ago
Thanks
a lot. I've a question though, what's the significance of
"B.prototype.constructor = B;"? (I tried removing this line from the
sample code but didn't see any difference in the results.)
Like
Report
Reply
More ▼
Optional:
Login
or
Connect
mckoss
1 year ago
Without
"B.prototype.constructor = B", any object created from "new B()" will
have the wrong "constructor" value. This could come in to play if code
is explicitly testing what type of object it is. For example, "b
instanceof B" would return false, even though the object was created
from "b = new B();".
Like
Report
Reply
More ▼
Optional:
Login
or
Connect
Joe
11 months ago
This
doesn't seem to be true. If "B.prototype.constructor = B" is commented
out in your code, "b instanceof B" still returns true.
Like
Report
Reply
More ▼
Optional:
Login
or
Connect
mckoss
10 months ago
I think I mis-spoke on the example. If you do this:
x = new B;
document.write(x.constructor == B)
it
will return false instead of true. It's pretty minor, but if there is
some code that is doing some inspection, or want's to clone the object
by calling it's constructor, it will have a reference the superclasses
constructore instead of its own.
Like
Report
Reply
More ▼
Optional:
Login
or
Connect
yuan
9 months ago
thanks, this piece help a lot
Like
Report
Reply
More ▼
Optional:
Login
or
Connect
Aks
2 months ago
Thanks , I too was confused with line B.prototype.constructor = B ;
Like
Report
Reply
More ▼
Optional:
Login
or
Connect
phani
1 month ago
i was also thinking why do we need B.prototype.constructor=B;
this was very helpful...
thanx mckoss
Like
Report
Reply
More ▼
Optional:
Login
or
Connect
oops in java script
1 year ago
a very good article
Like
Report
Reply
More ▼
Optional:
Login
or
Connect
Shaked
1 year ago
As
a Java and Actionscript developer i never really understood OO in
javascript , but this article is very helpful and nicely written .
Thanks a lot !
Like
Report
Reply
More ▼
Optional:
Login
or
Connect
Nitin Jain
1 year ago
good article
thanks
Like
Report
Reply
More ▼
Optional:
Login
or
Connect
Henry
1 year ago
What a lovely tutorial! Thanks so much for taking the time to put this amazing piece of work online.
Nice site by the way...
Like
Report
Reply
More ▼
Optional:
Login
or
Connect
ospx
11 months ago
good stuff, particularly your first kind of creating classes because of the proper usability of the instanceof operator.
Edit: deleted, There was a stupid mistakes on my proposal on entering protected behavior ... sorry
Like
Report
Reply
More ▼
Optional:
Login
or
Connect
Prosunjit
11 months ago
This is really a nice tutorial. I liked it. I think it is very conducive for the neophyte.
Like
Report
Reply
More ▼
Optional:
Login
or
Connect
ChanHan Hy
11 months ago
For beginner of Javascript OOP, it is very good explaination.
Good article!
Like
Report
Reply
More ▼
Optional:
Login
or
Connect
antoniojl
11 months ago
Great
tutorial!!! It sure helped me figure out EXACTLY how JS handles
classing! Very, very, very, very simple and powerful, I say!!!
Like
Report
Reply
More ▼
Optional:
Login
or
Connect
robertmarkbram
10 months ago
Excellent article - thank you for this Mike. It is very helpful.
Two questions.
1) In the section starting "Polymorphism is achieved by simply ..." you have this:
a = new A;
b = new B;
Shouldn't it be this:
a = new A();
b = new B();
2) Is there any difference between these two techniques?
function A() {
this.x = 1;
}
A.prototype.DoIt = function() {
this.x += 1;
}
and
function A() {
this.x = 1;
this.DoIt = DoIt;
}
function DoIt() {
this.x += 1;
}
Like
Report
Reply
More ▼
Optional:
Login
or
Connect
mckoss
10 months ago
1.
"new A" is identical to "new A()". Both will call the constructor with
no arguments [note that all the code on this page is LIVE - you can
view source and see that these examples are executing, and then output
the results inline].
2. Yes, there is a difference between
assigning a function in the constructor or using a prototype. The
former is more efficient to create objects - you don't allocate
additional storage for the function references inside of each instance
- they are all just created once in the prototype, and then referred to
as needed. Functionally, both will work nearly the same; though there
are differences in how functions would be "inherited" if you want to
subclass this constructor.
Like
Report
Reply
More ▼
Optional:
Login
or
Connect
Joaquín L. Robles
10 months ago
excellent!!!
this is what I was looking for...!
thanks!
Like
Report
Reply
More ▼
Optional:
Login
or
Connect
t03
10 months ago
Greatest article I have ever read for JavaScript.
Like
Report
Reply
More ▼
Optional:
Login
or
Connect
mckoss
10 months ago
**blush** - Thanks!
Like
Report
Reply
More ▼
Optional:
Login
or
Connect
janaka
10 months ago
It's Cool - http://janaka077.blogspot.com
Like
Report
Reply
More ▼
Optional:
Login
or
Connect
kasun
9 months ago
This is good. We expect next lesson from you
Like
Report
Reply
More ▼
Optional:
Login
or
Connect
kasun
9 months ago
Advandec things - http://kamatha.blogspot.com/
Like
Report
Reply
More ▼
Optional:
Login
or
Connect
sharie
9 months ago
Can
I save this site??..I haven't reading the informations yet but I think
this is an interesting aand very helpful site for me since I am a
programmer student..
aAAhmm... May I know other helpful site that
contains information like this?....Anyways I want to ask about the
attributes of an object?? can you give me an example????
This site is good!!!
Like
Report
Reply
More ▼
Optional:
Login
or
Connect
slightlymore
9 months ago
Excellent,
thanks a lot! Had to learn about OOJS at university, but through lack
of use, had forgotten most of it as there are a lot of subtleties to
think about (which you don't in C and PHP which I use on a daily
basis). This was a brilliant article, helped me remember a lot, and
which I have delicioused to help again in the future when.
Like
Report
Reply
More ▼
Optional:
Login
or
Connect
don
9 months ago
porque no haces una mejor documentación, digamos, que sea más actualizada,
salu2 y que la chela sea
Like
Report
Reply
More ▼
Optional:
Login
or
Connect
Morgan Cheng
9 months ago
Awesome description about Javascript object modeling.
Like
Report
Reply
More ▼
Optional:
Login
or
Connect
Anthony
8 months ago
In Defining a Subclass, why
B.prototype = new A;
instead of
X=new A; // Once
B.protoype = X
Ie. is it possible to share Xs?
And what does a constructor really do anyway? Is it just assigning function values to slots or is it messing with a prototype.
Like
Report
Reply
More ▼
Optional:
Login
or
Connect
Will
8 months ago
Wish
I had found your site a week ago. Could have really saved some time.
This is the clearest explanation I've found thus far of doing OO in
javascript.
Like
Report
Reply
More ▼
Optional:
Login
or
Connect
Ben nadel
8 months ago
This
is a really great explanation of the prototype chain and how it can be
used in OOP stlye programming. I have read other articles out there on
the subject that make it seem so much more complex.
Like
Report
Reply
More ▼
Optional:
Login
or
Connect
codemeit
8 months ago
Good combination of prototype and OOP. Thanks for the time
Like
Report
Reply
More ▼
Optional:
Login
or
Connect
Roy
7 months ago
Many thanks this is now bookmarked :)
Like
Report
Reply
More ▼
Optional:
Login
or
Connect
jonze
7 months ago
many thanks to your kind of people that make this n00b->semi-n00b transition much much easier :D
Like
Report
Reply
More ▼
Optional:
Login
or
Connect
sj
7 months ago
Great article.
Is
there a function in javascript that can be used to inspect object. for
example in ruby, we can do object.inspect to see internal details of
object
Most of the time I can use JSON, but sometimes it fails.
Thanks
Like
Report
Reply
More ▼
Optional:
Login
or
Connect
Vanya
6 months ago
Use Firebug in Firefox.
Like
Report
Reply
More ▼
Optional:
Login
or
Connect
mckoss
6 months ago
I'd agree. Do a 'console.log(obj)' and you'll be able to manually inspect the object in Firebug; it's quite nice.
Like
Report
Reply
More ▼
Optional:
Login
or
Connect
Jonathan Hawkes, TECHHEAD
6 months ago
To
learn more about the 'new' operator, constructors, and prototype-based
programming, see my article on building the Proto framework (http://devblog.techhead.biz/2009/04/prototype-b...
).
Like
Report
Reply
More ▼
Optional:
Login
or
Connect
Freelance web designer
5 months ago
i read your article on the link you provided, it was usefull, thank you Jonathan.
Like
Report
Reply
More ▼
Optional:
Login
or
Connect
Pete Ford
5 months ago
One
use of the private member paradigm that I find useful is when defining
callbacks which use the object. There I assign "this" to "me" and I can
use "me" in the callbacks to refer to the instance. The following works:
function A(element)
{
this.element = element;
this.message = 'Hello';
var me = this;
this.element.onclick = function(ev)
{
alert(me.message);
}
}
I
was always worried that the "me" was being created in the global scope,
and there might be conflicts when more than one class declared "me" in
this way, but your page has given me comfort about that...
Like
Report
Reply
More ▼
Optional:
Login
or
Connect
batigol
5 months ago
This tutorial is way too brilliant. Many thanks for the effort...
Like
Report
Reply
More ▼
Optional:
Login
or
Connect
mckoss
5 months ago
Thanks!
Like
Report
Reply
More ▼
Optional:
Login
or
Connect
Masih
5 months ago
Thank a lot for your perfect article.
Is there any way to copy local (private) variables to new class in inheritance?
Like
Report
Reply
More ▼
Optional:
Login
or
Connect
Robert Stevens
4 months ago
As a long time practitioner (and promoter) of OOP, using Java and Javascript,
I would like to complement you on your excellent Javascript OOP presentation.
Now three years retired, I enjoy hearing about what's happening in the programming
world -- and to read your page. VERY well done, indeed!
And may I just add, as a retiree who pays probably too much attention to the
current political scene: it's most unfortunate that something like an OO world
view is not available to politicians. It is truly bizarre that we live in a world
in which such estimable things like OOP AND 18th century political practices are
BOTH present. It's a funny old world, isn't it.
Like
Report
Reply
More ▼
Optional:
Login
or
Connect
maxpert
3 months ago
Nice :D
Like
Report
Reply
More ▼
Optional:
Login
or
Connect
hudz
3 months ago
Thanks for the tutorial :)
I have a question, I don't know whether it suit here, but here goes.
var pencilBox = pencilBox || {};
pencilBox = {
sideA: {},
sideB: {},
}
pencilBox.sideA = {
pencil: function(){
this.getSharp = sharpness;
}
}
pencilBox.sideB = {
sharpener: function(){
this.sharpen = sharpen;
}
}
Why this piece of code got error in IE but not in other browsers? and how should I do appropriately in JavaScript or OO manner.
p/s: omit the getSharp() and sharpen method, it’s just for beautify. :p
Thanks.
Like
Report
Reply
More ▼
Optional:
Login
or
Connect
mckoss
3 months ago
The
reason for the IE error is simple - they don't support the "trailing
comma" in object intializers. I wrote a blog post about this here:
http://blog.pageforest.com/2008/07/back-from-pa...
If
you're trying to create a "class" for pencilBox, you should define the
methods in the pencilBox.prototype (see above). That way, all instances
will
have the methods available to them.
Like
Report
Reply
More ▼
Optional:
Login
or
Connect
Juan
3 months ago
This
tutorial is very good. Many thanks for the effort but… I don't
understand the example of Polymorphism. You say: "Polymorphism is
achieved by simply having different object classes implement a
collection of methods that use the same names. Then, a caller, need
just use the correctly named function property to invoke the
appropriate function for each object type" … but the polymorphism ( in
Java, Delphi, and others OOP languages ) has methods with the same name
between a class and a superclass. In the example, the method doIt()
exists in a different classes ( class A and class B ) and they casually
have the same name ( doIt ), I don't see the polymorphism. The
polymorphism in Java ( by example ) is a little more complex ( http://en.wikipedia.org/wiki/Polymorphism_in_ob...
).
Thanks
Like
Report
Reply
More ▼
Optional:
Login
or
Connect
mckoss
3 months ago
In
a strongly typed language, the only way to achieve polymorphism is to
derive different implementations from the same base class. This is to
avoid the sort of accidental name-collision that you describe. Also
note that in modern languages, a polymorphic object need not derive
from an actual base class, but can simply declare that it implements a
particular "abstract interface".
But the underlying concept of
polymorphism more basically, getting two different "types" of objects
to behave the same in some respect. In dynamic languages, like
Javascript (and Python), this is acheived via "Duck Typing" (if it
walks like a duck, quacks like a duck, .... it's a duck). The
"contract" is simply a collection of methods that each of the objects
supports that are sufficient for some piece of code to interact with
them. Note that there need not be a formal base class or abstract
interface defined for this to occur. Simply by implmenting methods, A,
B, and, C, my object can conform to the contract and be used.
While
this is a looser system, it is also more flexible. For example,
contracts can consists of subsets or even overlapping collections of
methods from other contracts (one contract may us methods, A and B,
while another uses B and C).
Note that you can achieve
EVERYTHING you can in this dynamic form or polymorphism as you can in
the strongly typed languages (with the exception of type safety imposed
by the language). So I don't have any qualms about using the term
"polymorphism" in the JavaScript case.
(I also note the first line of the Wikipedia article you quote says exactly what I have:
"Type
polymorphism in object-oriented programming is the ability of one type,
A, to appear as and be used like another type, B. In strongly typed
languages, this usually means that type A somehow derives from type B,
or type A implements an interface that represents type B. In weakly
typed languages types are implicitly polymorphic." -- mike)
Like
Report
Reply
More ▼
Optional:
Login
or
Connect
linjava
2 months ago
Wow,
good question and great answer. I had no idea that Polymorphism had
slightly different definitions with the same underlying them for
dynamic and static languages. Both your article and answers to comments
are very useful Mr. Koss. Thank you for donating so much of your
valuable time to the rest of us!
Like
Report
Reply
More ▼
Optional:
Login
or
Connect
aacv
3 months ago
// Why this is not working?
//
Object.prototype.objSayHello = function(){alert('Hello,from OBJECT
prototype')}; // this one works as I expected, when objSayHello()
Object.prototype ={objSayHello: function(){alert('Hello,from OBJECT prototype')}}; // NOT working !
objSayHello();
// Please email me if you know, thank you! cr7cr8@126.com
Like
Report
Reply
More ▼
Optional:
Login
or
Connect
rick
2 months ago
Your the man! , Best article so far! , you should be a teacher , cant wait to get my coding organized
Like
Report
Reply
More ▼
Optional:
Login
or
Connect
leisulin
2 months ago
Referring
to your example near the beginning where you explain prototypes, I was
not understanding how the interpreter digs up the property values from
the prototype objects when the time comes. But now I think I see what's
really going on:
inB: it's actually attached to x as a property directly (x.inB)
inBProto:
it's not found on x directly, but the interpreter knows to look on
B.prototype to find it; it needs to know the identity of B, which is
its own constructor, and then it looks on that object's prototype
object and finds it like this:
x.constructor.prototype.inBProto
inA: again not a member of x, but it's also a member of B.prototype, and will be found here:
x.constructor.prototype.inA
inAProto: this one's in A's prototype, so we should have to look here:
x.constructor.prototype.constructor.prototype.inAProto
inObj: found on
x.constructor.prototype.constructor.prototype.constructor.prototype.inObj
I
typed all of those expressions in in place of the shorter versions, and
they all still displayed the same result: 1, 2, 3, 4, 5. So somewhere
internally, when the interpreter is looking up a property name, it
probably does something like this: try finding it on the object, no
dice?, try it on theObject.constructor.prototype, no dice?, keep
inserting another constructor.prototype in the middle there until that
newly added prototype object itself is undefined, meaning of course
that the property can't possibly be attached to it, so the ultimate
result is undefined. Am I finally getting this?
What I DON'T get is the code on page 33 of Javascript: The Good Parts, which is heavily related to this discussion:
Function.prototype.method = function(name,func) {
this.prototype[name] = func;
return this;
}
This
is designed to let you add methods without the "ugliness" of the
prototype keyword in there. So, Function now has a new method method
added to its prototype. But next, Mr. Crockford immediately shows how
to define an integer method of Number:
Number.method('integer', function() {
return Math[this < 0 ? 'ceiling' : 'floor'](this);
});
which he puts into use immediately with:
document.writeln((-10/3).integer());
which prints "-3".
I'm
having some major mental block here. We seem to be executing a method
of Number called "method", and the implication is that Number got this
method from the Function.prototype's method method. Does Number
"inherit" from Function? It surely inherits from Object, but from
Function? Would someone please help me out here?
Like
Report
Reply
More ▼
Optional:
Login
or
Connect
manjeet
2 months ago
Great stuff - simple and precise
Like
Report
Reply
More ▼
Optional:
Login
or
Connect
dipak
1 month ago
simply awesome.. thanks for such a nice tutorial.
Like
Report
Reply
More ▼
Optional:
Login
or
Connect
vikram12
1 month ago
Its interesting................
How to inherit a class present in the head of script into div class present in the body.....
Like
Report
Reply
More ▼
Optional:
Login
or
Connect
vikram12
1 month ago
Its interesting................
How to inherit a class present in the head of script into div class present in the body.....
Like
Report
Reply
More ▼
Optional:
Login
or
Connect
anonymous41
3 weeks ago
can any one send me a program in java that is associated with OOP...I need atleast 1 example that works
Like
Report
Reply
More ▼
Optional:
Login
or
Connect
kahenahi
3 weeks ago
kahe
Like
Report
Reply
More ▼
Optional:
Login
or
Connect
shake178
3 weeks ago
thanks for the code, however the "prototype" you were adding to your code is confussing, is it okay to not use them?
Like
Report
Reply
More ▼
Optional:
Login
or
Connect
Ian Lesser
2 weeks ago
I
still tend to write a lot of procedural code in JavaScript, and I
notice that trend is changing. I like your straightforward way of
explaining how JS can actually be used very flexibly for OOP. It
definitely makes for prettier code.
Like
Report
Reply
More ▼
Optional:
Login
or
Connect
Bikash
1 week ago
In
your defining a subclass example, the diagram shows x twice first time
directly under the object and second time under the prototype object.
The values are also different (2 & 1). I think x should appear only
once under the prototype object. Please correct me if I am wrong.
Like
Report
Reply
More ▼
Optional:
Login
or
Connect
#disqus_thread { margin-bottom: 10px; } .dsq-brlink { font-size: 10px; } .logo-disqus { font-family: Arial, sans-serif; text-transform: uppercase; font-size: 9px; font-weight: bold; } #dsq-content .dsq-alert-message { background-color:#FDF1D0; border:1px solid #FAD163; line-height: 1.25; padding: 5px 8px; color: #817134; margin: 10px 0; } #dsq-content iframe, #dsq-popup-alert iframe { border: 0; overflow-y: auto; overflow-x: hidden; *overflow-x: visible; width: 100%; background-color: transparent; height: 355px; <!--[if IE 7]> width: 0px; <![endif]--> } #dsq-content iframe.dsq-post-reply, #dsq-popup-alert iframe.dsq-post-reply { height: 300px; } #dsq-content iframe.dsq-post-reply-authenticated, #dsq-popup-alert iframe.dsq-post-reply-authenticated { height: 170px; } #dsq-content #dsq-comments .dsq-header-avatar .dsq-drop-profile { color: #333; font-size: 11px; font-family: Arial, Helvetica, sans-serif; float: left; left: 0px; position: relative; background: #f0f0f0; z-index: 2; border-left: 1px solid #888; border-right: 1px solid #888; border-bottom: 1px solid #888; -moz-border-radius: 0px 5px 5px 5px; -webkit-border-top-right-radius: 5px; -webkit-border-bottom-right-radius: 5px; -webkit-border-bottom-left-radius: 5px; display: none; min-width: 64px; /* IE6 */ _position: absolute; _top: 32px; _z-index: 9000; } /** * Popup */ .dsq-overlay { display: block; position:absolute; top:0; left:0; width:100%; height:100%; z-index:5000; background-color:#000; -moz-opacity: 0.8; opacity:.80; filter: alpha(opacity=80); } .dsq-overlay[id] { position:fixed; } .dsq-popup h4, .dsq-popup ul, .dsq-popup li, .dsq-popup ol, .dsq-popup div, .dsq-popup table, .dsq-popup td, .dsq-popup th, .dsq-popup p, .dsq-popup a, .dsq-popup cite, .dsq-popup img { border: 0; padding: 0; margin: 0; float: none; text-indent: 0; background: none; } .dsq-popup table { border-collapse: separate; border-spacing: 0; } .dsq-popup { font-size: 13px; color: #333; display: none; position: absolute; z-index: 9999; padding: 0; border: 0; text-align: left; font-family: Arial, Helvetica, sans-serif; } .dsq-popup[id] { position: fixed; } .dsq-popup img { max-width: none; } .dsq-popup ul, .dsq-popup li, .dsq-popup ol { list-style-type: none; list-style-image: none; background: none; display: block; } .dsq-popup li:before { content: ""; } .dsq-popup p, .dsq-popup ul { color: #333; line-height: 1.22em; } .dsq-popup a { color: #1C5392; } .dsq-popup a:hover { color: #869AAD; } .dsq-popup .dsq-popup-top { position: relative; text-align: right; width: 520px; height: 20px; background: transparent url(http://media.disqus.com/images/embed/popup-top.png) no-repeat; } .dsq-popup .dsq-popup-top img { margin: 12px 13px 0 0; *margin: 12px 13px 0 0; } .dsq-popup .dsq-popup-bottom { text-align: right; width: 520px; height: 20px; background: transparent url(http://media.disqus.com/images/embed/popup-bottom.png) no-repeat; } .dsq-popup .powered-by{ font-size: 90%; text-align: right; margin-top: 10px; padding-top: 10px; border-top: 1px solid #ddd; } .dsq-popup .dsq-popup-body div.powered-by a { color: #888; text-decoration:none; } .dsq-popup .dsq-popup-body { width: 520px; background: transparent url(http://media.disqus.com/images/embed/popup-body.png) repeat-y; } .dsq-popup .dsq-popup-body .dsq-popup-header a.dsq-close-link { color:#7aa5d5; position: absolute; top:-8px; right: 5px; text-decoration:none; } .dsq-popup .dsq-popup-body .dsq-popup-header a.dsq-close-link img { width: 23px; height: 24px; border: 0; } .dsq-popup .dsq-subscribe-submit { margin: 0 auto; padding: 0 10px; color: #222; } .dsq-popup .dsq-subscribe-submit input { font-size: 110%; width: 200px; } .dsq-popup p.dsq-popup-notice { padding: 5px; margin: 20px 0 0 0; background-color: #fdf1d0; border: 1px solid #fad163; } /** * New popup */ .dsq-popup .dsq-popup-container { position: relative; } .dsq-popup-container .dsq-popup-b { background:url(http://media.disqus.com/images/facebox/b.png); } .dsq-popup-container .dsq-popup-tl { background:url(http://media.disqus.com/images/facebox/tl.png); } .dsq-popup-container .dsq-popup-tr { background:url(http://media.disqus.com/images/facebox/tr.png); } .dsq-popup-container .dsq-popup-bl { background:url(http://media.disqus.com/images/facebox/bl.png); } .dsq-popup-container .dsq-popup-br { background:url(http://media.disqus.com/images/facebox/br.png); } .dsq-popup-container table { border-collapse: collapse; } .dsq-popup-container td { border-bottom: 0; padding: 0; } .dsq-popup-container .dsq-popup-body { padding: 10px; background: #fff; width: 370px; } .dsq-popup-container .dsq-popup-tl, .dsq-popup-container .dsq-popup-tr, .dsq-popup-container .dsq-popup-bl, .dsq-popup-container .dsq-popup-br { height: 10px; width: 10px; overflow: hidden; padding: 0; } .dsq-popup-container .dsq-popup-title { position: static; text-align: left; background: none; height: auto; width: auto; background-color: #E5EBED; margin: -10px -10px 10px; padding: 10px; border-bottom: 1px solid #2F414B; } .dsq-popup-container .dsq-popup-title img { margin: 0; } .dsq-popup-container .dsq-popup-title h3 { font-size: 18px; font-weight: bold; margin: 0; } .dsq-popup-container h4 { font-size: 14px; font-weight: bold; margin: 0; } /** * Popup : Blacklist */ .dsq-popup .dsq-blacklist-option { padding: 5px 10px; border-bottom: 1px dotted #E5EBED; } /** * Popup : Help */ .dsq-popup ul.dsq-popup-help { margin: 0 10px; } #dsq-popup-message.dsq-popup ul.dsq-popup-help li { margin: 0 0 15px 0; padding: 0 0 10px 0; border-bottom: 1px dotted #E5EBED; } .dsq-popup ul.dsq-popup-help li.dsq-help-otheraccts { font-weight: bold; font-size: 110%; border-bottom-width: 2px; border-bottom-style: solid; } #dsq-popup-message ul.dsq-list-tick li { list-style: none inside url(http://media.disqus.com/images/tick.png) !important; display: list-item; } #dsq-popup-message ul.dsq-list-bluebullet li { list-style: none inside url(http://media.disqus.com/images/bullet_blue.png); display: list-item; } #dsq-popup-message li { margin: 10px 0; padding: 0 10px; border-bottom: 1px dotted #E5EBED; } #dsq-popup-message li li { padding-left: 10px; } /* * Popup : Login */ .dsq-popup iframe#dsq-popup-login { margin-top: 10px; height:310px; width: 100%; } .dsq-popup-login .dsq-popup-content { width: 420px; } /** * Popup : Lightbox : Authenticate */ .dsq-lightbox .dsq-popup-content { width: 550px; } .dsq-lightbox .powered-by { display: none; } .dsq-lightbox img { border: 0 !important; height: auto !important; width: auto !important; } .dsq-lightbox .dsq-lightbox-register-reasons { padding: 0 10px !important; } .dsq-lightbox .dsq-lightbox-register-reasons li { background: url(http://media.disqus.com/images/small-tick.png) no-repeat; padding-left: 12px !important; margin: 0 0 0 6px !important; display: inline !important; font-size: 11px !important; color: #555; } .dsq-lightbox .dsq-lightbox-register-reasons li img { margin-bottom: -1px !important; } .dsq-lightbox .dsq-lightbox-auth-fields { } .dsq-lightbox .dsq-lightbox-submit { height: 1%; overflow: auto; padding: 0 5px; margin-top: 20px; } .dsq-lightbox .dsq-lightbox-auth-post { float: right; padding: 4px; background-color: #EAFFCD; -moz-border-radius: 4px; -webkit-border-radius: 4px; -webkit-border-radisu: 4px; } .dsq-lightbox .dsq-lightbox-auth-skip { float: left; margin-top: 5px; padding: 2px; } .dsq-lightbox .dsq-lightbox-switch-auth { width: 400px; font-size: 11px; text-align: right; margin: 0 auto; } .dsq-lightbox .dsq-lightbox-auth-fields table { padding: 8px; background-color: #EDFFC9; border: 1px solid #A5C469; -moz-border-radius: 4px; -webkit-border-radius: 4px; -webkit-border-radius: 4px; width: 400px; margin: 10px auto; } .dsq-lightbox .dsq-lightbox-auth-fields table td { padding: 4px; } .dsq-lightbox .errorlist { color: #c03000 !important; font-size: 11px; font-weight: bold; margin: 0; padding: 0; } .dsq-lightbox .errorlist li { margin: 5px 0 !important; padding: 0 !important; } .dsq-lightbox-errors p { color: #c03000 !important; font-size: 11px; font-weight: bold; } .dsq-lightbox .dsq-lightbox-auth-fields table td input { font-size: 13px; padding: 2px; } .dsq-lightbox-recognized table { width: 400px; margin: 10px auto; } .dsq-lightbox-recognized table td { padding: 4px; } /* * Popup : Profile */ .dsq-popup-profile .dsq-popup-content { width: 500px; } .dsq-popup-profile .dsq-popup-title { height: 1%; overflow: auto; } .dsq-popup-profile .dsq-popup-title td { vertical-align: top; } .dsq-popup-profile .dsq-popup-title img.dsq-popup-profile-avatar { width: 48px; height: 48px; } .dsq-popup-profile .dsq-popup-profile-user { padding: 0 10px; } .dsq-popup-profile .dsq-popup-profile-user h3 { font-size: 20px; font-weight: bold; margin: 0; } .dsq-popup-profile .dsq-popup-profile-user-stats span { margin-right: 10px; } .dsq-popup-profile .dsq-popup-profile-user-stats big { font-weight: bold; font-size: 16px; } .dsq-popup-profile .dsq-popup-profile-state { clear: both; padding: 15px; background-color: #f0f0f0; border-bottom: 1px solid #aaa; height: auto; overflow: hidden; margin: -10px -10px 0px; border-bottom: 1px solid #B2B2B2; } .dsq-popup-profile .dsq-popup-profile-status { padding: 10px; margin: 0 -10px 0; background-color: #EEF9FD; border-bottom: 1px solid #9FCDE3; } .dsq-popup-profile .dsq-popup-profile-snapshot { padding: 15px 0; } .dsq-popup-profile .dsq-popup-profile-snapshot table { width: 100%; } .dsq-popup-profile .dsq-popup-profile-snapshot table td { width: 50%; vertical-align: top; } .dsq-popup-profile .dsq-popup-profile-snapshot table td h4 { margin-bottom: 5px; } .dsq-popup-profile .dsq-popup-profile-snapshot table td ul { margin-bottom: 15px; max-height: 200px; overflow: auto; } .dsq-popup-profile .dsq-popup-profile-snapshot table td ul img { vertical-align: text-top; margin-right: 5px; } .dsq-popup-profile .dsq-popup-profile-snapshot table td ul li { margin-bottom: 5px; } .dsq-popup-profile .dsq-popup-profile-snapshot table td ul li a { font-size: 12px; text-decoration: none; text-transform: capitalize; } .dsq-popup .dsq-popup-body div.show-more{ padding-left: 10px; font-size: 95%; color:#7aa5d5; } .dsq-popup .dsq-popup-body .dsq-popup-body-padding { padding: 0 10px; font-size: 13px; } .dsq-popup .dsq-popup-body .dsq-popup-header { background-color: #e5ebed; padding: 0 10px; position: relative; padding-bottom: 10px; border-bottom: 1px solid #445460; } .dsq-popup .dsq-popup-body .dsq-popup-header img { border: 1px solid #fff; width: 32px; height: 32px; vertical-align: middle; } .dsq-popup .dsq-popup-body .dsq-popup-body-padding cite { margin-left: 5px; /* top: 8px; position: absolute;*/ font-style: normal; vertical-align: middle; } .dsq-popup .dsq-popup .dsq-popup-body .dsq-popup-body-padding cite { position: static; margin: 0; } .dsq-popup .dsq-popup-body .dsq-popup-body-padding cite span { font-weight: bold; font-size: 150%; font-style: normal; margin-right: 10px; vertical-align: middle; } .dsq-popup .dsq-popup-body .dsq-popup-body-padding .dsq-popuplink { margin: 0 0 0 5px; font-size: 90%; } .dsq-popup .dsq-clout { float: left; width: 72px; height: 32px; line-height: 32px; background: url('http://media.disqus.com/images/embed/clout-background.png') no-repeat top left; } .dsq-popup .dsq-clout.unverified { background: url('http://media.disqus.com/images/embed/unverified-background.png') no-repeat top left; line-height: 24px; } .dsq-popup .dsq-clout a{ float: left; width: 100%; text-align: center; color: #FFF; font-size: 16px; font-weight: bold; text-decoration: none; } .dsq-popup .dsq-clout.unverified a{ font-size: 11px; font-weight: normal; } .dsq-popup .dsq-clout a:hover { color: #fff; } .dsq-popup .dsq-profile-services { padding: 10px; background-color: #f0f0f0; border-bottom: 1px solid #aaa; height: auto; overflow: hidden; } .dsq-popup .dsq-profile-services .dsq-profile-userlvl { padding-bottom: 10px; margin-bottom: 15px; border-bottom: 1px solid #ddd; } .dsq-popup .dsq-profile-services span.dsq-profile-ontheweb { float: left; font-family: Trebuchet MS, Trebuchet, Verdana, sans-serif; font-size: 95%; color: #aaa; } .dsq-popup .dsq-profile-services ul { margin-left: 15px; display: inline; } .dsq-popup .dsq-profile-services ul li{ display: inline; margin-right: 15px; } .dsq-popup .dsq-profile-services ul li.dsq-service-labeltxt{ margin: 0; } .dsq-popup .dsq-profile-services ul li.dsq-service-labeltxt{ margin: 0; } .dsq-popup .dsq-profile-services span.dsq-services-description { font-size: 85%; color: #555; position: absolute; top: 25px; left: 5px; display: none; white-space: nowrap; } .dsq-popup .dsq-profile-services img { border:2px solid #fff; } .dsq-popup a.dsq-profile-follow { color:#7aa5d5; } .dsq-popup .dsq-profile-status, .dsq-popup .dsq-profile-recentcomments { clear: both; padding: 10px; } .dsq-popup .dsq-profile-status p, .dsq-popup .dsq-profile-recentcomments p{ padding: 0; } .dsq-popup .dsq-profile-status h4, .dsq-popup .dsq-profile-recentcomments h4 { font-size: 110%; border-bottom: 2px solid #D7DBDD; margin-bottom: 10px; } .dsq-popup .dsq-profile-status h4 span, .dsq-popup .dsq-profile-recentcomments h4 span { background-color: #D7DBDD; padding: 2px 5px; color: #555; font-weight: bold; } .dsq-popup p.dsq-profile-label { font-family: Trebuchet MS, Trebuchet, Verdana, sans-serif; font-size: 95%; color: #aaa; } .dsq-popup ul.dsq-profile-commentlist { margin-top: 10px; } .dsq-popup .dsq-profile-commentlist li{ padding: 5px 0; border-bottom: 2px solid #e9ebed; } .dsq-popup .dsq-profile-commentlist li img.avatar-small { width: 24px; height: 24px; border: 1px solid #DDD; float: left; } .dsq-popup .dsq-profile-commentlist li .comment-message { margin-left: 30px !important; *float: left !important; *margin-left: 5px !important; } .dsq-popup .dsq-profile-commentlist li span.comment-meta { clear: both !important; margin-left: 30px !important; display: block !important; font-size: 90% !important; background: none !important; float: none !important; width: auto !important; } .dsq-popup .dsq-profile-commentlist span{ color: #666; font-size: 95%; } /** * Menu */ .dsq-menu{ margin: 0 !important; left: 0px; position: absolute; _position: absolute; _left:; background: #f0f0f0 !important; z-index: 2 !important; border-width: 1px !important; border-color: #888 !important; border-style: solid !important; -moz-border-radius: 0px 0px 4px 4px; -webkit-border-bottom-right-radius: 4px; -webkit-border-bottom-left-radius: 4px; display: inline; padding: 5px 10px 5px 0 !important; list-style: none !important; } .dsq-menu li{ margin: 0 !important; padding: 0 !important; clear: both; line-height: 1.3em !important; font-size: 12px !important; margin-bottom: 2px !important; margin-left: 4px !important; white-space: nowrap !important; list-style: none !important; float: none; background: none; text-align: left; } .dsq-menu li:before { content: ""; } .dsq-menu li a.dsq-admin-toggle { font-weight: bold; } .dsq-menu li.dsq-admin-email, .dsq-menu li.dsq-admin-ip { color: #555; font-style: italic; cursor: default; } .dsq-menu li.dsq-menu-sep { border-bottom: 1px dotted #aaa; font-size: 1pt !important; } .dsq-menu li a{ text-decoration: none; color: #333; } .dsq-menu li a:hover { color: #869AAD; } /** * Drop profile */ #dsq-content #dsq-comments .dsq-header-avatar:hover .dsq-drop-profile { display: inline; } #dsq-content #dsq-comments .dsq-drop-profile li{ float: none; clear: both; line-height: 1.3em; padding: 2px 4px; white-space: nowrap; } #dsq-content #dsq-comments .dsq-drop-profile li img { float: none; height: 12px; width: 12px; margin: 0px 4px 0px 0; vertical-align: middle; } #dsq-content #dsq-comments .dsq-drop-profile li a { color: #1C5392; vertical-align: middle; } #dsq-content #dsq-comments .dsq-drop-profile li a:hover { font-weight: bold; } #dsq-content #dsq-comments .dsq-drop-profile li.dsq-drop-services { height: 16px; padding: 4px 4px; } #dsq-content #dsq-comments .dsq-drop-profile li.dsq-drop-services:hover { background-color: #ddd; outline-top: 1px solid #ccc; outline-bottom: 1px solid #ccc; } #dsq-content #dsq-comments .dsq-drop-profile li.dsq-drop-services a { display: block; width: 100%; height: 16px; } #dsq-content #dsq-comments .dsq-drop-profile li.dsq-drop-sep { border-bottom: 1px dotted #aaa; } #dsq-content #dsq-comments .dsq-drop-profile li.dsq-drop-showlnk { padding: 4px 2px; border-bottom: 1px solid #ccc; text-align: center; height: 16px; -moz-border-radius: 0px 5px 0px 0px; -webkit-border-top-right-radius: 5px; } #dsq-content #dsq-comments .dsq-drop-profile li.dsq-drop-showlnk a { font-weight: bold; font-size: 95%; display: block; width: 100%; height: 16px; } #dsq-content #dsq-comments .dsq-drop-profile li.dsq-drop-badge { padding: 6px 2px; text-align: center; font-size: 95%; cursor: help; border-bottom: 1px solid #ddd; } #dsq-content #dsq-comments .dsq-drop-profile li.dsq-drop-badge span { padding: 1px 3px; } #dsq-content #dsq-comments .dsq-drop-profile li.dsq-drop-more { height:16px; background: url(http://media.disqus.com/images/drop-more.gif); background-position: 0px 0px; background-repeat: repeat-x; background-color: #fff; text-align: center; border-top: 1px solid #ddd; -moz-border-radius: 0px 0px 5px 5px; -webkit-border-bottom-right-radius: 5px; -webkit-border-bottom-left-radius: 5px; } #dsq-content #dsq-comments .dsq-drop-profile li.dsq-drop-more:hover { background-position: 0px -20px; border-top: 1px solid #ccc; } #dsq-content #dsq-comments .dsq-drop-profile li.dsq-drop-more a { font-size: 95%; height: 16px; width: 100%; display: block; } #dsq-content #dsq-comments .dsq-drop-profile li.dsq-drop-hidden { display: none; padding: 0; } /*----- Classic Theme -----*/ #disqus_thread #dsq-content iframe.dsq-post-video { height: 370px; overflow: hidden; } #dsq-content #dsq-comments .dsq-header-avatar img{ float: left; margin: 4px; width: 32px; height: 32px; } #dsq-content #dsq-comments .dsq-comment-body{ padding-top: 5px; } #dsq-content #dsq-comments .dsq-header-avatar { width: 32px; height: 34px; height: 43px; width: 40px; } #dsq-content #dsq-comments .dsq-comment:hover .dsq-header-avatar{ background: url('http://media.disqus.com/images/embed/avatar-frame-32.png') no-repeat top left; } #dsq-content #dsq-comments .dsq-comment-header { background: url('http://media.disqus.com/images/embed/header-grey.png') repeat-x; height: 30px; line-height: 30px; height: 38px; line-height: 38px; } #dsq-content { font-size: 13px; } img.dsq-record-img { border: 0; padding: 0; margin: 0; float: none; text-indent: 0; background: none; vertical-align: text-bottom; } a.dsq-brlink { font-size: 10px; color: #666; text-decoration: none; font-family: Trebuchet MS, Trebuchet, Verdana, Arial, sans-serif; } span.disqus { font-family: Trebuchet MS, Trebuchet, Verdana, Arial, sans-serif; font-size: 90%; text-transform: uppercase; color: #64747d; } span.logo-disqus { font-family: Trebuchet MS, Trebuchet, Verdana, Arial, sans-serif; font-size: 95%; text-transform: uppercase; font-weight: bold; } span.logo-disqus.color { color: #64747d; } span.logo-disq { font-family: Trebuchet MS, Trebuchet, Verdana, Arial, sans-serif; font-size: 95%; text-transform: uppercase; color: #64747d; font-weight: bold; } span.logo-us { font-family: Trebuchet MS, Trebuchet, Verdana, Arial, sans-serif; font-size: 95%; text-transform: uppercase; color: #ff9300; font-weight: bold; } span.dsq-downtri { font-size: 70%; } a.dsq-help { color: inherit; text-decoration: none !important; border-color: inherit !important; border-bottom-width: 1px !important; border-bottom-style: dotted !important; cursor: help !important; } #dsq-content #dsq-comments .dsq-editedtxt { margin-top: 15px; font-style: italic; font-size: 85%; opacity: .80; filter: alpha(opacity=80); } #dsq-content #dsq-comments .dsq-likedtxt { font-size: 85%; text-align: right; opacity: .80; filter: alpha(opacity=80); } #dsq-content small { font-size: .7em; } #disqus_thread #dsq-content iframe.dsq-post-reply, #dsq-popup-alert iframe.dsq-post-reply { height: 300px; } #disqus_thread #dsq-content iframe.dsq-post-reply-authenticated, #dsq-popup-alert iframe.dsq-post-reply-authenticated { height: 170px; } .clearfix:after { content:"."; display: block; height: 0; clear: both; visibility: hidden; } #dsq-content #dsq-comments img.icon-adjust { margin-bottom: -3px; } #dsq-content #dsq-comments img.dsq-mod-star { vertical-align: middle; _float: left; _margin-top: 5px; } #disqus_thread #dsq-content ul, #disqus_thread #dsq-content li, #disqus_thread #dsq-content ol, #disqus_thread #dsq-content cite, #disqus_thread #dsq-content img, /* dsq-content */ #dsq-content #dsq-comments ul, #dsq-content #dsq-comments li, #dsq-content #dsq-comments ol, #dsq-content #dsq-comments div, #dsq-content #dsq-comments p, #dsq-content #dsq-comments a, #dsq-content #dsq-comments cite, #dsq-content #dsq-comments img { border: 0; padding: 0; margin: 0; float: none; text-indent: 0; background: none; } #disqus_thread #dsq-content cite, #dsq-content #dsq-comments cite { font-style: normal; } #dsq-content #dsq-comments img { max-width: none; } #disqus_thread #dsq-content li, #disqus_thread #dsq-content ul, #disqus_thread #dsq-content ol, #dsq-content #dsq-extra-links li, #dsq-content #dsq-comments ul, #dsq-content #dsq-comments li, #dsq-content #dsq-comments ol { list-style-type: none; list-style-image: none; background: none; display: block; } #dsq-content #dsq-extra-links li:before, #dsq-content #dsq-comments li:before { content: ""; } #dsq-content #dsq-comments { width: 100%; list-style-type: none; padding: 0; border: 0; } #dsq-content #dsq-comments .dsq-remove-message { color: #555; list-style-type: none; margin: 10px 0; padding: 5px; border: 1px solid #c03000; background-color: #FDDFD0; } #dsq-content #dsq-comments .dsq-comment-alert, #dsq-content #dsq-alerts p { font-weight: bold; color: #555; margin: 15px 0; padding: 5px; background-color: #fdf1d0; border: 1px solid #fad163; } #dsq-content #dsq-comments .dsq-comment-header .dsq-hl-up { background-color: #92C72A; color: #fff; margin:0pt 5px; padding:0 2px; } #dsq-content #dsq-comments .dsq-comment-header .dsq-hl-down { background-color: #c03000; color: #fff; margin:0pt 5px; padding:0 2px; } #dsq-content #dsq-comments .dsq-hl-anchor { background-color: #ffff99 !important; color: #000 !important; } #dsq-content #dsq-comments .dsq-hl-anchor p { color: #000 !important; } #dsq-content #dsq-comments .dsq-hl-anchor a { color: #000 !important; } #dsq-content h3#dsq-comments-count { width: 99%; } /** * Misc Items */ #dsq-content .dsq-item-feed a { text-decoration: none; } /** * Auth Header */ #dsq-content #dsq-auth .dsq-auth-header{ margin-bottom: 10px; width: 99%; } #dsq-content #dsq-auth .dsq-authenticated { margin-bottom: 10px; display: none; height: auto; overflow: hidden; } #dsq-content #dsq-auth .dsq-authenticated-pic { float: left; } #dsq-content #dsq-auth .dsq-authenticated-pic img { height: 48px; width: 48px; } #dsq-content #dsq-auth .dsq-authenticated-info { float: left; } #dsq-content #dsq-auth .dsq-authenticated-info ul { padding: 0 0 0 5px; margin: 0; list-style-type:none; } #dsq-content #dsq-auth .dsq-authenticated-info ul li { margin-bottom: 5px; } #dsq-content #dsq-auth .dsq-authenticated-info ul li.logout { font-size: 0.8em; } #dsq-content #dsq-auth .dsq-authenticated-info ul li.logout a { text-decoration: none; } #dsq-content #dsq-auth .dsq-authenticated-info ul li.logout img { margin-bottom: -2px; } #dsq-content h3 { margin: 10px 0; } #disqus_thread #dsq-content h3 { font-weight: bold; } #dsq-content #dsq-auth.dsq-auth-bottom { margin-top: 20px; } #dsq-content .dsq-by { float: right; } #dsq-content #dsq-login { float: none; } #dsq-content #dsq-login .dsq-login-message { margin-bottom: 10px; } #dsq-content #dsq-comments .dsq-login-icon { margin-bottom: -2px; } #dsq-content .dsq-auth-header img, #dsq-content #dsq-options-toggle img { border: 0; margin: 0; padding: 0; max-width: none; float: none; } #dsq-content #dsq-options { margin-bottom: 20px; } #dsq-options .dsq-extra-meta { background: transparent url('http://media.disqus.com/images/embed/transp-line-10.png') repeat-x top center; margin-top:10px; padding-top:10px; } #dsq-extra-links { margin-top: 15px; font-size: 90%; } #dsq-extra-links img { margin-bottom: -3px; } /** * Reply bar */ #dsq-content #dsq-comments .dsq-reply-bar { margin: 15px 0; } #dsq-content #dsq-comments .dsq-reply-bar img { margin-bottom: -2px; } #dsq-content #dsq-comments a.dsq-reply-req-opt { font-size: 100%; margin-right: 5px; opacity: .80; filter: alpha(opacity=80); } #dsq-content #dsq-comments .dsq-reply-bar-items { float: right; } #dsq-content #dsq-comments .dsq-reply-bar-auth { font-size: .9em; } #dsq-content #dsq-comments .dsq-reply-bar-auth .dsq-no-anon-msg { margin: 5px 0 2px 0; } #dsq-content #dsq-comments .dsq-reply-bar-auth img.dsq-post-avatar { height: 24px; width: 24px; } #dsq-content #dsq-auth ul.dsq-media-items li, #dsq-content #dsq-comments ul.dsq-media-items li { display: inline; font-size: .90em; } /** * Pagination */ #dsq-content #dsq-pagination { margin: 20px 0; } #dsq-content #dsq-pagination a { font-weight: bold; } #dsq-content #dsq-pagination a, #dsq-content #dsq-pagination span { margin-right: 5px; } #dsq-content #dsq-pagination span.dsq-paginate-ellipsis { font-size: 110%; } #dsq-content #dsq-pagination a.dsq-paginate-arrows span { margin: 0; padding: 0; font-family: Lucida Sans Unicode, sans-serif; } #dsq-content .dsq-paginate-append-text { display: inline; } #dsq-content .dsq-paginate-append-button { display: none; } /** * Badges */ span.dsq-badge { font-family: Optima, Lucida Grande, Lucida Sans, Helvetica, Arial, sans-serif; padding: 2px 4px; -moz-border-radius: 0px 5px 0px 5px; -webkit-border-top-right-radius: 5px; -webkit-border-bottom-left-radius: 5px; vertical-align: middle; } span.dsq-badge.dsq-badge-verified { background-color: #92C72A; border: 1px solid #6ca300; color: #fff; } span.dsq-badge.dsq-badge-registered { background-color: #fffe98; border: 1px solid #eae800; color: #000; } span.dsq-badge-verified, span.dsq-badge-registered, span.dsq-badge-guest, span.dsq-badge-facebook, span.dsq-badge-twitter, span.dsq-badge-openid { font-family: Optima, Lucida Grande, Lucida Sans, Helvetica, Arial, sans-serif; padding: 2px 4px; -moz-border-radius: 0px 5px 0px 5px; -webkit-border-top-right-radius: 5px; -webkit-border-bottom-left-radius: 5px; vertical-align: middle; } span.dsq-badge-verified { background-color: #92C72A; border: 1px solid #6ca300; color: #fff; } span.dsq-badge-registered { background-color: #fffe98; border: 1px solid #eae800; color: #000; } span.dsq-badge-guest { background-color: #ddd; border: 1px solid #ccc; color: #333; } span.dsq-badge-facebook { background-color: #46639d; color: #fff; } span.dsq-badge-twitter { background-color: #31ceff; color: #fff; } span.dsq-badge-openid { background-color: #f9f9f9; border: 1px solid #aaa; color: #f7931e; } /** * OpenID */ table.dsq-openid-form { margin-left: 10px; margin-bottom: 20px; } table.dsq-openid-form img { width: 50px; height: 50px; margin-right: 10px; } table.dsq-openid-form td.dsq-openid-submit { padding-top: 5px; text-align: right; } /** * Linkbacks */ #dsq-content span.dsq-item-trackback { margin: 15px 0; } #dsq-content input.dsq-trackback-url { width: 150px; font-size: 10px; color: #666; } #disqus_thread #dsq-content ul#dsq-references li { margin-bottom: 20px; display: list-item; list-style: disc; margin-left: 15px; } #disqus_thread #dsq-content ul#dsq-references cite { margin-bottom: 0px; padding-bottom: 0px; font-weight: bold; } #disqus_thread #dsq-content ul#dsq-references p.dsq-meta { margin-top: 0px; padding-top: 0px; font-size: 95%; } /* Reactions */ #disqus_thread #dsq-content li.dsq-reaction { padding: 0; margin: 0; border: 0; list-style-type: none; margin-left: 0px; color: #000; margin-bottom: 20px; } #disqus_thread #dsq-content li.dsq-reaction:before { content: ""; } #disqus_thread #dsq-content .dsq-reaction-header { background: url('http://media.disqus.com/images/embed/header-grey.png') repeat-x; } #disqus_thread #dsq-content .dsq-reaction-header a { text-decoration: none; } #disqus_thread #dsq-content .dsq-reaction .dsq-header-avatar { position: relative; margin-top: 2px; float: left; height: 32px; width: 32px; } #disqus_thread #dsq-content .dsq-reaction .dsq-header-avatar img { float: left; width: 32px; height: 32px; } #disqus_thread #dsq-content .dsq-reaction .dsq-header-avatar img.dsq-service-icon { width: 12px; height: 12px; position: relative; margin-top: -12px; margin-left: 20px; } #disqus_thread #dsq-content .dsq-reaction-header cite { float: left; font-style: normal; font-weight: bold; margin: 0 5px; line-height: inherit; cursor: pointer; } #disqus_thread #dsq-content .dsq-reaction-header cite a { line-height: inherit; } #disqus_thread #dsq-content .dsq-reaction-header .dsq-header-meta { font-size: 90%; line-height: inherit; } #disqus_thread #dsq-content .dsq-reaction a.dsq-header-time { margin: 0 5px; color: inherit; line-height: inherit; } #disqus_thread #dsq-content .dsq-reaction-body { clear: left; padding-top: 5px; } #disqus_thread #dsq-content .dsq-reaction-footer { opacity: .35; filter: alpha(opacity=35); font-size: 90%; margin: 5px 0 0 0px; } #disqus_thread #dsq-content .dsq-reaction-footer a { color: inherit; text-decoration: none; } #disqus_thread #dsq-content .dsq-reaction-footer a:hover { text-decoration: underline; } #disqus_thread #dsq-content .dsq-reaction-retweets { border-left: solid 5px #666; margin-top: 10px; padding-left: 5px; } #disqus_thread #dsq-content .dsq-service-name { text-transform: capitalize; } #disqus_thread #dsq-content li#dsq-show-more-reactions { text-align: center; } /** * Introduced in Embed 2.0 */ #dsq-content #dsq-comments .dsq-comment-footer { height: auto; overflow: hidden; } #dsq-content #dsq-comments .dsq-comment-options { float: right; list-style: none; } #dsq-content #dsq-comments ul.dsq-list-style li { display: inline; background-image: url(http://media.disqus.com/images/middot.png); _background-image: url(http://media.disqus.com/images/middot.gif); background-repeat: no-repeat; background-position: 0 50%; padding-left: 1.6em; } #dsq-content #dsq-comments ul.dsq-list-style li.dsq-list-first { background: none; padding: 0; } /** * Reactions */ #disqus_thread #dsq-content ul#dsq-reactions li.dsq-reaction { padding: 0; margin: 0; border: 0; list-style-type: none; margin-left: 0px; color: #000; margin-bottom: 20px; } #dsq-content ul#dsq-reactions .dsq-reaction-header { background: url('http://media.disqus.com/images/embed/header-grey.png') repeat-x; height: 38px; line-height: 38px; *overflow-y: hidden; } #dsq-content ul#dsq-reactions .dsq-reaction-header a { text-decoration: none; } #dsq-content ul#dsq-reactions .dsq-header-avatar { position: relative; float: left; margin-top: 2px; height: 35px; width: 40px; } #dsq-content ul#dsq-reactions .dsq-header-avatar img { float: left; width: 32px; height: 32px; } #dsq-content ul#dsq-reactions .dsq-header-avatar img.dsq-service-icon { width: 12px; height: 12px; position: relative; margin-top: -12px; margin-left: 20px; } #dsq-content ul#dsq-reactions .dsq-reaction-header cite { float: left; font-style: normal; font-weight: bold; margin: 0 3px 0 5px; line-height: inherit; cursor: pointer; } #dsq-content ul#dsq-reactions .dsq-reaction-header cite a { line-height: inherit; } #dsq-content ul#dsq-reactions .dsq-reaction-header .dsq-header-meta { font-size: 90%; float: left; line-height: inherit; } #dsq-content ul#dsq-reactions a.dsq-header-time { margin: 0 5px; color: inherit; line-height: inherit; } #dsq-content ul#dsq-reactions .dsq-reaction-body { clear: both; padding-top: 5px; } #dsq-content ul#dsq-reactions .dsq-reaction-footer { font-size: 90%; margin: 5px 0 0 0px; } /*----- Comments (comments-1.css) -----*/ #dsq-content #dsq-comments .dsq-comment { list-style-type: none; padding: 0; margin: 0; border: 0; } #dsq-content #dsq-comments .dsq-comment { margin-bottom: 20px; } #dsq-content #dsq-comments .dsq-comment-rate { float: left; line-height: 1.22em; *margin-top: 15px; } #dsq-content #dsq-comments .dsq-comment-rate a, #dsq-content #dsq-comments .dsq-comment-rate img { border: 0; margin: 0; padding: 0; background-color: transparent; } #dsq-content #dsq-comments .dsq-arrows, #dsq-content #dsq-comments .not-votable .dsq-arrows:hover { opacity: .25; filter: alpha(opacity=25); _width: 16px; _height: 14px; }/ #dsq-content #dsq-comments .dsq-arrows.voted { opacity: .5; filter: alpha(opacity=50); } #dsq-content #dsq-comments .dsq-arrows:hover { opacity: 1; filter: alpha(opacity=100); } #dsq-content #dsq-comments .dsq-arrows img { _width: 16px; _height: 14px; } #disqus_thread #dsq-content #dsq-comments .dsq-header-avatar { position: relative; float: left; margin-top: -2px; } #dsq-content #dsq-comments .dsq-comment.special .dsq-comment-header { background: url('http://media.disqus.com/images/embed/header-blue.png') repeat-x; } #dsq-content #dsq-comments .dsq-comment-header a { text-decoration: none; } #dsq-content #dsq-comments .dsq-comment-header cite { float: left; font-style: normal; font-weight: bold; margin: 0 3px; line-height: inherit; } #dsq-content #dsq-comments .dsq-comment-header cite a { line-height: inherit; } #dsq-content #dsq-comments .dsq-comment-header .dsq-header-meta { font-size: 90%; line-height: inherit; } #dsq-content #dsq-comments a.dsq-header-time{ margin: 0 5px; color: inherit; line-height: inherit; } #dsq-content #dsq-comments span.dsq-header-points{ margin: 0 5px; color: inherit; line-height: inherit; } #dsq-content #dsq-comments .dsq-comment-footer { font-size: 90%; margin: 10px 0 0 0; } #dsq-content #dsq-comments .dsq-footer-alert { text-align: right; }
blog comments powered by Disqus
References
ECMA-262(PDF)
- ECMAScript Standard Documentation
JavaScript Closures
- Detailed (if lengthy) explanation of JavaScript closures, along with
efficiency concerns especially with the inability of the garbage collector to
clean up function calls in the presence of possible closures.
google_ad_client = "pub-5601944029322846";
google_ad_width = 728;
google_ad_height = 15;
google_ad_format = "728x15_0ads_al";
//2007-04-14: JScript.Links
google_ad_channel = "7327752269";
google_protectAndRun("ads_core.google_render_ad", google_handleError, google_render_ad);
_uacct = "UA-177353-1";
urchinTracker();
相关文章推荐
- 一篇关于UG二次开发的论文
- 【HTML+CSS+JavaScript】网页实战开发笔记之二—关于Web标准,你不能不知道的事
- 转一篇关于android开发框架的全局理解的好文
- 今天读到一篇非常好的轻量级,关于介绍网站开发流量的文章
- web前端开发中关于面向对象(一)
- 关于javascript中面向对象的功能:类、子类
- 一篇关于数学建模美赛论文撰写的心得
- Web 开发面试中常见的 10 个关于 JavaScript 的概念
- 一篇笔记带你快速掌握面向对象的Javascript(纯手打)
- 关于面向对象的javascript
- javascript面向对象开发
- 【JavaScript 基础知识】一篇关于 JavaScript 一些知识点的总结 —— 持续更新
- 关于javascript面向对象的编程和构造器的简单创建
- 【HTML+CSS+JavaScript】网页实战开发笔记之二―关于Web标准,你不能不知道的事
- 开发经验总结,关于需求以及面向对象的经验.
- web前端-关于javascript开发的重要知识点
- 面向对象JavaScript开发实战
- 不错的一篇关于javascript-prototype继承
- 关于android开发中涉及到的java知识:面向对象(八)
- 一些javascript中关于面向对象的连接