wrapping plain javascript object in jquery $({}) - javascript

I have this fragment of code from a book I am reading. And want to understand what $({}) means and what is its use exactly.
I tried searching on several search engines and even on SO. $({}) wasn't a search-friendly term.
var Events = {
bind: function(){
if ( !this.o ) this.o = $({});
this.o.bind.apply(this.o, arguments);
},
trigger: function(){
if ( !this.o ) this.o = $({});
this.o.trigger.apply(this.o, arguments);
}
};
I did find a similar question about $([]) but I don't think it is quite the same thing.

You're just wrapping a basic javascript object as a jQuery one.
From jquery documentation :
Working With Plain Objects
At present, the only operations supported
on plain JavaScript objects wrapped in jQuery are:
.data(),.prop(),.bind(), .unbind(), .trigger() and .triggerHandler().
The use of .data() (or any method requiring .data()) on a plain object
will result in a new property on the object called
jQuery{randomNumber} (eg. jQuery123456789).
// define a plain object
var foo = {foo:'bar', hello:'world'};
// wrap this with jQuery
var $foo = $(foo);
// test accessing property values
var test1 = $foo.prop('foo'); // bar
// test setting property values
$foo.prop('foo', 'foobar');
var test2 = $foo.prop('foo'); // foobar
// test using .data() as summarized above
$foo.data('keyName', 'someValue'); console.log($foo); // will now contain a
// jQuery{randomNumber}
// property
// test binding an event name and triggering
$foo.bind('eventName', function (){
console.log('eventName was called');
});
$foo.trigger('eventName'); // logs 'eventName was called'
Should
.trigger('eventName') be used, it will search for an 'eventName'
property on the object and attempt to execute it after any attached
jQuery handlers are executed. It does not check whether the property
is a function or not. To avoid this behavior,
.triggerHandler('eventName') should be used instead.
$foo.triggerHandler('eventName'); // also logs 'eventName was called'
Here's a (not really useful) example :
​var a =$({});
a.data('b', 3);
console.log(a.data('b')); // this prints 3
If you keep your object created with $({}), you may use it as callee for data, bind, and so on. This is probably the minimal non DOM keepable jquery object you can make.

this really has more to do with javascript syntax than jQuery.
{} is for objects like so:
//makes an empty object
var myObject = {};
//makes an object containing 'foo' and 'bar' as 'firstItem' and 'secondItem'
var myObject = { firstItem : foo, secondItem : bar };
[] is for arrays like so:
//makes a blank array
var myArray = [];
//makes an array containing 'foo' and 'bar' at postions 0 and 1
var myArray = [foo, bar];
() is for functions (which jQuery generally is). This is abit more complicated because it can have multiple meanings.
//running an existing function
myFunction();
//running an anonymous function
(function(){
//doSomething }
)();
//running a function with an argument
myFunction(arg);
jQuery is generally just a function called $ instead of myFunction so...
//runs jQuery as a function on 'arg'
$(arg);
The argument you pass jQuery can be almost anything. If you pass it a string like '#myDiv' jQuery will use that argument as a selector to get an element from the html. If you pass it something else like an object or an array, it can still do some things with it like: http://api.jquery.com/jQuery/ as #dystroy said.
So $({}) is the same as $(myBlankObject), for example:
var myBlankObject = {};
$(myBlankObject);
//is the same as
$({});
and
var myObjectWithStuff = { firstItem : foo, secondItem : bar };
$(myObjectWithStuff);
//is the same as
$({ firstItem : foo, secondItem : bar });
$('selector') works. $({'selector'}) or $(['selector']) does not, because you are not passing jQuery a string, but another data type.

Related

Use a variable both as function and object instance

I was wondering how does JQuery use "$" both as a function to return a new instance and an instance itself.
I guess that it's not exactly the case but I mean, we can use $(element).method and for exemple $.ajax without brackets (.ajax will still be a method).
EDIT :
I think that I misspoke. I know how objects work in JavaScript and my question was not about that.
JQuery allows us to use $ without the key word new. It has a function that returns a new instance automatically. So my question was about how it can use $ both as a function to instanciate a new object and an object itself.
Let's say we have
(function() {
var jQ = function (arg){
this.own = arg;
};
jQ.prototype = {
foo : function (){
alert("Foo");
},
bar : function (){
alert("Bar");
}
};
window.jQ = window.$ = jQ;
return jQ;
}());
In this exemple, i have to go througth the key word new if I want to use my object.
So how does JQuery do to avoid us this step ?
Function is an object in javascript: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function You can check this code:
var f = function () { alert(1); };
f.func1 = function () { alert(2); };
f.func2 = function () { alert(3); };
and you can call f(), f.func1() and so on...
It's not jQuery. In JavaScript functions are objects.
In the case of $(element).method you are passing a parameter element into the jQuery function, where with the $.ajaxcall you are calling the ajax function inside of the $ jQuery object. In both cases we are talking about the same piece of code, but we are using it two different ways.
Have a look at the raw source code for jQuery and that should help to visualize this a little: https://code.jquery.com/jquery-2.1.1.js
Note: the jQuery function that is used repeatedly is aliased at the bottom of the page.
Remember that in JavaScript, functions are objects. So, using the specific functions you called out in your question, you could create them like this:
var $ = function(selector) {
...
};
$.ajax = function(url) {
...
};
EDIT: To respond to your edited/clarified question, you don't have to use prototyping to make constructor functions in javascript. Remember, all a constructor is doing is returning an object - here's the equivalent of your prototyping code, but without having to use the new operator to instantiate the object:
(function() {
var jQ = function (arg){
return {
own: arg,
foo: function (){
alert("Foo");
},
bar: function (){
alert("Bar");
}
}
};
window.jQ = window.$ = jQ;
return jQ;
}());
I believe this style is actually preferred by Douglas Crockford because forgetting to use the new keyword won't throw an error but you'll get some very unexpected behavior.
JQuery allows us to use $ without the key word new. It has a function that returns a new instance automatically.
Nothing magical here. The jQuery function simply returns an instance of another constructor (source):
// Define a local copy of jQuery
jQuery = function( selector, context ) {
// The jQuery object is actually just the init constructor 'enhanced'
// Need init if jQuery is called (just allow error to be thrown if not included)
return new jQuery.fn.init( selector, context );
},
The only magic going on in the code (not shown in the example) is that jQuery.fn.init.prototype = jQuery.prototype. But jQuery.fn.init is a different function than jQuery.
Applied to your example:
var jQ = function (arg){
return new jQ.prototype.init(arg);
};
jQ.prototype = {
init: function(arg) {
this.own = arg;
},
// ...
};
jQ.prototype.init.prototype = jQ.prototype;

How can I access what a function was called on?

I am assuming that $('thing1') or document.getElementById('thing1') will return the node or object representing <div id="thing1"></div> But how do I access that in myFunc()?
HTML:
<div id="thing1"></div>
JS:
var foo = $('#thing1').myFunc();
var myFunc = function() {
console.log(this); // I want to log $('#thing1')
}
I am trying to figure out how various api's work, take highcharts for example, they do something like this:
$('#dailyKPIChart').highcharts({
chart: {
zoomType: 'x',
spacingRight: 20
}
});
And the chart will load in $('#dailyKPIChart')
How does that work?
There is no way to (programatically) know which variable (or which function call) was used to get the object upon which a method was called.
A debugger will tell you (set a break point, and then look at the stack) but that won't be useful if you think you need to know the name in your code.
$a_jquery_object.selector will (in older versions of jQuery) hold the selector used to construct a jQuery object, which might help for your particular example.
And the chart will load in $('#dailyKPIChart')
How does that work?
It doesn't need to know about $() or '#dailyKPIChart', it only needs the object that you get when calling it, which is available through this, which your earlier example code already uses.
There are several ways to invoke a function in javascript and perhaps you are after call (or its cousin apply):
Supposing you define your funciton as:
var myFunc = function() {
console.log(this); // I want to log $('#thing1')
}
You can call it while at the same time you specify the context. For example, you can do this:
var foo = $('#thing1');
var myFunc = function() {
console.log(this);
}
myFunc.apply(foo);
Or via call:
var foo = $('#thing1');
var myFunc = function() {
console.log(this);
}
myFunc.call(foo);
If you have arguments to pass, you can do so by specifying an argument list or an array of arguments. For example:
var foo = $('#thing1');
var myFunc = function(one, two) {
console.log(one);
console.log(two);
console.log(this);
}
myFunc.apply(foo,[2,3]);
Or with call:
myFunc.apply(foo,2,3); //foo is the calling context
Fiddle

Method vs Functions, and other questions

With respect to JS, what's the difference between the two? I know methods are associated with objects, but am confused what's the purpose of functions? How does the syntax of each of them differ?
Also, what's the difference between these 2 syntax'es:
var myFirstFunc = function(param) {
//Do something
};
and
function myFirstFunc(param) {
//Do something
};
Also, I saw somewhere that we need to do something like this before using a function:
obj.myFirstFunc = myFirstFunc;
obj.myFirstFunc("param");
Why is the first line required, and what does it do?
Sorry if these are basic questions, but I'm starting with JS and am confused.
EDIT: For the last bit of code, this is what I'm talking about:
// here we define our method using "this", before we even introduce bob
var setAge = function (newAge) {
this.age = newAge;
};
// now we make bob
var bob = new Object();
bob.age = 30;
// and down here we just use the method we already made
bob.setAge = setAge;
To answer your title question as to what is the difference between a 'function' and a 'method'.
It's semantics and has to do with what you are trying to express.
In JavaScript every function is an object. An object is a collection of key:value pairs. If a value is a primitive (number, string, boolean), or another object, the value is considered a property. If a value is a function, it is called a 'method'.
Within the scope of an object, a function is referred to as a method of that object. It is invoked from the object namespace MyObj.theMethod(). Since we said that a function is an object, a function within a function can be considered a method of that function.
You could say things like “I am going to use the save method of my object.” And "This save method accepts a function as a parameter.” But you generally wouldn't say that a function accepts a method as a parameter.
Btw, the book JavaScript Patterns by Stoyan Stefanov covers your questions in detail, and I highly recommend it if you really want to understand the language. Here's a quote from the book on this subject:
So it could happen that a function A, being an object, has properties and methods, one of which happens to be another function B. Then B can accept a function C as an argument and, when executed, can return another function D.
There is a slight difference -
Method : Method is a function when object is associated with it.
var obj = {
name : "John snow",
work : function someFun(paramA, paramB) {
// some code..
}
Function : When no object is associated with it , it comes to function.
function fun(param1, param2){
// some code...
}
Many answers are saying something along the lines that a method is what a function is called when it is defined on an object.
While this is often true in the way the word is used when people talk about JavaScript or object oriented programming in general (see here), it is worth noting that in ES6 the term method has taken on a very specific meaning (see section 14.3 Method Definitions of the specs).
Method Definitions
A method (in the strict sense) is a function that was defined through the concise method syntax in an object literal or as a class method in a class declaration / expression:
// In object literals:
const obj = {
method() {}
};
// In class declarations:
class MyClass {
method() {}
}
Method Specificities
This answer gives a good overview about the specificities of methods (in the strict sense), namely:
methods get assigned an internal [[HomeObject]] property which allows them to use super.
methods are not created with a prototype property and they don't have an internal [[Construct]] method which means that they cannot be called with new.
the name of a method does not become a binding in the method's scope.
Below are some examples illustrating how methods (in the strict sense) differ from functions defined on objects through function expressions:
Example 1
const obj = {
method() {
super.test; // All good!
},
ordinaryFunction: function ordinaryFunction() {
super.test; // SyntaxError: 'super' keyword unexpected here
}
};
Example 2
const obj = {
method() {},
ordinaryFunction: function ordinaryFunction() {}
};
console.log( obj.ordinaryFunction.hasOwnProperty( 'prototype' ) ); // true
console.log( obj.method.hasOwnProperty( 'prototype' ) ); // false
new obj.ordinaryFunction(); // All good !
new obj.method(); // TypeError: obj.method is not a constructor
Example 3
const obj = {
method() {
console.log( method );
},
ordinaryFunction: function ordinaryFunction() {
console.log( ordinaryFunction );
}
};
obj.ordinaryFunction() // All good!
obj.method() // ReferenceError: method is not defined
A method is a property of an object whose value is a function. Methods are called on objects in the following format: object.method().
//this is an object named developer
const developer = {
name: 'Andrew',
sayHello: function () {
console.log('Hi there!');
},
favoriteLanguage: function (language) {
console.log(`My favorite programming language is ${language}`);
}
};
// favoriteLanguage: and sayHello: and name: all of them are proprieties in the object named developer
now lets say you needed to call favoriteLanguage propriety witch is a function inside the object..
you call it this way
developer.favoriteLanguage('JavaScript');
// My favorite programming language is JavaScript'
so what we name this: developer.favoriteLanguage('JavaScript');
its not a function its not an object? what it is? its a method
Your first line, is creating an object that references a function. You would reference it like this:
myFirstFunc(param);
But you can pass it to another function since it will return the function like so:
function mySecondFunction(func_param){}
mySecondFunction(myFirstFunc);
The second line just creates a function called myFirstFunc which would be referenced like this:
myFirstFunc(param);
And is limited in scope depending on where it is declared, if it is declared outside of any other function it belongs to the global scope. However you can declare a function inside another function. The scope of that function is then limited to the function its declared inside of.
function functionOne(){
function functionTwo(){}; //only accessed via the functionOne scope!
}
Your final examples are creating instances of functions that are then referenced though an object parameter. So this:
function myFirstFunc(param){};
obj.myFirst = myFirstFunc(); //not right!
obj.myFirst = new myFirstFunc(); //right!
obj.myFirst('something here'); //now calling the function
Says that you have an object that references an instance of a function. The key here is that if the function changes the reference you stored in obj.myFirst will not be changed.
While #kevin is basically right there is only functions in JS you can create functions that are much more like methods then functions, take this for example:
function player(){
this.stats = {
health: 0,
mana: 0,
get : function(){
return this;
},
set : function( stats ){
this.health = stats.health;
this.mana = stats.mana;
}
}
You could then call player.stats.get() and it would return to you the value of heath, and mana. So I would consider get and set in this instance to be methods of the player.stats object.
A function executes a list of statements example:
function add() {
var a = 2;
var b = 3;
var c = a + b;
return c;
}
1) A method is a function that is applied to an object example:
var message = "Hello world!";
var x = message.toUpperCase(); // .toUpperCase() is a built in function
2) Creating a method using an object constructor. Once the method belongs to the object you can apply it to that object. example:
function Person(first, last, age, eyecolor) {
this.firstName = first;
this.lastName = last;
this.age = age;
this.eyeColor = eyecolor;
this.name = function() {return this.firstName + " " + this.lastName;};
}
document.getElementById("demo").innerHTML = person.fullName(); // using the
method
Definition of a method: A method is a property of an object that is a function. Methods are defined the way normal functions are defined, except that they have to be assigned as the property of an object.
var myFirstFunc = function(param) {
//Do something
};
and
function myFirstFunc(param) {
//Do something
};
are (almost) identical. The second is (usually) just shorthand. However, as this jsfiddle (http://jsfiddle.net/cu2Sy/) shows, function myFirstFunc will cause the function to be defined as soon as the enclosing scope is entered, whereas myFirstFunc = function will only create it once execution reaches that line.
As for methods, they have a this argument, which is the current object, so:
var obj = {};
obj.func = function( ) {
// here, "this" is obj
this.test = 2;
}
console.log( obj.test ); // undefined
obj.func( );
console.log( obj.test ); // 2
The exact syntax you showed is because you can also do this:
function abc( ) {
this.test = 2;
}
var obj = {};
obj.func = abc;
obj.func( ); // sets obj.test to 2
but you shouldn't without good reason.
ecma document
4.3.31method :
function that is the value of a property
NOTE When a function is called as a method of an object, the object is
passed to the function as its this value.
It is very clear: when you call a function if it implicitly has a this (to point an object) and if you can't call the function without an object, the function deserves to name as method.

obj.foo() and obj(a).foo - how is the solution to do this ? (idea by jQuery)

At first - sorry for my terrible english. I must practice it and will give my very best.
I'll try something new for me in javascript. i get the idea by jQuery libary. There are two
different ways to work with 'jQuery' or '$'.
jQuery(arg).foo(); // first way
jQuery.foo(); // second way
Now i wanted to do the same with an object.
obj(arg).foo();
obj.foo();
My first question was: How can jQuery be an function that returns an object and be an object in
the same way ?
obj(arg).foo();
seems like a function that returns an object.
But
obj.foo();
seems like an object.
I tried something to work with obj.foo() and obj().foo() but nothing worked - in any way i tried out something an error returned: foo() is undefined.
Do you know how jQuery solved it, to register the variable jQuery in this unnormaly way ?
The following is what i want to realize (the code doenst work!):
myClass = function () {
this.foo() {
window.alert('foo()!');
return this;
}
}
var myObj = new myClass();
function obj() {
return myObj.foo(arguments);
}
var obj = {
secondFoo : function () {
myObj.foo();
}
};
obj('arg').foo(); // alert(foo()!) && alert(foo()!)
obj.secondFoo(); // alert(foo()!)
obj('arg'); // alert(foo()!)
here is a little fiddle that display how jQuery does it (well not exactly but the core logic is there) http://jsfiddle.net/UD2Mv/1/
Basically jQuery always returned itself (actually not the jQuery object but an instance of jQuery.fn) unless the function call is expected to return something.
Because it return itself all the properties and methods are returned and are available as a chain. The trick that jQuery does is that it stores element inside this but by using integer keys like in an array.
Which is what I do in the example with this line
this[0] = document.getElementById(id);
This mean the element is now store and available to all methods that are part of this, so when I call colorMe this[0] gives me the targetted element.
Here is the code
function wrap(id) {
return new wrap.init(id);
};
wrap.init = function(id) {
this[0] = document.getElementById(id);
return this;
};
wrap.init.prototype = {
colorMe: function(color) {
this[0].style.color = color;
return this;
}
};
$(function() {
wrap('boo').colorMe('red');
});
In Javascript, all functions are also objects.
You can write
someFunction.someProperty = function() { ... };
someFunction.someProperty();

Coffeescript 'this' inside jQuery .each()

I have some coffeescript like the following:
class foo:
#bar = 'bob loblaw'
processRows: ->
$("#my-table>tr").each ->
id = $(this).attr("id")
#processRow id
processRow: (id) ->
console.log #bar + id
So my problem is: I need this to reference the .each context inside the loop to get at id, but I also would like this to reference the class instance inside foo.processRow()---which it does not currently do.
Using something like _this = this outside the .each function and passing it around isn't a great solution, either, since I reference many class variables inside processRow.
Any thoughts? Am I missing something obvious? Thanks!
jQuery.each passes the current element as second parameter of the callback, so you don't have to reserve this for jQuery:
processRows: ->
$("#my-table>tr").each (index, element) =>
id = $(element).attr("id")
#processRow id
Notice the use of the fat arrow (=>) syntax for the callback function; it binds the function's context to the current value of this. (this in the callback function is always the same this as the one at the time you defined the function.)
You say
Using something like _this = this outside the .each function and passing it around isn't a great solution, either, since I reference many class variables inside processRow.
This is the most efficient solution, though. JavaScript's this is a strange beast; you can keep it fixed inside of a nested function using the => operator, as arnaud576875 sugests in his answer (which is elegant but inefficient), or you can copy this to another variable (which is efficient but inelegant). The choice is yours.
Note that some modern browsers support a bind method on every function, which is more efficient than CoffeeScript's =>. There's an open ticket to have => use the native bind when available: https://github.com/jashkenas/coffee-script/pull/1408
Addendum: Of course, a more efficient alternative than any of the above would be to write
for element, index in $('#my-table>tr')
...
which would also solve your this problem.
Your code...
class foo
#bar = 'bob loblaw'
processRows: ->
$("#my-table>tr").each ->
id = $(this).attr("id")
#processRow id
processRow: (id) ->
console.log #bar + id
Is transpiled to...
var foo;
foo = (function() {
function foo() {}
foo.bar = 'bob loblaw';
foo.prototype.processRows = function() {
return $("#my-table>tr").each(function() {
var id;
id = $(this).attr("id");
return this.processRow(id);
});
};
foo.prototype.processRow = function(id) {
return console.log(this.bar + id);
};
return foo;
})();
Which has assumed much about about the current context that it is translating to. Unfortunately, since jQuery manages context, you'll have to be explicit or declare a reference to your class's this.
Incidentally, there are other issues with that generated code, take a look at this reduced case:
class foo
#bar = 'bob loblaw'
getBar: () ->
#bar
Transpiles to:
var foo;
foo = (function() {
function foo() {}
foo.bar = 'bob loblaw';
foo.prototype.getBar = function() {
return this.bar;
};
return foo;
})();
The results of attempting to use this piece of code:
> foo.bar;
"bob loblaw"
> var f = new foo();
undefined
> f.getBar();
undefined
Your code seems to expect that #bar is an own property, but it's being created as a static property of the foo function

Categories