JavaScript Scoping Idiosyncrancies - scoping

I'm new to JS (I'm more familiar with Java), so the scoping has been rather confusing for me. I was given the following code snippet, and I'm hoping someone can walk me through why the console.log() function calls are returning the values they're returning:
var x = 0;
function a (){
var x = 1;
function b(){
console.log(x); //---> this will be undefined
var x = 2;
console.log(x); //---> this will be 2
}
b();
}
console.log(x);//---> this will be 0;
a();

Related

Reference Error const is not defined. I can't understand why

I have a simple script like this
function importazione() {
const ss = SpreadsheetApp.getActiveSpreadsheet();
const wsd = ss.getSheetByName("morosi");
wsd.getRange(2,1,1000,10).clearContent();
SpreadsheetApp.flush();
const ws = ss.getSheetByName("importa");
const max_riga = ws.getLastRow();
var dati = ws.getRange(2, 1, max_riga-1, 6).getValues();
dati.forEach(r => {
scriviElenco({
corso: r[0],
ciclo: r[1],
studente: r[2],
status: r[4],
id_matr: r[5]
});
});
}
function scriviElenco(passa) {
if (passa.status === "NO PAGÓ") {
var daSplittare = passa.corso+"|"+passa.studente+"|"+passa.id_matr;
var riga = [];
riga = daSplittare.split("|");
wsd.appendRow(riga);
};
}
it returns this error on the last line:
ReferenceError: wsd is not defined
I don't understand why wsd constant is not defined, I have much more complex scripts in which I use the same definitions and it works.
Could someone help me to understand please?
I don't understand why wsd constant is not defined
wsd is not in scope within your second function, scriviElenco(); it is only in scope within importazione() - since Javascript const definitions have block scope. And this actually makes sense, because wsd is only set when you execute importazione(), and you can't expect it to have a valid value in the second function. So, you'll probably have to write something like:
function scriviElenco(passa) {
const ss = SpreadsheetApp.getActiveSpreadsheet();
const wsd = ss.getSheetByName("morosi");
// your existing implementation
}
and perhaps even a one-liner helper function such as:
function getSheet(sheetName) {
return SpreadsheetApp.getActiveSpreadsheet().getSheetByName(sheetName);
}
which you assign to a constant at the beginning of each of the two functions.

Javascript and Callback function

I’m a newbie in programming language and I’m learning Javascript. I’m trying to understand the concept of callback function. I realized that callback is intended a function passed as parameter, but when does it call?
In the below examples I used a classic approach to write functions and then I tried to use the arrow function. The callback is done() function, in the first example it is called after the parent function, in the second one after.
What is the reason? Can you give me an explanation? Thank you so much for the feedback
Example no. 1
function done(){
console.log("Done");
}
function increment(num, callBack){
for(var i = 0; i <= num; i++){
console.log(i);
}
return callBack();
}
increment(10, done);
Example no. 2
const done = () => {
console.log("Done");
}
const increment = (num, done) => {
for (var i = 0; i <= num; i++) {
console.log(i);
}
}
increment(10, done());
To use callback you need to specify that there'll be a callback function as a argument, and you need to call that somewhere in the parent function like this, and that's when it will be called:
function someFunction(callback){
//Do something if needed...
callback() //callback(someParameter) if you want to pass some parameter to the callback func
//Do something if needed...
}
In your 2nd example, it's actually not a proper way of using callback function because you did not call the callback function inside parent function. You can modify it to to make it work as 1st example like this:
const increment = (num, done) => {
for (var i = 0; i <= num; i++) {
console.log(i);
}
done(); //call the callback function
}
increment(10, done); //just pass the name of callback func, not call it like you did "done()"

Access non static function from static function

Here is some insight: I am working with UnityScript in Unity 4.6.3. I have one script called Pause.js and it contains this function:
function fadeMusicOut () {
while (audio.volume >= 0.005) {
yield WaitForSeconds(0.1);
Debug.Log("Loop Entered: " + audio.volume);
audio.volume = (audio.volume - 0.015);
}
Another script GameManager.js has this function:
static function Score (wallName : String) {
if (wallName == "rightWall") {
playerScore01 += 1;
}
else {
playerScore02 += 1;
}
if (playerScore01 == SettingsBack.scoreLimit || playerScore02 == SettingsBack.scoreLimit)
{
startParticles = 1;
SettingsBack.gameOver = 1;
BallControl.fadeSound = 1;
yield WaitForSeconds(4);
Camera.main.SendMessage("fadeOut");
Pause.fadeMusic = 1;
SettingsBack.soundVolume = 0;
yield WaitForSeconds(2);
playerScore01 = 0;
playerScore02 = 0;
SettingsBack.soundVolume = oldSoundVol;
Application.LoadLevel("_Menu");
}
}
So pretty much I want to call the fadeMusicOut() function from static function Score, but it will not let me because it says it needs an instance of that object.
The Pause.js script is not attached to any game objects, but it is attached to 2 buttons that call their specific functions. The GameManager.js script is attached to an object called GM. So how can I go about calling fadeMusicOut() from the Score function?
I have tried setting new vars that import the game object but still no luck. I tried making fadeMusicOut() a static function, but it creates many errors.
Any help at all is appreciated.

easeljs cannot dispatch event

I want to dispatch my event,but it doesn't work. this is my code and I've deleted some irrelevant parts .
(function(window){
function HeroSelectView(){
this.initialize();
}
createjs.EventDispatcher.initialize(HeroSelectView.prototype);
HeroSelectView.prototype = new createjs.Container();
var selectedName;
HeroSelectView.prototype.Container_initialize=HeroSelectView.prototype.initialize;
HeroSelectView.prototype.initialize=function(){
this.Container_initialize();
this.initView();
}
HeroSelectView.prototype.initView = function(){
for (var i = 0; i < heroArray.length; i++) {
heroArray[i].x=100+40*i;
heroArray[i].y=200;
this.addChild(heroArray[i]);
heroArray[i].addEventListener("click",onSelectHero);
};
}
function onSelectHero(event){
selectedName=event.target.name;
var myevent = {
type: "selectedEvent",
param: selectedName
};
//var myevent=new createjs.Event("selectedEvent"); //createjs 0.7 doesnot work either.
this.dispatchEvent(myevent);
}
window.HeroSelectView=HeroSelectView;
}(window))
in the onSelectedHero, at first I tried it with createjs-0.61. you can see the "myevent" .But there is an error " TypeError: Argument 1 of EventTarget.dispatchEvent is not an object.". Then I tried it with version 0.7, but still got the same error. How can I fix this?
Thanks

How can i force website to stay in frame?

I'm using Firefox + searchbastard addon to do a multi-search on shopping search engines.The pages are part of a frame. This works just fine for all sites I tried so far except for shopmania.com.
If I use noscript to forbid scripts from the shopmania domain name then everything stays in place but the part of the website elements become nonresponsive. I know there is an option in Firefox to force links that open in a new window to open in a new tab. Is there something similar to prevent websites from popping out of frame? Maybe a Firefox addon that blocks these requests?
Or at least can someone please tell me what is causing only this website to act like this?
EDIT: What tool can i use to pause firefox OR javascript and stepthrough code like in c++ ? I tried a javascript debugger and firebug. They don't help but i'm probably not using them right..
EDIT2: I tried this greasemonkey script : https://userscripts.org/scripts/show/92424. It does not work so i guess it isn't because of 'target' attribute
This is wrong. I'm guessing you're using a plugin to capture and override the output some site gives you. I'm pretty sure this violates their ToS and it's not a very nice thing to do in general.
JavaScript is not designed to allow this kind of meddling. It's patchy at best.
If you want to use the data from a website, to aggregate or display in some manner, use their public API. If they don't have a public API they probably don't want you to use their service in such a manner.
The solution : I took the script from Stop execution of Javascript function (client side) or tweak it and modified it to search for the tag that has in it top.location = location and then appended a new script with the if (top != self) {top.location = location;} line commented . Being a js total newbie i don't know if it's the most elegant choice but it soves the prob. Special thanks to Tim Fountain.
I will leave this open just in case someone else will suggest a better solution, for my and others's education. Again thanks for the help.
Below is the code:
// ==UserScript==
// #name _Replace evil Javascript
// #run-at document-start
// ==/UserScript==
/****** New "init" function that we will use
instead of the old, bad "init" function.
*/
function init () {
/* //changing stuff around here
var newParagraph = document.createElement ('p');
newParagraph.textContent = "I was added by the new, good init() function!";
document.body.appendChild (newParagraph); */
<!--//--><![CDATA[//><!--
document.getElementsByTagName("html")[0].className+=" js "+(navigator.userAgent.toLowerCase().indexOf("webkit")>=0?"webkit":navigator.userAgent.toLowerCase().indexOf("opera")>=0?"opera":"");
for(i in css3_tags="abbr|header|footer".split("|")){document.createElement(css3_tags[i]);}
var PATH = "http://www.shopmania.com";
var PATH_STATIC = "http://im4.shopmania.org";
var PATH_SELF = "http://www.shopmania.com/";
var RETURN = "http%3A%2F%2Fwww.shopmania.com%2F";
var DOMAIN_BASE = "shopmania.com";
var SUBDOMAINS_FORCE_FILES_JS = "aff.remote,biz.remote,my.remote,cp.remote,cp.register_quick,cp.account_details,partner.remote,site.recommend,site.remote,site.feedback,site.report_problem,site.report,site.cropper";
var URL_REWRITE_MAPPING_JS = "cmd,section,do,option|feed,mode,option|forgot,section|info,page|login,section|logout,section|new_password,section,code|settings,section|shopping,param_main,param_sec|site,store_str_key|register,section|unsubscribe,section|agentie,store_str_key,id|brand,manuf_str_key|brands,letter|build,type,param_main,param_sec|compare,online|confirm,section|edit,section|deal,deal|dictionary,online|home,section|link_accounts,section|profile,user|reactivate,section|searches,letter|signup,section|rs_agent,store_str_key|rs_list,param_main,param_sec|rs_view,ad|agents,state|complex_list,param_main|complex_view,complex|list,cat|ad,a|map,option|my_ads,section|my_alerts,section";
var SVR_SITE_ID = "us";
var CONTEXT = "c5b27de70340c97a94092a43bd34b2b8";
var link_close = "Close";
var txt_loading = "Loading...";
var form_is_submitted = 0;
var search_is_focused = 0;
// Overlay object
var OL;
var DB;
var iframe_cnt = "";
// Facebook post to user's Wall action
var FACEBOOK_WALL_FEED_SIGNUP = "";
var SITENAME = "ShopMania";
//if (top != self) {top.location = location;} // SIT!
var comps = new Array(); comps['all'] = 0;var comps_cat_titles = new Array(); var views = new Array(); views['auto'] = 0; views['prod'] = 0; views['realestate'] = 0; views['classifieds'] = 0; views['all'] = 0; var search = new Array(); search['all'] = 0; search['prod'] = 0;
var favs = new Array(); favs['all'] = 0; favs['prod'] = 0; favs['store'] = 0; favs['manuf'] = 0; favs['other'] = 0; favs['realestate'] = 0; favs['auto'] = 0;
function addCss(c){var b=document.getElementsByTagName("head")[0];var a=document.createElement("style");a.setAttribute("type","text/css");if(a.styleSheet){a.styleSheet.cssText=c}else{a.appendChild(document.createTextNode(c))}b.appendChild(a)};
addCss(".lzl {visibility: hidden;}");
var RecaptchaOptions = { theme : 'clean' };
//--><!]]>
}
/*--- Check for bad scripts to intercept and specify any actions to take.
*/
checkForBadJavascripts ( [
[false, /top.location = location/, function () {addJS_Node (init);} ]
] );
function checkForBadJavascripts (controlArray) {
/*--- Note that this is a self-initializing function. The controlArray
parameter is only active for the FIRST call. After that, it is an
event listener.
The control array row is defines like so:
[bSearchSrcAttr, identifyingRegex, callbackFunction]
Where:
bSearchSrcAttr True to search the SRC attribute of a script tag
false to search the TEXT content of a script tag.
identifyingRegex A valid regular expression that should be unique
to that particular script tag.
callbackFunction An optional function to execute when the script is
found. Use null if not needed.
*/
if ( ! controlArray.length) return null;
checkForBadJavascripts = function (zEvent) {
for (var J = controlArray.length - 1; J >= 0; --J) {
var bSearchSrcAttr = controlArray[J][0];
var identifyingRegex = controlArray[J][1];
if (bSearchSrcAttr) {
if (identifyingRegex.test (zEvent.target.src) ) {
stopBadJavascript (J);
return false;
}
}
else {
if (identifyingRegex.test (zEvent.target.textContent) ) {
stopBadJavascript (J);
return false;
}
}
}
function stopBadJavascript (controlIndex) {
zEvent.stopPropagation ();
zEvent.preventDefault ();
var callbackFunction = controlArray[J][2];
if (typeof callbackFunction == "function")
callbackFunction ();
//--- Remove the node just to clear clutter from Firebug inspection.
zEvent.target.parentNode.removeChild (zEvent.target);
//--- Script is intercepted, remove it from the list.
controlArray.splice (J, 1);
if ( ! controlArray.length) {
//--- All done, remove the listener.
window.removeEventListener (
'beforescriptexecute', checkForBadJavascripts, true
);
}
}
}
/*--- Use the "beforescriptexecute" event to monitor scipts as they are loaded.
See https://developer.mozilla.org/en/DOM/element.onbeforescriptexecute
Note that it does not work on acripts that are dynamically created.
*/
window.addEventListener ('beforescriptexecute', checkForBadJavascripts, true);
return checkForBadJavascripts;
}
function addJS_Node (text, s_URL, funcToRun) {
var D = document;
var scriptNode = D.createElement ('script');
scriptNode.type = "text/javascript";
if (text) scriptNode.textContent = text;
if (s_URL) scriptNode.src = s_URL;
if (funcToRun) scriptNode.textContent = '(' + funcToRun.toString() + ')()';
var targ = D.getElementsByTagName ('head')[0] || D.body || D.documentElement;
//--- Don't error check here. if DOM not available, should throw error.
targ.appendChild (scriptNode);
}
there are some escaping issues with the cdata part in the code.So SO does not allow me to post the code.
EDIT: fixed