variable may not have been initialized when test - javascript

I'm trying to understand why I get "variable may not have been initialized" when I test (variable === "some text") but I dont get when I used (typeof passwordHashOrg !== 'undefined')
The working code:
checkPass('share', function (error, response) {
"use strict";
if (error) {
console.log(error);
} else {
console.log(response);
}
});
function checkPass(username, callback) {
"use strict";
// Require
var fs = require('fs');
// Static Parameters
var usernameInput = username;
// Open shadow file
fs.readFile('/etc/shadow', function (error, file) {
if (error) {
return callback(error); // file does not exit
}
// file is a buffer, convert to string and then to array
var shadowArray = file.toString().split('\n');
var passwordHashOrg;
shadowArray.forEach(function (line) {
var shadowLineArray = line.split(":");
var usernameOrg = shadowLineArray[0];
if (usernameOrg === usernameInput) {
passwordHashOrg = shadowLineArray[1];
}
});
if (typeof passwordHashOrg !== 'undefined') {
callback(null, 'userExist');
} else {
callback(null, 'unknownUser');
}
});
}
and the code that I get "variable may not have been initialized" :
checkPass('share', function (error, response) {
"use strict";
if (error) {
console.log(error);
} else {
console.log(response);
}
});
function checkPass(username, callback) {
"use strict";
// Require
var fs = require('fs');
// Static Parameters
var usernameInput = username;
// Open shadow file
fs.readFile('/etc/shadow', function (error, file) {
if (error) {
return callback(error); // file does not exit
}
// file is a buffer, convert to string and then to array
var shadowArray = file.toString().split('\n');
var passwordHashOrg;
shadowArray.forEach(function (line) {
var shadowLineArray = line.split(":");
var usernameOrg = shadowLineArray[0];
if (usernameOrg === usernameInput) {
passwordHashOrg = shadowLineArray[1];
}
});
if (passwordHashOrg === 'some text') {
callback(null, 'userExist');
} else {
callback(null, 'unknownUser');
}
});
}
The only diferent from the two code is:
if (typeof passwordHashOrg !== 'undefined') {
vs
if (passwordHashOrg === "some text") {

The warning means just what it says - the variable might not have been initialised with a value at the time of the comparison. Since that's the expected behaviour, and basically just what you want to test for, the warning can be safely ignored. Alternatively, use
var passwordHashOrg = null; // or
var passwordHashOrg = undefined; // or whatever default value you want
So why didn't you get the warning when using typeof? Because that's not necessarily evaluating the value of the variable, and might be seen by jshlint as justified on non-initialised variables (it even works on undeclared variables). You'd probably get the same warning if you did compare the value to undefined.

Related

Does the change of object in js is also local in a function?

The bellow generates a file containing code and prints the output of the program:
class Code {
static list = require("./settings.json");
static fs = require("fs");
constructor(
code="print('Hello World')",//default code
lang = "py",//language
fn = "test",//file name
args = "" //arguments
) {
this.code = code;
const path = require('path');
this.fn = path.join(__dirname,fn) + "." + lang;//for platform independence
this.run_com = Code.replace(Code.list[lang], this.fn, args);
this._output="Server not responding";
this._error="Server not responding";
}
file_exists()
{
return Code.fs.existsSync(`${this.fn}`);
}
make_file() {
Code.fs.writeFile(`${this.fn}`, this.code, (err) => {
if (err) {
console.log(err);
}
});
}
run_file()
{
if(!this.file_exists())
this.make_file();
const { exec } = require("child_process");
exec(this.run_com, (error, stdout, stderr) =>{
if(error)
{
console.log(error);
}
else if(stderr==""){
this._output=stdout;
this._error="No error";
}
else{
this._error=stderr;
this._output=stdout;
}
console.log(this);//this
});
console.log(this);//this
}
get error()
{
return this._error;
}
get output()
{
return this._output;
}
static replace(
s //replace {}
) {
const arg = Object.values(arguments).slice(1); //convert obj to array removing s
for (let i in arg) {
s = s.replace("{}", arg[i]);
}
return s;
}
}
a = new Code("print('exd')");
a.run_file();
In the above program the output is:
The change in the state of object is not persistent once it comes out of the inner function.
why does the second console.log prints first and why the output of both the console.log are different, please justify in detail.
Also suggest a solution of this problem.
I think this is because exec is async and the second log is printed first. When the async code executes the second log is printed. And in the exec the values of _output and _error are changed hence the difference.

make async.waterfall start with argument from another function

I have bumped into a problem that I can't seem to solve. This is for a steam trading bot and it works well except for when two people trades with it at the same time because class_id and other_id are global variables and they will change in the middle of a trade if more than one is using it.
I tried defining the variables inside the last if statement but then get_class_id did not find the variables. Is there any way the async function can take item.classid and convert_id_64(offer.accountid_other) directly without defining them as variables? I appreciate any help.
var class_id
var other_id
function accept_all_trades(offers_recieved) {
offers_recieved.forEach( function(offer) {
if (offer.trade_offer_state == 1) {
if (typeof offer.items_to_give === "accept") {
offers.acceptOffer({tradeOfferId: offer.tradeofferid}, function(error, response) {
console.log('accepterat offer');
offer.items_to_receive.forEach(function(item) {
if (item.appid === '420') {
class_id = item.classid;
other_id = convert_id_64(offer.accountid_other);
console.log(class_id);
async.waterfall([get_class_id, get_stack, get_name, get_save], add_names);
}
});
});
}
}
});
}
function get_class_id(callback) {
var test = class_id
callback(null, test)
}
Update
I've changed the code to what ben suggested but still when I call get_class_id and try to print the id it is just a blank row in the console, any Ideas?
function get_class_id(callback) {
console.log(class_id);
var test = class_id;
callback(null, test)
}
The problem here is not aysnc.waterfall(). It's async calls (offers.acceptOffer(), get_class_id, get_stack, get_name, get_save, add_names) inside regular javascript forEach(). You need control-flow loops that can control the flow of those async calls. Here is the revised code using async.each():
function accept_all_trades(offers_recieved) {
async.each(offers_recieved, function(offer, eachCb) {
if (offer.trade_offer_state !== 1 || typeof offer.items_to_give !== "accept") {
return eachCb(null);
}
offers.acceptOffer({tradeOfferId: offer.tradeofferid}, function(error, response) {
console.log('accepterat offer');
async.each(offer.items_to_receive, function(item, eachCb) {
var class_id;
var other_id;
if (item.appid !== '420') {
return eachCb(null);
}
class_id = item.classid;
other_id = convert_id_64(offer.accountid_other);
console.log(class_id);
async.waterfall([
function(waterfallCb) {
var test = class_id;
console.log(class_id);
waterfallCb(null, test);
},
get_stack,
get_name,
get_save,
add_names
], eachCb);
}, function(err) {
console.log(err);
eachCb(null);
});
});
});
}

Async Recursion with JavaScript and Node.js

This is probably a noob JavaScript question, but I'm looking to know if my solution to a problem I am having is 'correct'
I have created the following sample application that recreates my error:
Firstly in index.js
var processor = require('./fileProcessor/processor.js');
var container = {
source: "source.txt",
destination: "destination.txt"
};
new processor().process(container);
I create my container object which has the name of the source file and the name of the destination file. This is passed into the process function of the processor:
var fileProcessor = require('./fileProcessor.js');
module.exports = function Processor() {
this.process = function(container) {
var file = new fileProcessor();
if(container.finished === undefined) {
if(container.body === undefined) {
file.read(container, this.process);
} else {
file.write(container, this.process);
}
}
};
};
As you can see this calls the read and write functions passing in the container and the process function as the callback, the fileProcessor looks like this:
var fs = require('fs');
module.exports = function() {
this.read = function(container, callback) {
fs.readFile(container.source, function (err, data) {
if(err) throw err;
container.body = data;
callback(container);
});
};
this.write = function(container, callback) {
fs.writeFile(container.destination, container.body, function(err) {
if(err) {
return console.log(err);
}
container.finished = true;
callback(container);
});
};
};
In simple terms the processor calls file.read, which reads the file and calls back into the process function, which then calls the write function. However at the end of the write function an error is thrown:
callback(container);
^
TypeError: object is not a function
Obviously when passing in this.process to file.write(container, this.process); the this isn't the this I intend it to be!
If I update my processor by adding a processFunction variable:
var fileProcessor = require('./fileProcessor.js');
module.exports = function Processor() {
var processFunction = function(container) {
var file = new fileProcessor();
if(container.finished === undefined) {
if(container.body === undefined) {
file.read(container, processFunction);
} else {
file.write(container, processFunction);
}
}
};
this.process = function(container) {
processFunction(container);
};
};
Everything works fine. Is this a good way to do this or is there a better solution?
I think this is a fine way to do it. There is one possible modification that you might make. Since you are creating a new name in your scope just for the purpose of recursing, you could just name your function and refer to it by its name inside of the function.
module.exports = function Processor() {
this.process = function processFunction(container) {
var file = new fileProcessor();
if(container.finished === undefined) {
if(container.body === undefined) {
file.read(container, processFunction);
} else {
file.write(container, processFunction);
}
}
};
};
Then you can avoid creating a name (processFunction) that will be visible outside the function.
Take a look here for reference:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/function#Named_function_expression

Javascript closure and events

I am facing following issue:
I am calling in foreach cycle following browse function. When the rb.wsc.browse(symbol) is called the program do some WebSocket request and when the message is returned the event is emmited. The problem is that I always get the same browseData even when I know that the event is emited with different one. I think that this is closure issue, but I don't know how to solve it.
function browse(rb, symbol, callback) {
var result = function(wsc, browseData) {
wsc.off('browse', result);
wsc.off('failed', result);
var err = null;
if (wsc.errno < 0) {
err = new Error("Browsing symbol " + symbol + " failed!");
err.status = wsc.errno;
} else {
saveBrowseData(rb, browseData);
}
callback(err, symbol);
};
// Register temporary listeners
rb.wsc.on('browse', result);
rb.wsc.on('failed', result);
// Browse symbol
rb.wsc.browse(symbol);
}
RexBrowser.prototype.refresh = function() {
var that = this;
var browseRequestNumber = 1;
var browseResult = function(err, symbol) {
browseRequestNumber--;
var item = that.getSymbol(symbol);
_.each(item.children, function(child) {
if (child.browse) {
browseRequestNumber++;
debug("Browsing: " + child.cstring);
browse(that,child.cstring, browseResult);
}
});
if (browseRequestNumber === 0) {
that.emit('refresh', that);
}
};
// Start recursive browsing
browse(this,'$', browseResult);
};-
You could try using a IIFE:
} else {
function(rbInner, browseDataInner){
saveBrowseData(rbInner, browseDataInner);
}(rb, browseData);
}
This makes sure the variables used by / in saveBrowseData have the values they have when the function is called.

javascript atob returning 'String contains an invalid character'

I have an AJAX call getting info out of the Github API. It is returned in base64 encoding but when i try to decode it I get the aforementioned error.
Has anyone run into this before and know what is going on? The info the server is returning runs fine through web based decoders. Maybe it get s mangled a bit in a variable? IDK :/
(function () {
'use strict';
var objectsList = [];
var isParsing = 0;
var insertArea = $('body');
function makeAJAXCall(hash, cb) {
$.ajaxSetup({
Accept: 'Application/vnd.github.raw+json',
dataType: 'jsonp'
});
$.ajax({
url: hash,
success: function (json) {
if (cb) {
cb(json);
}
},
error: function (error) {
console.error(error);
throw error;
}
});
}
function parseBlob(hash, cb) {
makeAJAXCall(hash, function (returnedJSON) { // no loop as only one entry
if (cb) {
cb(returnedJSON.data.content);
}
});
}
function addSVGToPage(SVGToAdd) {
var entry, decodedEntry;
makeAJAXCall(SVGToAdd, function (returnedJSON) {
console.info(window.atob(returnedJSON.data.content));
});
}
function parseTree(hash) {
var i, entry;
var tree = 'https://api.github.com/repos/myusername/SVG-Shapes/git/trees/' + hash;
makeAJAXCall(tree, function (returnedJSON) {
for (i = 0; i < returnedJSON.data.tree.length; i += 1) {
entry = returnedJSON.data.tree[i];
if (entry.type === 'blob') {
if (entry.path.slice(-4) === '.svg') { // we only want the svg images not the ignore file and README etc
addSVGToPage(entry.url);
}
} else if (entry.type === 'tree') {
parseTree(entry.sha);
}
}
});
}
$(document).ready(function () {
parseTree('master');
});
}());
Edit: below is a sample of what is returned from a console.info(returnedJSON.data.content);
PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4KPCFET0NU WVBFIHN2ZyBQVUJMSUMgIi0vL1czQy8vRFREIFNWRyAxLjEvL0VOIiAiaHR0 cDovL3d3dy53My5vcmcvR3JhcGhpY3MvU1ZHLzEuMS9EVEQvc3ZnMTEuZHRk Ij4KPHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHht bG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB2ZXJz aW9uPSIxLjEiIGhlaWdodD0iMjQiIHdpZHRoPSI0MDAiPgkKCTxkZWZzPgoJ CTxwYXR0ZXJuIGlkPSJzdHJpcGVkYmFjayIgaGVpZ2h0PSIyMCIgd2lkdGg9 IjIwIiB5PSIyIiBwYXR0ZXJuVW5pdHM9InVzZXJTcGFjZU9uVXNlIiBvdmVy Zmxvdz0ic2Nyb2xsIj4KCQkJPGcgdHJhbnNmb3JtPSJza2V3WCgtMjApIj4K CQkJCTxyZWN0IHg9Ii0xMCIgeT0iMCIgd2lkdGg9IjEwIiBoZWlnaHQ9IjIw IiBzdHJva2U9Im5vbmUiIGZpbGw9IiNGMkYyRjIiLz4KCQkJCTxyZWN0IHg9 IjAiIHk9IjAiIHdpZHRoPSIxMCIgaGVpZ2h0PSIyMCIgc3Ryb2tlPSJub25l IiBmaWxsPSIjRTJFMkUyIi8+CgkJCQk8cmVjdCB4PSIxMCIgeT0iMCIgd2lk dGg9IjEwIiBoZWlnaHQ9IjIwIiBzdHJva2U9Im5vbmUiIGZpbGw9IiNGMkYy RjIiLz4KCQkJCTxyZWN0IHg9IjIwIiB5PSIwIiB3aWR0aD0iMTAiIGhlaWdo dD0iMjAiIHN0cm9rZT0ibm9uZSIgZmlsbD0iI0UyRTJFMiIvPgoJCQk8L2c+ CgkJPC9wYXR0ZXJuPgoKCQk8cmVjdCBpZD0iaW5uZXJjdXQiIHg9IjIiIHkg PSIxIiB3aWR0aD0iMzk2IiBoZWlnaHQ9IjIyIi8+CgoJCTxjbGlwUGF0aCBp ZD0ibG9hZGNsaXAiPgoJCQk8dXNlIHhsaW5rOmhyZWY9IiNpbm5lcmN1dCIv PgoJCTwvY2xpcFBhdGg+Cgk8L2RlZnM+CgoJPHJlY3Qgd2lkdGg9IjQwMCIg aGVpZ2h0PSIyNCIgeD0iMCIgeT0iMCIgc3R5bGU9InN0cm9rZS13aWR0aDoy cHg7c3Ryb2tlOmdyZXk7Ii8+ICA8IS0tIEJhY2tpbmcgcmVjdC9mcmFtZSAt LT4KCgk8ZyBjbGlwLXBhdGg9InVybCgjbG9hZGNsaXApIj4KCQk8cmVjdCB4 PSItMTgiIHkgPSIyIiB3aWR0aD0iNTE2IiBoZWlnaHQ9IjIwIiBzdHlsZT0i c3Ryb2tlLXdpZHRoOjBweDtzdHJva2U6Z3JleTsiIGZpbGw9InVybCgjc3Ry aXBlZGJhY2spIj4KCQkJPGFuaW1hdGVUcmFuc2Zvcm0KCQkgICAgICAgIGF0 dHJpYnV0ZVR5cGU9IlhNTCIKCQkgICAgICAgIGF0dHJpYnV0ZU5hbWU9InRy YW5zZm9ybSIKCQkgICAgICAgIHR5cGU9InRyYW5zbGF0ZSIKCQkJCWZyb209 IjIwIiB0bz0iMCIKCQkJCWJlZ2luPSIwcyIgZHVyPSIwLjZzIgoJCQkJcmVw ZWF0Q291bnQ9ImluZGVmaW5pdGUiCgkJCQlhZGRpdGl2ZT0ic3VtIi8+CgkJ PC9yZWN0PgoJPC9nPgo8L3N2Zz4K
According to MDN docs, you might need to escape and then decodeURIComponent to handle unicode:
function utf8_to_b64( str ) {
return window.btoa(unescape(encodeURIComponent( str )));
}
function b64_to_utf8( str ) {
return decodeURIComponent(escape(window.atob( str )));
}
// Usage:
utf8_to_b64('✓ à la mode'); // "4pyTIMOgIGxhIG1vZGU="
b64_to_utf8('4pyTIMOgIGxhIG1vZGU='); // "✓ à la mode"
atob breaks due to the newlines in the response. Remove them to get your code to work:
function addSVGToPage(SVGToAdd) {
var entry, decodedEntry; // <-- What is this doing here? It's unused.
makeAJAXCall(SVGToAdd, function (returnedJSON) {
console.info(window.atob(returnedJSON.data.content.replace(/\s/g, '')));
// ^^^^^^^^^^^^^^^^^^^
});
}
I have a better solution here:
live demo: https://codepen.io/arliang/pen/mNQayE?editors=1111
// https://best33.com/311.moe
function base64encode(str) {
let encode = encodeURIComponent(str).replace(/%([a-f0-9]{2})/gi, (m, $1) => String.fromCharCode(parseInt($1, 16)))
return btoa(encode)
}
function base64decode(str) {
let decode = atob(str).replace(/[\x80-\uffff]/g, (m) => `%${m.charCodeAt(0).toString(16).padStart(2, '0')}`)
return decodeURIComponent(decode)
}
function tests() {
Array.from([
/*鼠、牛、虎、兔、龙、蛇、马、羊、猴、鸡、狗、猪*/
'🐭🐂🐯🐰🐲🐍🐎🐑🐒🐔🐶🐷',
'测试'
])
.forEach(text => {
try{
console.assert(btoa(atob(text)) === text, `btoa(atob('${text}')) === '${text}' fail`)
} catch(e) {
// console.error(`btoa(atob('${text}')) === '${text}' fail`, e)
}
console.assert(base64decode(base64encode(text)) === text, 'pass')
})
console.log(`Open the console and click this link👉: data:text/html;base64,${base64encode('🐭🐂🐯🐰🐲🐍🐎🐑🐒🐔🐶🐷')}`)
}
tests()
<script>
function unicodeBase64Decode(text){
text = text.replace(/\s+/g, '').replace(/\-/g, '+').replace(/\_/g, '/');
return decodeURIComponent(Array.prototype.map.call(window.atob(text),function(c){return'%'+('00'+c.charCodeAt(0).toString(16)).slice(-2);}).join(''));
}
console.log(unicodeBase64Decode("4pyTIMOgIGxhIG1vZGU="));
</script>
The best, omnivorous
From https://www.base64encode.org/

Categories