This question already has answers here:
Is JavaScript a pass-by-reference or pass-by-value language?
(33 answers)
Closed 7 years ago.
I know I am doing something egregiously wrong in using the namespaces. I am posting this question after researching a ton in the net / google searches. Still can’t find what I am doing wrong. Can you please help me out?
This is what I have
Javascript
Javascript file1
(function (js_namspace1, $, undefined) {
js_namespace1.n1function1 = function(){
var return_obj = {
return_function_to_call: “n1function_name2”
return_function_to_call_namespace: “js_namespace1”
}
js_namespace2.n2function1(return_obj)
}
Js_namespace1.n1function_name2 =function(list_of_names){
Js_namespace1.list_of_names = list_of_names
// do some processing to js_namespace1. list_of_names
}
}
(window. js_namspace1 = window. js_namspace1|| {}, jQuery ));
Javascript file2
(function (js_namspace2, $, undefined) {
js_namespace2.n2function1(return_obj) = function(return_obj){
js_namespace2.return_function_to_call = return_obj.return_function_to_call
js_namespace2.return_function_to_call_namespace = return_obj. .return_function_to_call_namespace
// do some processing
Js_namespace2.list_of_names = []
Js_namespace2. list_of_names.push(value_name)
window[js_namespace2.return_function_to_call_namespace][js_namespace2.return_function_to_call]( Js_namespace2.list_of_names);
}
}
(window. js_namspace2 = window. js_namspace2|| {}, jQuery ));
Html
From html file1 call js_namespace1.n1function1 based on end user clicking a field
// js_namespace1.n1function1 calls js_namespace2.n2function1 and displays another html file2
// In html file2 process the data (collect value of names) and then call the return function Js_namespace1.n1function_name2
In Js_namespace1.n1function_name2, process Js_namespace1.list_of_names(array), but when I do this, it also changes in Js_namespace2.list_of_names
For example when I do
Js_namespace1.n1function_name2.push(add_another_name), and then call js_namespace1.n1function1 (which in turn calls js_namespace2.n2function1). Js_namespace2.list_of_names contains the value of add_another_name.
Please note that when js_namespace2.n2function1 is called from js_namespace1.n1function1 the array is not passed as parameter.
My expectation was when js_namespace1.n1function1 calls js_namespace2.n2function1 it would not update Js_namespace2.list_of_names with the add_another_name.
Can you please explain what is happening? most importantly point out any mistakes that I should be avoiding in this design (namespace, exchange of parameters between function calls). Am I using the namespace correctly in javascript – any best practices to recommend?
Here's a link from a quick Google search on best practices for JS. There are different schools of thought out there (eg. use of terminating semicolons), but use of a some kind of linter might help you figure out typos, case sensitivity, and unintended whitespace in the code if you can't notice for yourself. Below is your code with some fixes:
(function (js_namespace1, $, undefined) {
js_namespace1.n1function1 = function(){
var return_obj = {
return_function_to_call: "n1function_name2",
return_function_to_call_namespace: "js_namespace1"
};
js_namespace2.n2function1(return_obj)
};
js_namespace1.n1function_name2 =function(list_of_names){
js_namespace1.list_of_names = list_of_names;
console.log(js_namespace1.list_of_names); // ["some_name"]
};
}
(js_namespace1 = window.js_namespace1 || {}, jQuery));
(function (js_namespace2, $, undefined) {
js_namespace2.n2function1 = function(return_obj){
js_namespace2.return_function_to_call = return_obj.return_function_to_call;
js_namespace2.return_function_to_call_namespace = return_obj.return_function_to_call_namespace;
// do some processing
js_namespace2.list_of_names = [];
js_namespace2.list_of_names.push("some_name");
window[js_namespace2.return_function_to_call_namespace][js_namespace2.return_function_to_call]( js_namespace2.list_of_names);
};
}
(js_namespace2 = window.js_namespace2 || {}, jQuery));
js_namespace1.n1function1();
Some points about your code and my fixes:
You used case sensitive names like js_namespace2 for Js_namespace2.
Your syntax here is incorrect js_namespace2.n2function1(return_obj) = function(return_obj).
And here: return_obj. .return_function_to_call_namespace and others.
value_name is not defined
I tested the code here and see expected behavior.
Related
I have a problem with the binding of functions in Javascript.
Be sure that I read all StackOverflow's answers I could find
(like this one),
and followed the instructions and examples of
Mozilla's Developpers guides
here is the relevant part of my code :
class Collection extends Array {
constructor (...args) {
super(...args)
}
each (callback) {
this.forEach(element => {
callback.bind(element)(element)
// bind the function THEN call it with element as argument
// but I also tried :
// callback.bind(element)()
// callback.call(element, element)
// let bound = callback.bind(element); bound()
})
}
}
//the tests :
let el1 = {x:1, y:"somevars"}
let el2 = {x:42, y:"another"}
let col = new Collection()
col.push(el1)
col.push(el2)
// the test
col.each(element => console.log(Object.keys(this)))
// and I get ['console', 'global', 'process' ...] all the global variables
// instead of ['x','y'] which is what I want
I really don't understant why it is'nt working...
for context, it is to solve an interesting
kata on Codewars,
not a matter of life and death.
Ok so as pointed by #Teemu, arrow functions can't be bound ...
but with that insight, I could look for a way to bypass this and found
another StackOverflow's post
that gives a trick :
(copy-pasted from the post)
function arrowBind(context, fn) {
let arrowFn;
(function() {
arrowFn = eval(fn.toString());
arrowFn();
}).call(context);
}
arrowBind(obj, () => {console.log(this)});
this works just fine, the new this is the context...
But doesn't solve the puzzle in my case ( 'having is not defined') I need to look further
I've got a functional script on my site that allows me to open a link in a new window when a specific class is added to the link. I need a lot of those on my site though so I figured I'd make the script a bit easier to edit by working with variables.
In the process of changing out hardcoded strings for variables my script stopped working though. The only one that works is the var where I set the url.
I'm learning that ${} doesn't work everywhere. Hope that someone can point out where my thinking is wrong. Also hope that I got the terminology right, trying to learn though! :-)
var function1Name = "test_function";
var function1Url = "https://www.google.com";
var function1Class = ".test_function_class";
function ${function1Name}() {
window.open(function1Url, "_blank", "height=200");
}
jQuery("${function1Class}").click(function(){
${function1Name}()
});
None of your uses of ${} are valid JavaScript syntax.
Your function declaration van be replaced with:
window[function1Name] = function () {
window.open(function1Url, "_blank", "height=200");
}
Please note that the function will no longer be hoisted when declared this way, so order of operation matters.
The click handler can be written as follows:
jQuery(function1Class).click(function() { // Note that I just used the variable there.
window[function1Name]();
});
There is a ${} concept in JavaScript, but that is only in template literals:
const myVariable = "Foo";
const message = `myVariable contains: "${myVariable}"!`;
console.log(message);
There's several syntax issues here.
Firstly, function ${function1Name}() is not valid syntax. Function names must be defined before runtime. If you want to dynamically access a function, place it in an object and set the key with the variable reference.
Secondly, ${function1Name}() is again not valid syntax. You cannot invoke a function like that dynamically. Referring to the suggestion above, you can access an object dynamically so the first point fixes this problem.
Thirdly, string interpolation only works within template literals, so you need to delimit the string with backticks: ``. However it's completely redundant here as you can just use $(function1Class)
With those issues in mind, here's an updated example:
var function1Name = "test_function";
var function1Url = "https://www.google.com";
var function1Class = ".test_function_class";
var funcObj = {
[function1Name]: function() {
console.log(`function called, window would open here containing ${function1Url}...`);
// window.open(function1Url, "_blank", "height=200");
}
}
$(function1Class).click(function() {
funcObj[function1Name]()
});
/*
alternative using a template literal, although note that it's redundant here
$(`${function1Class}`).click(function() {
funcObj[function1Name]()
});
*/
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
Click me
One last thing to note is that no version of IE supports template literals, so be sure of your browser support requirements before using them.
So cool, I got it to work!
var function1Name = "test_function_1";
var function1Url = "https://www.google.com";
var function1Class = ".test_function_class1";
var function2Name = "test_function_2";
var function2Url = "https://www.cnn.com";
var function2Class = ".test_function_class2";
// Function 1
window[function1Name] = function () {
window.open(function1Url, "_blank", "toolbar=no,status=no,scrollbars=yes,resizable=yes,top=500,left=500,width=600,height=745");
}
jQuery(function1Class).click(function() {
window[function1Name]();
});
// Function 2
window[function2Name] = function () {
window.open(function2Url, "_blank", "toolbar=no,status=no,scrollbars=yes,resizable=yes,top=500,left=500,width=600,height=745");
}
jQuery(function2Class).click(function() {
window[function2Name]();
});
I can now add a bunch of url's and corresponding classes as was my intention. Super happy about that.
A follow up question though, as I'll have to experiment with what the ideal window parameters will be I'm trying to make those arguments variables as well. I've tried the examples of how to insert a variables output from the functional code but those methods don't work there. Here's that code:
var windowWidth = 250
var function1Name = "test_function_1";
var function1Url = "https://www.google.com";
var function1Class = ".test_function_class1";
var function2Name = "test_function_2";
var function2Url = "https://www.cnn.com";
var function2Class = ".test_function_class2";
// Function 1
window[function1Name] = function () {
window.open(function1Url, "_blank", "toolbar=no,status=no,scrollbars=yes,resizable=yes,top=500,left=500,width=[windowWidth],height=745");
}
jQuery(function1Class).click(function() {
window[function1Name]();
});
// Function 2
window[function2Name] = function () {
window.open(function2Url, "_blank", "toolbar=no,status=no,scrollbars=yes,resizable=yes,top=500,left=500,width=600,height=745");
}
jQuery(function2Class).click(function() {
window[function2Name]();
});
How would I insert the variables value (2nd line of Function1) there ?
So I am currently reading through Clean Code and I really like the idea of super small functions that each tell their own "story". I also really like the way he puts how code should be written to be read in terms of "TO paragraphs", which I've decided to kind of rename in my head to "in order to"
Anyway I have been refactoring alot of code to include more meaningful names and to make the flow in which it will be read a little better and I have stumbled into something that I am unsure on and maybe some gurus here could give me some solid advice!
I know that code-styles is a highly controversial and subjective topic, but hopefully I wont get reamed out by this post.
Thanks everyone!
PSA: I am a noob, fresh out of College creating a web app using the MEAN stack for an internal project in an internship at the moment.
Clean Code refactor
//Modal Controller stuff above. vm.task is an instance variable
vm.task = vm.data.task;
castTaskDataTypesForForm();
function castTaskDataTypesForForm() {
castPriorityToInt();
castReminderInHoursToInt();
castDueDateToDate();
getAssigneObjFromAssigneeString();
}
function castPriorityToInt() {
vm.task.priority = vm.task.priority === undefined ?
0 : parseInt(vm.task.priority);
}
function castReminderInHoursToInt() {
vm.task.reminderInHours = vm.task.reminderInHours === undefined ?
0 : parseInt(vm.task.reminderInHours);
}
function castDueDateToDate() {
vm.task.dueDate = new Date(vm.task.dueDate);
}
function getAssigneObjFromAssigneeString() {
vm.task.assignee = getUserFromId(vm.task.assignee);
}
Possibly better refactor? / My question ----------------------------
//Modal Controller stuff above. vm.task is an instance variable
vm.task = vm.data.task;
castTaskDataTypesForForm();
function castTaskDataTypesForForm() {
castPriorityToInt();
castReminderInHoursToInt();
castDueDateToDate();
getAssigneObjFromAssigneeString();
function castPriorityToInt() {
vm.task.priority = vm.task.priority === undefined ?
0 : parseInt(vm.task.priority);
}
function castReminderInHoursToInt() {
vm.task.reminderInHours = vm.task.reminderInHours === undefined ?
0 : parseInt(vm.task.reminderInHours);
}
function castDueDateToDate() {
vm.task.dueDate = new Date(vm.task.dueDate);
}
function getAssigneObjFromAssigneeString() {
vm.task.assignee = getUserFromId(vm.task.assignee);
}
}
Posting the IIFE example here so I have more room to work with. I'm not saying this is the best option, it's the one I would use with the info the OP gave us.
var castTaskDataTypesForForm = (function() {
var castPriorityToInt = function castPriorityToInt() { ... },
castReminderInHoursToInt = function castReminderInHoursToInt() { .. },
castDueDateToDate = function castDueDateToDate() { ... },
getAssigneObjFromAssigneeString = function getAssigneObjFromAssigneeString() { ... };
return function castTaskDataTypesForForm() {
castPriorityToInt();
castReminderInHoursToInt();
castDueDateToDate();
getAssigneObjFromAssigneeString();
};
}());
vm.task = vm.data.task;
castTaskDataTypesForForm();
This way the helper functions only get defined once and are kept private inside the closure. You can obv remove the var x = function x syntax if you prefer the function x() style.
edit: If the function only gets called once, your own examples are probably the cleaner code. The reason you'd use the IIFE syntax would be to keep the helper functions only accesible by the main function, like in your own second example.
MEANjs uses the second method sometimes (with callbacks for example). I personally think it's nice if you are not intending to use those helpers outside of the main function.
This question already has answers here:
How to access the correct `this` inside a callback
(13 answers)
Closed 7 years ago.
I have a class in javascript with a property (is_initialized) and a function (isInitialized).
Class definition :
function Test()
{
this.is_initialized = { obj: { isInitialized: 'notyet' } };
this.isInitialized = function( ref )
{
if ( !ref.obj )
{
console.log( 'now: ' + JSON.stringify( this.is_initialized ) );
/*line 9*/ this.is_initialized.obj.isInitialized = ref.isInitialized.toString();
console.log( ref );
}
else {
bluetoothle.isInitialized( this.isInitialized );
/*line 14*/ ref.obj = this.is_initialized.obj;
}
};
}
bluetoothle.isInitialized is a function in a cordova plugin (no knowledge of cordova is required for answering this question), it returns an object { isInitialized : true/false } and will pass the first if-statement whilst my call to isInitialized() will execute the else.
Question :
Why does this.is_initialized on line 9 create a new property inside the function isInitialized while this.is_initialized on line 14 uses the property is_initialized in Test()?
Shouldn't it both use the property inside Test() or use a (new) variable inside isInitialized()?
And if it 'just' behaves like this, what can i do to deal with it?
Code i ran :
var t = new Test();
var r = {obj:{isInitialized:'nope'}};
t.isInitialized(r);
// console.log( 'now: ' + JSON.stringify( this.is_initialized ) ); on line 8:
// now: {"obj":{"isInitialized":"false"}}
// console.log( ref ); on line 10:
// Object {isInitialized: false}
console.log(JSON.stringify(r));
// {"obj":{"isInitialized":"notyet"}}
console.log(JSON.stringify(t));
// {"is_initialized":{"obj":{"isInitialized":"notyet"}}}
What just happened is this:
i made a new instance of Test() and named it t.
i made an object with matching structure of is_initialized in Test() but with a different value.
i called the function with r as parameter.
code in the else executes.
asynchronous function with isInitialized as callback is called.
the function created a reference between the existing is_initialized and r.
the async function calls isInitialized and executes the code in the if.
it logs the current value of this.is_initialized on line 8, somehow it gets this.is_initialized after line 9 is executed.
line 9 executes, creating a new variable named is_initialized inside isInitialized() while i want it to set is_initialized in Test() and not create a new variable that dies when the function is done executing.
it logs the object that was put into this.is_initialized.obj.isInitialized.
i log r and see that it contains the initial value of Test.is_initialized.
i log t and see that is_initialized's value is still initial.
Info :
If you want to test it yourself to answer my question of the why? and the how do i deal with it? but need some code for bluetoothle.isInitialized just use this:
var bluetoothle = {isInitialized:function(){setTimeout(function(){func({isInitialized:false});},20);}};
// to execute:
bluetoothle.isInitialized(/*callbackfunction*/);
I would like to thank you for reading this long question.
You're in a function. Inside a function (unless it's declared as Test.prototype.isInitialized), the scoping rules for 'this' are different. This is one of the gotchas that ES6 aims to eliminate. (If you added "use strict"; at the top of the function most browsers would tell you this.)
Declare var self = this in Test and use self inside your interior function and you should get the result you want. #squint has pretty much already said this.
I'm trying to create a simple, small and basic javascript framework just for learning purposes.
But the thing is that i'm allready stuck at the very basics.
I'm trying to do something like this:
$('testdiv').testFunction();
And the code i've written for that:
var elementID;
var smallFramework = {
$:function(id) {
this.elementID = id;
},
testFunction:function() {
alert(this.elementID);
}
};
window.$ = smallFramework.$;
But in return I get:
$('testdiv) is undefined
Can anyone help me with this small and hopefully easy question?
To get the behavior you're expecting, you need the $ function to return an object with a method named testFunction.
Try:
var smallFramework = // an object for namespacing
{
$:function(id) // the core function - returns an object wrapping the id
{
return { // return an object literal
elementID: id, // holding the id passed in
testFunction: function() // and a simple method
{
alert(this.elementID);
}
};
}
};
Of course, there are many other ways to achieve the behavior you desire.
If you're trying to add methods to an HTML element you could do something along these lines.
$ = function( elementId ) {
var element = document.getElementById( elementId );
element.testFunction = function(){
alert( this.id );
return this; // for chaining
}
return element;
}
$('test').testFunction();
Try
smallFramework.$('testdiv');
instead. According to the code you posted, that's where your $ function ended up.
Or alternatively, it looks like you're trying to replicate something like jQuery. You might want to try something like this.
var $ = smallFramework = (function () {
var f =
{
find:function(id) {
f.elementID = id;
return f; //every function should return f, for chaining to work
},
testFunction:function() {
alert(f.elementID);
return f;
}
}
return f.find //the find function will be assigned to $.
//and also assigned to smallFramework.
//the find function returns f, so you get access to testFunction via chaining
// like $("blah").testFunction()
})() //note this function gets called immediately.
this code may look confusing to someone new to JavaScript because it depends heavily on the concept of closures. I suggest that if this doesn't make sense, spend some time at Douglas Crockford's JavaScript website. This is important because the code above will bite if you happen to use this in the find function because this won't be bound to f, as you may expect it to be when you use it from $ or smallFramework.