Dart, Google's new web language, says it supports outputting to JavaScript.
What does a simple conversion look like?
main() {
print('Hello, Dart!');
}
When compiled with dart2js (as of 2013-04-26) (see note at bottom) it is converted into:
// Generated by dart2js, the Dart to JavaScript compiler.
// The code supports the following hooks:
// dartPrint(message) - if this function is defined it is called
// instead of the Dart [print] method.
// dartMainRunner(main) - if this function is defined, the Dart [main]
// method will not be invoked directly.
// Instead, a closure that will invoke [main] is
// passed to [dartMainRunner].
function Isolate() {}
init();
var $ = Isolate.$isolateProperties;
// Bound closures
$.Primitives_printString = function(string) {
if (typeof dartPrint == "function") {
dartPrint(string);
return;
}
if (typeof window == "object") {
if (typeof console == "object")
console.log(string);
return;
}
if (typeof print == "function") {
print(string);
return;
}
throw "Unable to print message: " + String(string);
};
$.main = function() {
$.Primitives_printString("Hello, Dart!");
};
$.String = {builtin$cls: "String"};
var $ = null;
Isolate = Isolate.$finishIsolateConstructor(Isolate);
var $ = new Isolate();
// BEGIN invoke [main].
if (typeof document !== "undefined" && document.readyState !== "complete") {
document.addEventListener("readystatechange", function () {
if (document.readyState == "complete") {
if (typeof dartMainRunner === "function") {
dartMainRunner(function() { $.main(); });
} else {
$.main();
}
}
}, false);
} else {
if (typeof dartMainRunner === "function") {
dartMainRunner(function() { $.main(); });
} else {
$.main();
}
}
// END invoke [main].
function init() {
Isolate.$isolateProperties = {};
Isolate.$finishIsolateConstructor = function(oldIsolate) {
var isolateProperties = oldIsolate.$isolateProperties;
isolateProperties.$currentScript = typeof document == "object" ? document.currentScript || document.scripts[document.scripts.length - 1] : null;
var isolatePrototype = oldIsolate.prototype;
var str = "{\n";
str += "var properties = Isolate.$isolateProperties;\n";
var hasOwnProperty = Object.prototype.hasOwnProperty;
for (var staticName in isolateProperties) {
if (hasOwnProperty.call(isolateProperties, staticName)) {
str += "this." + staticName + "= properties." + staticName + ";\n";
}
}
str += "}\n";
var newIsolate = new Function(str);
newIsolate.prototype = isolatePrototype;
isolatePrototype.constructor = newIsolate;
newIsolate.$isolateProperties = isolateProperties;
return newIsolate;
};
}
//# sourceMappingURL=out.js.map
Note for posterity: The original answer to this question has been modified to reflect the current state of affairs.
On 2012-05-12 the dart output for Hello World was 18,718 characters.
On 2012-08-29 the output was 1531 characters.
On 2013-04-26, the output was 2642 characters.
dart2js can minify code. Here is an example (as of 2013-04-26)
// Generated by dart2js, the Dart to JavaScript compiler.
function I(){}
init()
var $=I.p
$.ib=function(a){if(typeof dartPrint=="function"){dartPrint(a)
return}if(typeof window=="object"){if(typeof console=="object")console.log(a)
return}if(typeof print=="function"){print(a)
return}throw "Unable to print message: " + String(a)}
$.E2=function(){$.ib("Hello, Dart!")}
$.qU={builtin$cls:"qU"}
var $=null
I = I.$finishIsolateConstructor(I)
var $=new I()
if (typeof document !== "undefined" && document.readyState !== "complete") {
document.addEventListener("readystatechange", function () {
if (document.readyState == "complete") {
if (typeof dartMainRunner === "function") {
dartMainRunner(function() { $.E2(); });
} else {
$.E2();
}
}
}, false);
} else {
if (typeof dartMainRunner === "function") {
dartMainRunner(function() { $.E2(); });
} else {
$.E2();
}
}
function init(){I.p={}
I.$finishIsolateConstructor=function(a){var z=a.p
z.$currentScript=typeof document=="object"?document.currentScript||document.scripts[document.scripts.length-1]:null
var y=a.prototype
var x="{\n"
x+="var properties = I.p;\n"
var w=Object.prototype.hasOwnProperty
for(var v in z){if(w.call(z,v)){x+="this."+v+"= properties."+v+";\n"}}x+="}\n"
var u=new Function(x)
u.prototype=y
y.constructor=u
u.p=z
return u}}//# sourceMappingURL=out.js.map
On 2013-04-26, the minified code was 1386 characters.
The output of the Dart->JavaScript compiler is a moving target. The first release (technical preview) didn't do a lot of tree shaking and was thus pretty big.
The new (experimental) frog compiler is much better in this respect (David Chandler's blog), but I expect DartC to improve considerably too.
Related
If you create a multidimensional-array:
var ThisArray = [];
ThisArray["a"] = [];
ThisArray["a"]["b"] = [];
ThisArray["a"]["b"]["c"] = "This is a string.";
How can you check if ThisArray["a"]["w"]["c"] for example is defined. Right now I'm doing this:
if (typeof ThisArray !== 'undefined') {
if (typeof ThisArray["a"] !== 'undefined') {
if (typeof ThisArray["a"]["w"] !== 'undefined') {
if (typeof ThisArray["a"]["w"]["c"] !== 'undefined') {
// ThisArray["a"]["w"]["c"] is defined!
}
}
}
}
How can I do this better and cleaner?
Use optional chaining:
if (typeof ThisArray?.["a"]?.["w"]?.["c"] !== 'undefined') {
// ThisArray["a"]["w"]["c"] is defined!
}
As noted in the comments, this is a relatively new language feature, and is not supported by older browsers. See Browser Compatibility.
You can use optional chaining.
the optional chaining operator enables simple way to access values through connected objects when it's possible that a reference or function may be undefined or null, hence, protecting you from getting null exception on null/undefined objects.
var ThisArray = [];
ThisArray["a"] = [];
ThisArray["a"]["b"] = [];
ThisArray["a"]["b"]["c"] = "This is a string.";
console.log(ThisArray.a.b.c?.d?.e);
This is a perfect place to use optional chaining!
You can do so like this:
if (typeof ThisArray.a?.b?.c !== 'undefined') {
console.log(`ThisArray["a"]["b"]["c"] is defined!`);
}
Here's a full demo:
var ThisArray = [];
ThisArray["a"] = [];
ThisArray["a"]["b"] = [];
ThisArray["a"]["b"]["c"] = "This is a string.";
if (typeof ThisArray.a?.b?.c !== 'undefined') {
console.log(`ThisArray["a"]["b"]["c"] is defined!`);
console.log(`ThisArray.a.w.c === "${ThisArray.a.b.c}"`)
} else {
console.log(`ThisArray["a"]["b"]["c"] is NOT defined!`);
}
go with try catch
var thirdDimensionValue = null;
try{
thirdDimensionValue = ThisArray["a"]["b"]["c"]
}
catch{
thirdDimensionValue = null
}
if(thirdDimensionValue){
console.log("value exist")
}
else{
console.log("No value exist in the property")
}
I currently have this code built in JS, but it's really, really ugly.
Is there any better way to approach it?
The way it works basically is pushing a string like app.chat.test to be the key, and value like teststr.
I test the lengths to see if the "parent" key is there, otherwise we build it.
function constructJson(jsonKey, jsonValue){
//REWRITE!!!!!!!!
let jsonObj = langFile;
let jsonKeyArr = jsonKey.split('.')
if (jsonKeyArr.length === 1) {
if (valToAdd === undefined) {
if (jsonObj[jsonKey] === undefined) {
jsonObj[jsonKey] = {}
}
} else {
if (jsonObj[jsonKey] === undefined) {
jsonObj[jsonKey] = valToAdd
}
}
} else if (jsonKeyArr.length === 2) {
if (jsonObj[jsonKeyArr[0]] === undefined) {
jsonObj[jsonKeyArr[0]] = {}
}
if (jsonObj[jsonKeyArr[0]][jsonKeyArr[1]] === undefined) {
jsonObj[jsonKeyArr[0]][jsonKeyArr[1]] = jsonValue
}
} else if (jsonKeyArr.length === 3) {
if (jsonObj[jsonKeyArr[0]] === undefined) {
jsonObj[jsonKeyArr[0]] = {}
}
if (jsonObj[jsonKeyArr[0]][jsonKeyArr[1]] === undefined) {
jsonObj[jsonKeyArr[0]][jsonKeyArr[1]] = {}
}
if (jsonObj[jsonKeyArr[0]][jsonKeyArr[1]][jsonKeyArr[2]] === undefined) {
jsonObj[jsonKeyArr[0]][jsonKeyArr[1]][jsonKeyArr[2]] = jsonValue
}
} else if (jsonKeyArr.length === 4) {
if (jsonObj[jsonKeyArr[0]] === undefined) {
jsonObj[jsonKeyArr[0]] = {}
}
if (jsonObj[jsonKeyArr[0]][jsonKeyArr[1]] === undefined) {
jsonObj[jsonKeyArr[0]][jsonKeyArr[1]] = {}
}
if (jsonObj[jsonKeyArr[0]][jsonKeyArr[1]][jsonKeyArr[2]] === undefined) {
jsonObj[jsonKeyArr[0]][jsonKeyArr[1]][jsonKeyArr[2]] = {}
}
if (jsonObj[jsonKeyArr[0]][jsonKeyArr[1]][jsonKeyArr[2]][jsonKeyArr[3]] === undefined) {
jsonObj[jsonKeyArr[0]][jsonKeyArr[1]][jsonKeyArr[2]][jsonKeyArr[3]] = jsonValue
}
} else if (jsonKeyArr.length === 5) {
if (jsonObj[jsonKeyArr[0]] === undefined) {
jsonObj[jsonKeyArr[0]] = {}
}
if (jsonObj[jsonKeyArr[0]][jsonKeyArr[1]] === undefined) {
jsonObj[jsonKeyArr[0]][jsonKeyArr[1]] = {}
}
if (jsonObj[jsonKeyArr[0]][jsonKeyArr[1]][jsonKeyArr[2]] === undefined) {
jsonObj[jsonKeyArr[0]][jsonKeyArr[1]][jsonKeyArr[2]] = {}
}
if (jsonObj[jsonKeyArr[0]][jsonKeyArr[1]][jsonKeyArr[2]][jsonKeyArr[3]] === undefined) {
jsonObj[jsonKeyArr[0]][jsonKeyArr[1]][jsonKeyArr[2]][jsonKeyArr[3]] = {}
}
if (jsonObj[jsonKeyArr[0]][jsonKeyArr[1]][jsonKeyArr[2]][jsonKeyArr[3]][jsonKeyArr[4]] === undefined) {
jsonObj[jsonKeyArr[0]][jsonKeyArr[1]][jsonKeyArr[2]][jsonKeyArr[3]][jsonKeyArr[4]] = jsonValue
}
} else if (jsonKeyArr.length > 5) {
return console.log("Length over 5 not supported yet!")
}
return jsonObj;
}
Regards.
OF course it's possible, a simple loop will perfeclty do the job.
function constructJson(jsonKey, jsonValue){
//REWRITE!!!!!!!!
langFile = {a:{}, foo:{}};// remove this for your own code
var jsonObj = langFile;
var jsonKeyArr = jsonKey.split('.');
var currentValue = jsonObj;
for(var i = 0; i < jsonKeyArr.length;i++){
if(currentValue[jsonKeyArr[i]]===undefined){
currentValue[jsonKeyArr[i]] = {};
}
if(i < jsonKeyArr.length-1){
currentValue = currentValue[jsonKeyArr[i]];
}else{
currentValue[jsonKeyArr[i]] = jsonValue;
}
}
return jsonObj;
}
alert(JSON.stringify(constructJson("a.b.cd.ef", "toto")));
I just assigning to a temporary variable each sublevel. When i'm on the last i'm assigning the value.
Yes you can, using the javascript reduce function on the array created from the splitted string.
function namespaceCreateExceptLast(representationOfElementToCreate, baseNamespace) {
var tokens;
if (typeof representationOfElementToCreate !== 'string')
throw new Error('Expecting string as first parameter');
if (baseNamespace === undefined)
baseNamespace = window;
tokens = representationOfElementToCreate.split('.');
// Remove the last element (which will contain the value)
tokens.pop();
// Use reduce to create part by part your new object
return tokens.reduce(function (prev, property) {
if (typeof prev !== 'object') {
throw Error('One property is already defined but not an object, namespace creation has failed', property);
return undefined;
} else {
if (!prev[property])
prev[property] = {};
return prev[property];
}
}, baseNamespace);
};
Then you can have:
function constructJson(jsonKey, jsonValue){
let jsonObj = langFile;
var lastItem = namespaceCreateExceptLast(jsonKey, jsonObj);
var lastKey = jsonKey.substring(jsonKey.lastIndexOf('.') + 1);
lastItem[lastKey] = jsonValue;
}
I have added some comments and exceptions to help you understand how it's done, but it's mainly based on the reduce function which you can easily get help for (https://developer.mozilla.org/fr/docs/Web/JavaScript/Reference/Objets_globaux/Array/reduce).
tem.jqw.Callback object contains an executable function, a CSS selector. and a looping delay.
tem.jqw.wait waits for jQuery to be loaded and then goes through an array of tem.jqw.Callback objects and executes their functions after having found an element with the CSS selector passed in.
The problem I am having is in the run function within the tem.jqw.Callback object. When the run function is called the first time, if the element exists, everything is fine and the executable function runs OK. However, if the element does not yet exist, and we need to loop, the function loses scope after setTimeout(this.run, 100) executes once. For example, when the run function is executing the second time, this.selector or this.fn become undefined. How can I work around this without using global variables? Thanks in advance.
if (typeof tem !== "object") {
tem = {};
}
tem.jqw = {};
tem.jqw.retries = 0;
tem.jqw.maxRetries = 100;
tem.jqw.delay = 100;
tem.jqw.callbacks = [];
tem.jqw.Callback = function (fn, selector, delay) {
this.fn = fn;
this.selector = (typeof selector === "string" && selector.length > 0) ? selector : document;
this.delay = (typeof delay === "number" && delay > 0 && delay < 1000) ? delay : 100;
this.retries = 0;
this.maxRetries = 100;
this.start = function () {
this.run();
};
this.run = function () {
if (jQuery(this.selector).length > 0) {
console.log("[OPDEBUG] tem.jqw.Callback.run says: " + this.selector.toString() + " is ready. Executing callback function...");
this.fn();
} else {
this.retries++;
console.log("[OPDEBUG] tem.jqw.Callback.run says: typeof this.selector " + typeof this.selector);
console.log("[OPDEBUG] tem.jqw.Callback.run says: Waiting for " + this.selector.toString() + "...");
if (this.retries < this.maxRetries) {
setTimeout(this.run, 100);
}
}
};
};
tem.jqw.wait = function () {
if (typeof jQuery === "function") {
console.log("[OPDEBUG] tem.jqw.wait says: jQuery is ready.");
for (var i = 0; i < tem.jqw.callbacks.length; i++) {
if (typeof tem.jqw.callbacks[i] === "object" && typeof tem.jqw.callbacks[i].start === "function") {
console.log("[OPDEBUG] tem.jqw.wait says: Executing callback function " + (i + 1) + "...");
tem.jqw.callbacks[i].start();
}
}
} else {
tem.jqw.retries++;
console.log("[OPDEBUG] tem.jqw.wait says: " + "Waiting for jQuery " + tem.jqw.retries + "...");
if (tem.jqw.retries < tem.jqw.maxRetries) {
setTimeout(tem.jqw.wait, tem.jqw.delay);
}
}
};
tem.jqw.callbacks.push(new tem.jqw.Callback(function () {
jQuery('.hero-inner:first a').css('background-image', 'url("https://www.thedogs.co.nz/Files/PhotoFinishImages/11298_89160.jpg")')
}, ".hero-inner:first"));
tem.jqw.callbacks.push(new tem.jqw.Callback(function () {
jQuery('.RR-placeholder ul li:first').hide();
}, ".RR-placeholder ul li:first"));
tem.jqw.wait();
you can use bind to set this
change this.run() to
this.run.bind(this)
Its better to assign this to another variable eg)
var self = this;
and then pass around self for better readability
Hi I'm looking to add javascript functions to game maker, but the format of them is like this:
companyname.initialize({
soundMuteCallback: muteSound, // optional
soundUnmuteCallback: unmuteSound // optional
});
And in the file they look like this
this.initialize = function(params) {
companyname.getSharedEventCenter().postEvent(SharedEventKeys.API_INITIALIZE);
_isInitialized = true;
if (typeof params !== "undefined") {
var muteSoundCallback = ("soundMuteCallback" in params && typeof params["soundMuteCallback"] === "function") ? params["soundMuteCallback"] : undefined;
var unmuteSoundCallback = ("soundUnmuteCallback" in params && typeof params["soundUnmuteCallback"] === "function") ? params["soundUnmuteCallback"] : undefined;
_adsManager.setSoundCallbacks(function() {
typeof muteSoundCallback === "function" && muteSoundCallback();
[].forEach.call(document.getElementsByTagName("audio"), function(element){
element.muted = true;
});
}, function() {
typeof unmuteSoundCallback === "function" && unmuteSoundCallback();
[].forEach.call(document.getElementsByTagName("audio"), function(element){
element.muted = false;
});
});
}
_tryShowAd();
};
Does anyone have any idea how to do this in game maker? I don't know what information to put in the extension function properties.
Thanks,
Mitchell.
I would recommend creating a new function that Game Maker can understand and then use that to create your object and the constructor you are showing here.
company.initialize = function(params) {
companyname.getSharedEventCenter().postEvent(SharedEventKeys.API_INITIALIZE);
_isInitialized = true;
if (typeof params !== "undefined") {
var muteSoundCallback = ("soundMuteCallback" in params && typeof params["soundMuteCallback"] === "function") ? params["soundMuteCallback"] : undefined;
var unmuteSoundCallback = ("soundUnmuteCallback" in params && typeof params["soundUnmuteCallback"] === "function") ? params["soundUnmuteCallback"] : undefined;
_adsManager.setSoundCallbacks(function() {
typeof muteSoundCallback === "function" && muteSoundCallback();
[].forEach.call(document.getElementsByTagName("audio"), function(element){
element.muted = true;
});
}, function() {
typeof unmuteSoundCallback === "function" && unmuteSoundCallback();
[].forEach.call(document.getElementsByTagName("audio"), function(element){
element.muted = false;
});
});
}
_tryShowAd();
};
function createMuteCallback() {
muteCallback = function () {
// Code to handle the callback
}
return muteCallback;
}
function createUnmuteCallback() {
unmuteCallback = function () {
// Code to handle the callback
}
return unmuteCallback;
}
function createCompany (mute, unmute) {
if (mute == 1) {
soundMuteCallback.createMuteCallback();
}
if (unmute == 1) {
soundUnmuteCallback.createUnmuteCallback();
}
company.initialize(soundMuteCallback, soundUnmuteCallback);
}
So all of that goes in the same .js file. Create a new extension in Game Maker. Add the .js file to that extension. Add a function named createCompany with two optional parameters.
Then when you call createCompany(1, 1); in your Game Maker code, the .js file will run and will initialize the company object with the two callback functions.
Hope this helps.
I'm using all of the latest dependencies for emberjs and yet I end up with an error on initializing the scripts in the page at ember-data-latest.min.js with:
Uncaught TypeError: Object function () {...} has no method 'registerInjection'
Before even writing a single line for my app. Why is that?
Appreciate any kind help.
Here's my script list:
jquery-1.10.2.min.js
handlebars-v1.3.0.js
ember-1.5.1.js
ember-states.js
ember-data-latest.min.js
And here's the full error:
Uncaught TypeError: Object function () {
if (!wasApplied) {
Class.proto(); // prepare prototype...
}
o_defineProperty(this, GUID_KEY, nullDescriptor);
o_defineProperty(this, '__nextSuper', undefinedDescriptor);
var m = meta(this), proto = m.proto;
m.proto = this;
if (initMixins) {
// capture locally so we can clear the closed over variable
var mixins = initMixins;
initMixins = null;
this.reopen.apply(this, mixins);
}
if (initProperties) {
// capture locally so we can clear the closed over variable
var props = initProperties;
initProperties = null;
var concatenatedProperties = this.concatenatedProperties;
for (var i = 0, l = props.length; i < l; i++) {
var properties = props[i];
Ember.assert("Ember.Object.create no longer supports mixing in other definitions, use createWithMixins instead.", !(properties instanceof Ember.Mixin));
if (typeof properties !== 'object' && properties !== undefined) {
throw new Ember.Error("Ember.Object.create only accepts objects.");
}
if (!properties) { continue; }
var keyNames = Ember.keys(properties);
for (var j = 0, ll = keyNames.length; j < ll; j++) {
var keyName = keyNames[j];
if (!properties.hasOwnProperty(keyName)) { continue; }
var value = properties[keyName],
IS_BINDING = Ember.IS_BINDING;
if (IS_BINDING.test(keyName)) {
var bindings = m.bindings;
if (!bindings) {
bindings = m.bindings = {};
} else if (!m.hasOwnProperty('bindings')) {
bindings = m.bindings = o_create(m.bindings);
}
bindings[keyName] = value;
}
var desc = m.descs[keyName];
Ember.assert("Ember.Object.create no longer supports defining computed properties. Define computed properties using extend() or reopen() before calling create().", !(value instanceof Ember.ComputedProperty));
Ember.assert("Ember.Object.create no longer supports defining methods that call _super.", !(typeof value === 'function' && value.toString().indexOf('._super') !== -1));
Ember.assert("`actions` must be provided at extend time, not at create " +
"time, when Ember.ActionHandler is used (i.e. views, " +
"controllers & routes).", !((keyName === 'actions') && Ember.ActionHandler.detect(this)));
if (concatenatedProperties && indexOf(concatenatedProperties, keyName) >= 0) {
var baseValue = this[keyName];
if (baseValue) {
if ('function' === typeof baseValue.concat) {
value = baseValue.concat(value);
} else {
value = Ember.makeArray(baseValue).concat(value);
}
} else {
value = Ember.makeArray(value);
}
}
if (desc) {
desc.set(this, keyName, value);
} else {
if (typeof this.setUnknownProperty === 'function' && !(keyName in this)) {
this.setUnknownProperty(keyName, value);
} else if (MANDATORY_SETTER) {
Ember.defineProperty(this, keyName, null, value); // setup mandatory setter
} else {
this[keyName] = value;
}
}
}
}
}
finishPartial(this, m);
this.init.apply(this, arguments);
m.proto = proto;
finishChains(this);
sendEvent(this, "init");
} has no method 'registerInjection'
You need to make sure to use the latest version which gets published at Ember build site.
The latest build for Ember Data is found here.