My understanding is that a function in JavaScript can have states. Some states need to be initialized just once. How do you do that so that calling the function does not re开发者_StackOverflow-initialize them?
For example, $()
in jQuery is a function, not an object, and yet it seems to have states and act like an object.
I thought about creating an object for this, but what I want is really a facade function, much like the way $()
works.
Functions are objects. They can have properties:
function F() {}
F.key = "value";
alert(F.key) // "value"
You can also use functions as constructors called with new
:
function F(val) { this.key = val; }
var instance = new F("value")
alert(instance.key) // "value"
The difference as you can see is that the first version only adds a key
memeber to the F
function object, while the second one initializes a new key
member on every instance created by new
F
.
When you call a function via new
an instance object is automatically created and can be augmented by the this
keyword. Every constructor returns this
by default.
You can also add public methods to the function's prototype
, and they will be available for all the instances. They can change their "state" (as you call it) individually using the this
keyword.
function F(val) { this.state = val; } // unique
F.prototype.change = function() { this.state = "stuff"; }
var inst = new F("value")
var inst2 = new F("value")
alert(inst.state) // "value"
alert(inst2.state) // "value"
inst.change();
alert(inst.state) // "stuff"
alert(inst2.state) // "value"
jQuery
I can even tell you what jQuery is doing behind the scenes, but I don't think you really want to know. :)
var jQuery = function( selector, context ) {
// The jQuery object is actually just the init constructor 'enhanced'
return new jQuery.fn.init( selector, context );
},
// ...
jQuery.fn = jQuery.prototype = {
init: function( selector, context ) {
// ...
},
// ...
};
// Give the init function the jQuery prototype for later instantiation
jQuery.fn.init.prototype = jQuery.fn;
So basically $(selector)
means new
jQuery.fn.init(selector)
, it's just a shortcut for easier typing (and also to prevent the "bug" mentioned in the comments where fogetting new
binds this
to the global object, instead of the current instance).
Also, the so-called plug-ins added as jQuery.fn.ext
are mapped to jQuery.fn.init.prototype
as you can see in the last line, it's another shortcut. So when you call $(selector)
everything that is added to jQuery.fn
will also be on jQuery.fn.init.prototype
and so the new instance will have those methods as $(selector).ext(...)
.
// as you use it today
jQuery.fn.plugin = function ( ... ) { ... }
$(selector).plugin( ... )
// as it would be without shortcuts
jQuery.fn.init.prototype.plugin = function ( ... ) { ... }
(new jQuery.fn.init(selector)).plugin( ... )
If you want to restrict a function from be called more than once, i suggest you implement the singleton pattern
JavaScript is fully object oriented, prototype-based language. And by fully I mean everything is an object including arrays, numbers and so-called functions:
var number = 32.1245;
alert(number.toFixed(2)); // 32.12
Basically when you define a function using function
keyword you're actually defining a object constructor. Inside object constructor you can define object's public properties using this
:
function Car(model) {
this.model = model;
this.productionYear = new Date().getFullYear();
}
var car = new Car("Audi A8");
car.productionYear = 2009;
Of course those properties can be objects constructors as well.
精彩评论