How to attach a function dynamically to a javascript object.For ex: if the function for dynamic attachment is attach(),then i should be able to attach the function fn to onject obj as follows..
attach(
obj,fn,{
alert(1)
}
)
function attach(obj,fnName,code)
{
obj[fnName] = code;
}
If by "attach a function dynamically to a javascript object" you mean "add a function-object as an object property" then the syntax you've already shown is almost right. This is what it should be:
var fnName = "testFunc";
obj[fnName] = function() { alert("Test function"); };
// or
obj.testFunc = function() { ... };
// or
obj[fnName] = nameOfFunctionDefinedElsewhereInCurrentScope;
Which means you could call your attach() function like this:
// attach an anonymous function:
attach(obj, "newFunctionName", function() { alert(1); });
// attach a function defined elsewhere
attach(obj, "newFunctionName", someFunction);
Note: the attach() function really doesn't save any effort at all, in fact it just gives you more characters to type...
By the way (but don't do this), if the parameter you want to pass as code is a string of code do this:
var code = "alert(0);";
obj[fnName] = new Function(code);
More information: https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function
EDIT : The other post's Function(code) solution appears better. I did not know about that constructor.
A possible solution may be:
Object.prototype.attach = function(name,code) {
this.name = function() {
eval(code);
};
}
You can attach them as function objects if they've already been defined, such as here: Javascript: better way to add dynamic methods?
You can also use the new Function constructor to dynamically define the functions, such as here: Creating functions dynamically in JS
Here is an explanation of the differences between eval and the new Function constructor: Are eval() and new Function() the same thing?
As a warning, use of eval() and the new Function constructor have created controversy and have been condemned (to some extent) by a number of individuals, such as here: Legitimate uses of the Function constructor
Here is more information about eval: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/eval
Here is more information about the new Function constructor: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function
Assuming that definition of function attach, you should call it like this:
attach(obj, fnName, function(){ alert(1); });
The way you invoked it is invalid syntax.
Also, as you may have noticed, that's not a very useful function, since you can do the same thing using your one-line function definition:
obj[fnName] = function(){ alert(1); });
Related
I'm trying to understand something in JavaScript which confuses me.
Let's say that I want to create a method Guard.ThrowError() in JavaScript, I have 2 approaches for this:
Using an object:
This is basically the approach which I found on the net.
var Guard2 = {
ThrowIfNull: function() {
throw new Error('sdmflsfk');
}
};
Using a Function:
When you create a class "Guard" in TypeScript and you let it compile to JavaScript, you get something like this:
var Guard = (function() {
function Guard() { }
Guard.ThrowIfNull = function () {
throw new Error('sdmflsfk');
};
return Guard;
})();
Both functions can be called using Guard.ThrowIfNull().
I would like to know what's the difference and when choose I choose approach 1 over approach 2?
Thanks for your valuable feedback.
Kind regards
I would like to know what's the difference and when choose I choose approach 1 over approach 2?
The only difference is that Guard is a function in your second example and not a function in your first. So the second one can be called (in that code it doesn't actually do anything, but it can be called); the first can't.
Functions are objects in JavaScript, proper real objects, and so like all other objects, they can have additional properties added to them like your ThrowIfNull.
jQuery is a widely-used example of this: The main function, jQuery (aka $) is used for its function-ness:
$("#foo").on("click", function() { /*...*/ });
...and also for its object-ness, because it has various properties attached to it exactly as you've done with Guard:
$.ajax(/*...*/);
Both approach works because a function in javascript is also an object. The only difference is that you can call a function myFunction(); and you can't do it with a object.
Function approach is used to create classes in JS. Using this approach, you can have private and public properties. This cannot be achieve in object approach. All properties are public in object.
Sample Example
function testClass(){
// Private member
var a = "abc";
var b = "test";
function print(){
console.log(a,b);
}
return {
print: print
}
}
testClass().print();
// testClass().a This will throw error
Guard2- your approach 1 - is somehow a 'static' definition of an object. You can't instatiate another object of that type.
Guard- your approach 2 - is a mixed: it's a definition of an 'automatic class' Guard which gets instantiated. The result is almost the same as you can't instantiate new objects from that as well.
Usually, you would do it like this:
var Guard = function() {
function Guard() { };
Guard.ThrowIfNull = function () {
throw new Error('sdmflsfk');
};
};
var myGuard = new Guard();
I am new to Javascript and am still getting my head round the various ways of creating objects i.e constructor+new, prototypal, functional & parts.
I have created what I think is an object factory using the module pattern and want to know what the correct method of calling an internal method would be. Is it via this or function name.
Here is my module:
function chart() {
function my() {
// generate chart here, using `width` and `height`
}
my.sayHi = function(){
console.log('hi');
my.sayBye();
};
my.sayBye = function(){
console.log('Bye');
};
return my;
}
var test = chart();
test.sayHi();
You can see that the first function calls the second using my.sayBye() or is it better to use this.sayBye(). Both produce the same result and run without error.
The module pattern allows you to dispense with the 'this' variable if you want to. I would probably rewrite the above code to look like this and then the question becomes moot.
function chart() {
var hiCount = 0;
function sayHi(){
console.log('hi');
hiCount++;
sayBye();
};
function sayBye(){
console.log('Bye');
};
return {
sayHi : sayHi,
sayBye: sayBye
};
}
var test = chart();
test.sayHi();
In the above code all is defined within the function chart. As JavaScript's scope is at the function level every time the chart function is called a new set of functions will be defined. And a new set of variables can also be defined that are private to the function as they are defined in the function and are not accessible from outside. I added hiCount as an example of how you could do this. The Module pattern allows privacy in JavaScript. It eats more memory than the prototype pattern though as each time a function is declared it is not shared between other instances of the same class. That is the price you have to pay in Javascript to have class variables that are private. I willingly pay it. Removing 'this' from my code makes it easier to understand and less likely that I will fall into problems of misplaced scope.
Using "this" is better approach because you would be able to bind the function directly to the parent function object.And you dont need to return anything from the function.
where as in your case you are explicitly returning another function
Here is the use of "this" approach
function chart() {
this.sayHi = function(){
console.log('hi');
}
}
var test = new chart();
test.sayHi();
Using this approach you would be able to call anything in the prototype of function "chart"
Eg
chart.prototype.hello = function(){
console.log('hello')
}
So you would be able to call the hello function from the same object(test)
Original Question
Can't figure out why I can't call the second function from within that first function. I am using jQuery-turbolinks. (Also, if you happen to know of a better way to only run page-specific javascript in rails, let me know. Currently this is my best implementation where I check if the body has a certain class, and if it does then I run the init function within this javascript object).
app/assets/javascripts/blogs.js
$(document).ready(function(){
var blogsjs = {
myBlog: this,
init: function(){
alert("hello from blogs");
$("input").on('click', function(){
$(this).hide('slow', function(){
myBlog.another();
});
});
},
another: function(){
alert("I was called!")
}
};
if($('body').hasClass("blogs") == true){
blogsjs.init();
}
});
Solution After Feedback
Simply Just used object.method() syntax from within a method to call another method within that same object:
$(document).ready(function(){
var blogsjs = {
init: function(){
alert("hello from blogs");
$("input").on('click', function(){
$(this).hide('slow', function(){
blogsjs.another();
});
});
},
another: function(){
alert("I was called!");
blogsjs.yetanother();
},
yetanother: function(){
alert("yet another called");
}
};
blogsjs.init();
});
I don't like how messy this code looks, but the encapsulation benefits from an Object-oriented design, I think, is solid: Each resource's javascript only has access to the methods inside its javascript object.
I don't know what you're trying to accomplish with this part of your declaration:
var blogsjs = {
myBlog: this
}
but, this will NOT be set to blogsjs. It will be whatever it was in the above function. In Javascript, this is only set on a function call. It is NOT set in a Javascript literal declaration so you cannot statically declare a property that refers to the object itself. Javascript just does not support that.
You can add properties after the object is constructed that contain references to the object if desired.
If you want myBlog to be initialized to point to blogsjs, then you will have to do that after the object is defined:
var blogsjs = {
init: function() {...},
another: function() {...}
};
blogsjs.myBlog = blogsjs;
In addition, this line of code won't work:
myBlog.another();
because myBlog is a property of an object, not a variable. It must be referenced with its parent object.
So you're probably getting an Cannot read property 'another' of undefined exception because you're specifying myBlog on the blogsjs object but do not reference it. Also myBlog will not be a reference to blogsjs but the scope jquery calls the document.ready function with.
You need to either create the reference inside your init method:
init: function(){
var myBlog = this;
alert("hello from blogs");
$("input").on('click', function(){
$(this).hide('slow', function(){
myBlog.another();
});
});
}
or simply use blogsjs from one scope above your init method.
Have a look at this question to learn about scoping.
ive been using call a bit recently in some tutorials I've been following but am more used to passing the object. I was wondering is it best to use call. What's the most efficient way?
var editor = function(someParam){
//do something with this
}
var testFunction function(someParam){
editor.call(this, someParam);
}
or
var editor = function(obj, someParam){
var self = obj;
}
var testFunction function(someParam){
editor(this, someParam);
}
I would stick with passing the object to the function as long as you can structure the function that way.
I see call more like a utility if the function cannot be changed anymore and you really have to inject a different this context.
Also, consider using the prototype approach if your function is bound very close to some object that you want to call the function on.
Also, call will be less performant than passing the object to the function, as the injection of a different this has some overhead.
In some cases call is very useful, for example when adding event handler:
window.addEventListener('load', function(){
var cb = document.getElementById('myCheckBox');
cb.addEventListener('change', onchange);
onchange.call(cb); // sets `cb` as `this` in `onchange` function
});
function onchange(){
// I'm using 'this' for current element
if(this.checked)
alert('checked');
}
In this case onchange will be called on window load and every time checkbox checked state changes
I have some javascript code (within an object) :
toggle: function() {
var me = this;
var handler = function() { me.progress() };
me.intervalId = setInterval(handler, me.intervalTime);
//...More code
}
I'm kind of new to javascript, so doing the above as far as I can tell actually passes the me variable into anonymous the function. I was wanting to see if there is a more declarative way to do so? I wanted something along the line of:
var handler = (function(o) { o.progress();})(this));
but that doesn't seem to be working... Am I missing something? Is this a case where "this is the way the language works so just declare a local variable and deal with it"?
UPDATE:
The source to my problem was/is my unclear understanding of scope and closures in javascript. I found this article to help me understand a little more.
You can use ".bind()":
var handler = function() { this.progress(); }.bind(this);
New browsers have "bind()", and the Mozilla docs have a solid implementation you can use to patch older browsers.
The reason
var handler = (function(o) { o.progress();})(this));
doesn't work because it just immediately calls the anon function, therefore immediately calling o.progress() and assigns the return value of the anon function (undefined) to handler. You need to return an actual function from the outer function:
handler = (function(me){
return function(){
return me.progress();
}
}(this));
On the flip side this is equivalent and just as bad looking as bad looking as the variable assignment (but can still be useful, particularly if this needs to be done in a loop, with the changing i rather than the fixed this).
BTW, if the progress function doesn't have any calls to this inside it , just doing handler = this.progress (without the parens) might suffice.
The anonymous function has access to me because it is declared inside of the outer function (the toggle function); it is closed over by the outer function.
Your handler function will be called by setInterval, which passes exactly zero arguments. This means you can't use parameters in the handler function itself.
I you really want to pass me explicitly, you could write a function accepting an parameter, and have that function return an anonymous function without parameters, but which could access the creator function's parameter:
toggle: function() {
var me = this;
var handler = (function (o) { return function() { o.progress() }; })(me);
me.intervalId = setInterval(handler, me.intervalTime);
//...More code
}
But this basically adds a layer of redirection without really making it more legible. Unless you pull that creating function outside:
function createProgressHandler(o) {
return function() {
o.progress();
};
}
// ...
toggle: function() {
var me = this;
var handler = createProgressHandler(me);
me.intervalId = setInterval(handler, me.intervalTime);
//...More code
}
What you have there is a closure. The function that is created and assigned to handler keeps a reference to the me object. This is normal, everyday JavaScript, and that's the way that closures work generally.
Have you tried to return the function like this?
var handler = function(o){
return function(){
o.progress();
}
}(me);
Now you can call:
handler();