What's the best way to chain a JavaScript function between different files? In this case, BusinessObjectCategories() and BusinessAddSiteStatusFunctionalities() are undefined because the function is in another page. Should I get the global object in JavaScript?
**Doo.js**
var Doo = new DooObject();
**Doo.Business.js**
function BusinessObject() {}
if (typeof Doo != undefined) {
Doo.Business = new BusinessObject();
BusinessObjectCategories();
}
**Doo.Business.Categories.js**
function BusinessObjectCategories() {}
if (typeof Doo != undefined) {
Doo.Business.Categories = new BusinessObjectCategories();
BusinessAddSiteStatusFunctionalities();
}
**Doo.Business.Categories.SiteStatus.js**
function BusinessAddSiteStatusFunctionalities() {}
Assuming this is just example code, it's about how you want to structure your project. You can easily split up all of your functions into different files and export them (MDN: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/export).
Then, in the file(s) of your choosing, just use import (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import).
This is extremely common, and allows you to not pollute up your global scope. Just as easily, you could put a variety of helper functions in a file, and import specific functions of need into particular files. This way, you're not split between so many different files and you're still not polluting your global scope.
Unless you want to go through countless hoops, hard to read code and many headaches... You'll want to use a javascript framework like Angular in order to apply object oriented concepts to javascript without having to write ugly things like:
MyParentFunction.call(this);
Javascript frameworks like Angular allows you to use inheritance as you would in most object oriented languages.
class MyChildrenClass implements MyParentClass { }
If you absolutely want to do it using vanilla javascript, give this a read.
Related
In Javascript, local variables do not live on any object that I'm aware of. That is,
function foo() {
const x = 2;
self.x; // undefined
this.x; // undefined
window.x; // undefined
x; // 2, obviously
eval('x'); // 2
}
The last option eval('x') shows that it is possible to refer to these variables by name. I'm looking to extend this and access a variable using a name pattern:
function foo() {
// Code not under my direct control
function foobar_abc() {}
function other_functions() {}
// Code under my control
const matchingFunction = // find the function with name matching 'foobar_*'
}
If this lived on an object, I would use something like myObject[Object.keys(myObject).find((key) => key.startsWith('foobar_'))]. If it were in the global scope, myObject would be window and everything works.
The fact that eval is able to access the variable by name implies that the value is available somewhere. Is there any way to find this variable? Or must I resort to techniques which re-write the (potentially very complex) code which is not under my direct control?
I'm targeting modern browsers, and in this use case I don't mind using eval or similarly hacky solutions. Arbitrary code is already being executed, because the execution of user-provided code is the purpose.
Another option is to use code parsing to deduce the function names using a javascript AST (abstract syntax tree) library. The "esprima" package will probably be good place to look:
https://www.npmjs.com/package/esprima
So you can do
import esprima from 'esprima'
const userCodeStructure = esprima.parseScript( userProvidedJavascriptString );
const allTopLevelFunctionDeclarations = userCodeStructure.body.filter( declaration => declaration.type === "FunctionDeclaration" );
const allTopLevelFunctionNames = allTopLevelFunctionDeclarations.map( d => d.id );
I haven't tried this myself by the documentation suggests it should work (or something like it):
http://esprima.readthedocs.io/en/latest/
One possible approach that might help you here is to evaluate at global scope rather than in a function, and that might put the functions on the window object instead of in local scope.
Easiest way to do this is probably to write a new tag into the document and inject the user-provided code.
Relying on variable names is the wrong approach.
eval is evil. It may not be available under CSP. Considering that the code is supposed to run in browser, the biggest problem is that variables don't have expected names in minified code. They are a, b, c...
In order to maintain their names, they should be object properties - and so they will be available on the object.
Or must I resort to techniques which re-write the (potentially very complex) code
This is refactoring and that's what should be done to avoid bad code that smells and creates major problems.
I've always used jquery with a
$(document).ready(function {
....
});
But i've recently just inherited a complete site with the script file opening like the following:
var gc = gc || {};
gc.header = {
mobileNav: function () {
...
},
headerLink: function () {
...
}
};
gc.header.headerLink();
I've never seen it structured in this way - it's actually quite easy to use and would love to learn more about to help improve my coding styles.
If somebody could help me by providing me with what this type of coding style is? And - if you know of any, some learning resources?
Thanks in advance!
Lew.
It is usually referred to as namespacing. It has absolutely nothing to do with jQuery.
This style of JavaScript syntax is a little more object oriented. This makes it easier to edit and read but also helps your JavaScript stay 'clean' by namespacing your JavaScript. This means that you basically try to keep as much of your JavaScript out of the Global Object as possible - thereby reducing collisions in your code.
Line by line:
var gc = gc || {}; // If a 'gc' object exists, use it. Otherwise create an empty object.
gc.header = { // In the gc.header object create 2 methods, mobileNav and headerLink
mobileNav: function () {
...
},
headerLink: function () {
...
}
};
gc.header.headerLink(); // Reference the headerLink() method inside gc.header
This is far preferable to creating a more flat pattern where mobileNav and headerLink are global functions because mobileNav and headerLink are very generic functions that may be used and named identically in other plugins. By namespacing you reduce the risk of breaking your code and running into collisions because gc.header.headerLink() is much more unique.
It`s just ordinary JavaScript, it's a technique called namespacing: How do I declare a namespace in JavaScript?
Context: I have written a mini JS library for myself which is simply a collection of commonly used classes. I have followed the IIFE (http://benalman.com/news/2010/11/immediately-invoked-function-expression/) technique to separate my code into modules/classes and they're all grouped under a common global namespace var. Let's call it, ns. So we have a typical setup, ns.ClassA, ns.ClassB, etc. Now on the other hand, a separate script (main.js) is loaded at runtime and appended to the document, and this main.js contains the actual code that uses these classes.
Goal: I am trying to find an elegant way of accessing the classes inside main.js directly by calling the class name instead of having to access them through ns. . For example, I would want to be able to do var a = new ClassA(); instead of var a = new ns.ClassA();
Solutions researched & considered:
1) the dreaded 'with' keyword (javascript "static imports"). In this case, I would do something like with(ns){ var a = new ClassA()} , except I will have to wrap the entire main.js inside the with(ns) statement. This is undesirable for obvious reasons.
2) using locally declared variables.
var ClassA = ns.ClassA, ClassB = ns.ClassB;
and then, I will be able to instantiate ClassA and ClassB directly. However, this approach would require me to manually maintain the declaration, and it will just get very messy and hard to maintain as the number of classes increase in the package.
3) pollute the global scope by injection
use a for loop to iterate over ns and map all the classes inside nsto global scope. This is clearly undesirable, and also it will create conflicts for cases such as ns.Event, ns.Audio etc.
4) PaperScript-style (http://paperjs.org/tutorials/getting-started/working-with-paper-js/)
Inspired by PaperScript from PaperJS, where PaperScript code is automatically executed in its own scope that without polluting with the global scope still has access to all the global browser objects and functions, such as document or window. Looking at their source code on GitHub (sorry SO won't let me post any more links), they seem to be using some custom script pre-processing and then Acorn.js to parse. The end result is that one can directly refer to any class inside the paper object. For example, var path = new Path() instead of var path = new paper.Path(), which is exactly what I wanted to achieve. However, my fear is that it might seem to be too much work to implement such a simple feature. So I wanted to see if any one has any ideas?
Thank you for taking your time to read this verbose description of the problem. Any inputs are appreciated.
Note: I have done my best in the past two days into researching this topic, please forgive me if I missed any obvious solutions. In addition, if there's no easy solution to this, I will simply stick with the ns.ClassA pattern. Thank you for your help!
I'm not an expert but I believe you could create a prototype of String and set your vars like so
String.prototype.ns = function(){
return new ns[this]();
}
var ca = "ClassA".ns();
I want to be able to define a statement in javascript. For example, I want to define
a statement called file that works like a class.
function file() {
//code goes here
}
I want that to be used as a statement, like if,for,andreturn.
file filename(filename,purpose) {
//code goes here
}
Do I need to build a seperate compiler or is it possible?
Please change the title if there is a better way to say it.
What are you trying to accomplish?
You can emulate some class-like structure in JavaScript using the Revealing Module Pattern
Also, I've never seen a class work like what you've described -- typically you instantiate an object of a class, and then access the object's public properties. This can be done in JavaScript ('cept objects are created dynamically). For example:
// file 'class'
var file = function () {
var a; // private variable
function filename(name, purpose) {
// code goes here
}
// return public members
return {
filename: filename
};
};
// An object created from your 'class' with the member function 'filename()'
var aFile = file();
Then call your member function using the . operator, like so: aFile.filename(name, purpose);
This would be writing a new language based on Javascript, much like Coffeescript, among many others. Those languages need to compile to JS before being served to a web browser, for instance.
Take a look at a Coffeescript -> JS interpreter to know how to go about this. For the record, I don't think this is a good approach.
Lastly I'll note that languages like Scala have very good DSL support, meaning it's easy to add features within the language. For instance, even + in Scala is library code, not native code. (More technically, could be written that way from a language standpoint.)
I want to be able to define a statement in javascript.
I want that to be used as a statement, like if,for,andreturn.
No, you cannot do this, as a Javascript parser would not be able to parse this.
If you really wish to do this, your only option would be to create your own language, and write a transpiler from your new language to Javascript, as #djechlin has pointed out.
I believe what you want is to implement control structures rather than statements since the example you gave, if, for and return are control structures. If that is what you really mean then yes, you can do that with functions but not with the syntax you describe.
In javascript, functions are first class objects. That is, they can be assigned to variables and passed as arguments to other functions. For example, here's an implementation of if that uses no built-in control structure (no if, while, switch etc. and no ternary operator):
function IF (condition, callback) {
[function(){}, callback][+!!condition]();
}
You can use the above function as a replacement of if but the syntax is a bit unconventional:
IF ( a == b, function(){
console.log('hello');
});
But if you've been programming javascript long enough the above syntax would be familiar and you'd have encountered many similar control structures implemented as functions such as [].forEach() and setTimeout().
So, if you want to implement a control structure to parse a file for example, you can do something like this:
function parseFile (filename, callback) {
// code to process filename
callback(result);
}
Or even something like this:
function eachLine (filename, callback) {
// code to process filename
for (var i=0; i<file_content.length; i++) {
callback(file_content[i]);
}
}
which you can use like this:
eachLine("some_file.txt",function(line){
if (line.match(/hello/)) {
console.log('Found hello! This file is friendly.');
}
});
if you don't need parameters you can do:
Object.defineProperty(window, 'newcmd', {
get: () => console.log("hello")
})
newcmd
Does anyone know if structuring javascript will be changed? What I mean is to have a way to manage javascript classes into packages, like in Java. Is there already a way?
I guess you are familiar with the Java concept of naming packages after a domain you own, this way avoiding collision with the packages of other vendors. You can simulate Java packages (and avoid possible naemspace collisions) with:
if (typeof(org) == "undefined")
org = {};
if (typeof(org.mydomain) == "undefined")
org.mydomain = {};
if (typeof(org.mydomain.mypackage) == "undefined")
org.mydomain.mypackage = {};
org.mydomain.mypackage.MyClass = function (newA) {
// constructor
this.a = newA;
}
org.mydomain.mypackage.MyClass.staticMethod = function () {
// static method
return "static";
}
org.mydomain.mypackage.MyClass.prototype.method = function () {
// normal method
return a;
}
var o = new org.mydomain.mypackage.MyClass(13);
console.log(o.method());
console.log(org.mydomain.mypackage.MyClass.staticMethod());
You can even simulate Java's import if you are working in a limited scope. (Doing this in the global scope would eliminate the whole point of packaging):
function afunc() {
var MyClass = org.mydomain.mypackage.MyClass;
var o = new MyClass(33);
console.log(o.method());
console.log(MyClass.staticMethod());
}
The weakest link here is the root of our namespace, org (or com or any top level domain). An other class may use it for some other reasons. Using org_mydomain as the root instead of org.mydomain may give some safety.
Edit:
You have other possibilities for the root name too if you want to avoid using TLD as the root. If your domain name is unique enough (for example a hip misspelled one like foogz.com) you can assume that there will be no other company writing reusable JavaScript classes who will go for foogz.org or foogz.biz, so probably you will be the only foogz out there. :)
An other possibility is to append your TLD to the domain name and use that for the first tag for example: mydomainorg.packagename.ClassName.
There are no JavaScript classes. There are only Objects. You can pack a bunch of objects into a different object, and treat it like a module/namespace if you wish. (example at the end.)
Because of that, there can't be any "improvements" in the field of JavaScript classes because there aren't any, and I hope there won't ever be either. And frankly, that's for the best. Would you rather deal with insane getters/setters, static members, protected, type coercion and so on etc? Prototypal inheritance beats "Classical inheritance" by miles. It's just that JavaScript didn't have too much time to get it just right.
For amazing explanations on how JavaScript objects work, I recommend Douglas Crockfords' "On JavaScript", or some answers from our very own members.
An example of "namespacing":
var obj = {
classRoom : {...},
objectify : function() {...},
capacity : 5
};
var myClass = obj.classRoom; //access it like you access a module
var capacity = 7; //this is a global variable named capacity, so it won't tamper with obj.capacity
Check out http://joose.it, it has a great module system (library, not language extension). The 4th edition of the ECMA-262 spec has packages, and it's implemented in actionscript.
There is some speculation (e.g. by John Resig) about new features like object freezing and packages that might be added to ECMAScript Harmony (a.k.a 6th Edition).
However, I personally doubt that the language committee would consider such a drastic change to the way the language handles some of its core OO principles.
JavaScript is dynamic code in a file. All you do is load some source code and run it dynamically.
Every structuring and managing system is dynamically written and done at runtime. There are lots of ways you can manage and structure javascript code.
requirejs check define
yui check YUI.add
dojo check dojo.provide
and more
Personally I recommend requireJS as it's not tied into any framework / other libraries.