In my program there is a piece of code structured similar to this:
Number.prototype.print = function(){ console.log(this); };
var a = 1,
b = a + 2
(a - b).print()
However, when this gets executed, it throws an error saying "number is not a function". What is happening here and why is this error get thrown?
In JavaScript semicolons are automatically inserted in most cases. However, seems like the people who developed ES likes to make things more complicated by setting up weird rules for where to put semicolons.
In this case, they decided not to insert semicolon for you, therefore the code becomes this:
var a = 1, b = a + 2(a - b).print()
As you can see, 2 is interpreted as a function reference, and of course, 2 as a primitive is not a function and thus the error.
Related
I spent hours looking at this piece of code:
1: const { services, lists } = this.props;
2:
3: const List = _.map(lists.list, (list) => {
4: const services = _.filter(services.list, (service) => lists.services.indexOf(service.id) > -1);
5: ...
120: ...
121: });
At line number 4, I get an error:
Cannot read property list of undefined
At line number 4, property list is being referenced by services, apparently. And, it is undefined. But, at line 1, it's defined which can be checked by logging its value.
I know the value of services becomes undefined in the closure because JS has its way of finding the variable declarations first and assigning undefined to them before executing the given function. My concern is that, should it be the behavior with the given piece of code considering it's being pre-compiled using Babel?
Edit: I realized that this was your actual question:
My concern is that, should it be the behavior with the given piece of code considering it's being pre-compiled using Babel?
The answer is no, Babel's job is to convert code into its older equivalent, the equivalent here being a var statement. The const statement you have there is perfectly valid syntactically, but is destined to throw an error semantically (note: if you actually executed that const statement in an environment that supports const, it would throw an error before you even tried to access service's list property).
Original answer:
If you define a variable in the same line that you use it, it will always be undefined the first time the statement tries to access it, even if there's a variable with the same name in an outer scope:
const a = 2;
function f() {
const a = a + 1; // error
console.log(a);
}
f();
The solution: don't reuse variable names in inner scopes. Just come up with new names for your variables:
const filteredServices = _.filter(services.list, (service) => lists.services.indexOf(service.id) > -1);
So I'm building a small app where you can evaluate some pieces of JavaScript code, but I'm having a huge "moral" problem:
Initially I wanted to use eval, but I found out about its dangers, so I quickly looked for an alternative.
The closest thing I could find was the function constructor, but for one thing it doesn't evaluate simple pieces of code, such as 2 + 3, since it needs a return statement, whereas eval doesn't, and it's also not that much better security-wise than eval (at least from what I've gathered).
Are there any other ways to evaluate a string as if it were code?
If you want to evaluate JavaScript code, use eval. Is it dangerous? Yes. But that's only because evaluating JavaScript is dangerous. There's no safe way to evaluate JavaScript. If you want to evaluate JavaScript, use eval.
Take every security precaution possible. It's impossible to know what security precautions you should take without knowing more details on what you want to support and how you plan to implement it.
This may be useful:
Is It Possible to Sandbox JavaScript Running In the Browser?
https://github.com/google/caja
You can easily make your own interpreter of JS in JS. I made such thing for www.Photopea.com (File - Scripts, I want to let users execute scripts over PSD documents).
Acorn is an advanced JS parser, which takes a string (JS code) and returns a syntax tree. Then, start at the root of the syntax tree and execute commands one by one.
"Jump" across the tree recursively. Use the JS call stack of the environment as a call stack of the interpreted code. Use JS objects {var1: ..., var2: ...} to store values of variables in each execution space (global, local in a function ...).
You can allow that code to access data from the outer environment through some interface, or make it completely sandboxed. I thought that making my own interpreter would take me a week, but I made it like in 6 hours :)
Please never ever use eval no matter what, there is a much better alternative. Instead of eval, use new function. eval is evil, there's no question about that, but most people skip over the most evil aspect of eval: it gives you access to variables in your local scope. Back in the 90's, back before the concept of JIST compilation, eval's sounded like a good idea (and they were): just insert some additional lines dynamically into the code you're already executing line-by-line. This also meant that evals didn't really slow things down all that much. However, now-a-days with JIST compilation eval statements are very taxing on JIST compilers which internally remove the concept of variable names entirely. For JIST compilers, in order to evaluate an eval statement, it has to figure out where all of its variables are stored, and match them with unknown globals found in the evaled statement. The problem extends even deeper if you get really technical.
But, with new function, the JIST compiler doesn't have to do any expensive variable name lookups: the entire code block is self-contained and in the global scope. For example, take the following terribly inefficient eval snippet. Please note that this is only for the purpose of being an example. In production code, you shouldn't even be using eval or new Function to generate a function from a string whose content is already known.
var a = {
prop: -1
};
var k = eval('(function(b){return a.prop + b;})');
alert( k(3) ); // will alert 2
Now, let's take a look at the much better new Function alternative.
var a = {
prop: -1
};
var k = (new Function('a', 'b', 'return a.prop + b')).bind(undefined, a);
alert( k(3) ); // will alert 2
Notice the difference? There is a major one: the eval is executed inside the local scope while the new Function is executed inside the global one.
Now, onto the next problem: security. There is a lot of talk about how security is difficult, and yes, with eval it is pretty much impossible (e.x. if you wrap the whole code in a sandboxing function, then all you have to do is prematurely end the function and start a new one to execute code freely in the current scope). But, with new Function, you can easily (but not the most efficiently) sandbox anything. Look at the following code.
var whitelist = ['Math', 'Number', 'Object', 'Boolean', 'Array'];
var blacklist = Object.getOwnPropertyNames(window).filter(function(x){
return whitelist.indexOf(x) === -1 && !/^[^a-zA-Z]|\W/.test(x)
});
var listlen = blacklist.length;
var blanklist = (new Array(listlen+1)).fill(undefined);
function sandboxed_function(){
"use-strict";
blacklist.push.apply(blacklist, arguments);
blacklist[blacklist.length-1] =
'"use-strict";' + arguments[arguments.length-1];
var newFunc = Function.apply(
Function,
blacklist
);
blacklist.length = listlen;
return newFunc.bind.apply(newFunc, blanklist);
}
Then, fiddle around with the whitelist, get it just the way you want it, and then you can use sandboxed_function just like new Function. For example:
var whitelist = ['Math', 'Number', 'Object', 'Boolean', 'Array'];
var blacklist = Object.getOwnPropertyNames(window).filter(function(x){
return whitelist.indexOf(x) === -1 && !/^[^a-zA-Z]|\W/.test(x)
});
var listlen = blacklist.length;
var blanklist = (new Array(listlen+1)).fill(undefined);
function sandboxed_function(){
"use-strict";
blacklist.push.apply(blacklist, arguments);
blacklist[blacklist.length-1] =
'"use-strict";' + arguments[arguments.length-1];
var newFunc = Function.apply(
Function,
blacklist
);
blacklist.length = listlen;
return newFunc.bind.apply(newFunc, blanklist);
}
var myfunc = sandboxed_function('return "window = " + window + "\\ndocument = " + document + "\\nBoolean = " + Boolean');
output.textContent = myfunc();
<pre id="output"></pre>
As for writing code to be runned under this strict sandbox, you may be asking, if window is undefined, how do I test for the existence of methods. There are two solutions to this. #1 is just simply to use typeof like so.
output.textContent = 'typeof foobar = ' + typeof foobar;
<div id="output"></div>
As you can see in the above code, using typeof will not throw an error, rather it will only just return undefined. The 2nd primary method to check for a global is to use the try/catch method.
try {
if (foobar)
output.textContent = 'foobar.constructor = ' + foobar.constructor;
else
output.textContent = 'foobar.constructor = undefined';
} catch(e) {
output.textContent = 'foobar = undefined';
}
<div id="output"></div>
So, in conclusion, I hope my code snippets gave you some insight into a much better, nicer, cleaner alternative to eval. And I hope I have aspired you to a greater purpose: snubbing on eval. As for the browser compatibility, while the sandboxed_function will run in IE9, in order for it to actually sandbox anything, IE10+ is required. This is because the "use-strict" statement is very essential to eliminating much of the sneaky sand-box breaking ways like the one below.
var whitelist = ['Math', 'Number', 'Object', 'Boolean', 'Array'];
var blacklist = Object.getOwnPropertyNames(window).filter(function(x){
return whitelist.indexOf(x) === -1 && !/^[^a-zA-Z]|\W/.test(x)
});
var listlen = blacklist.length;
var blanklist = (new Array(listlen+1)).fill(undefined);
function sandboxed_function(){
blacklist.push.apply(blacklist, arguments);
blacklist[blacklist.length-1] =
/*'"use-strict";' +*/ arguments[arguments.length-1];
var newFunc = Function.apply(
Function,
blacklist
);
blacklist.length = listlen;
return newFunc.bind.apply(newFunc, blanklist);
}
var myfunc = sandboxed_function(`return (function(){
var snatched_window = this; // won't work in strict mode where the this
// variable doesn't need to be an object
return snatched_window;
}).call(undefined)`);
output.textContent = "Successful broke out: " + (myfunc() === window);
<pre id="output"></pre>
One last final comment is that if you are going to allow event API's into your sandboxed environment, then you must be careful: the view property can be a window object, making it so you have to erase that too. There are several other things, but I would recommend researching thoroughly and exploring the objects in Chrome's console.
Good Day,
I am working on a pet project using NodeJS and Electron. It is basically a simple text editor at the moment. However I am running into an issue when trying to pass the value of a text-area to a function prior to saving to file.
Specifically when I call a function in another module, the value of the contents becomes 'undefined'. I suspect I am passing it incorrectly, or that it is being over-written between when I make the call and when the call executes, since strings are supposed to be passed by reference.
The code for the Renderer(index.html) is like this :
let otherModule = require('./js/otherModule.js');
let $ = require('jquery');
$('#btn_Save').on('click',() => {
// get the fileName, if empty propmt user with save dialog,
//log it to console for debugging
var contents = $('#txt_Content').val();
console.log('with:',contents.substring(0,9),'...');
var finalContents = contents; // (create a copy?)
if(//someConditionMet//)
{
var otherVar = $('#txt_Other').val();
console.log('Use:',otherVar.substring(0,9),'...');
finalContents = otherModule.someFunc(contents, otherVar);
}
//do something with final contents.
})// end of On-click
I have used console.log() to extensively evaluate the function and can confirm that up to the call to otherModule, the contents are correct, and match those in the textArea.It is once we are in the 'otherModule' that things go awry.
The code for the otherModule is like this:
const someFunc = function(contents, otherVar)
{
console.log('DoThings with:',contents.substring(0,9),'...');
// print shows the value to be undefined...
// do more things
console.log('Did stuff with otherVar:',otherVar.substring(0,9),'...');
// prints just fine as as expected.
// do more things
return someString;
}
module.exports = {
someFunc: someFunc
}
As mentioned in the comment, the very first line of the function logs the contents of the console, which displays the substring as 'undefined'.
Thank you for your time and your consideration!
// Extra context//
I have done some searching but beyond learning that strings are passed by reference and are immutable, I have not seen an answer to a question like this. There has been some discussion of closure issues, but usually in the context of events and callbacks, which I do not believe is the context here.
// Extra Information//
I have since found a solution to get my parameters to pass correctly. I have posted the answer below. I did two things:
1. Changed the function definition from 'const' to 'let'
2. Changed the order of the params, and removed the space following the comma.
If you get the value inside the if you should be fine.
if(//someConditionMet//)
{
var contents = $('#txt_Content').val(); //New line
var otherVar = $('#txt_Other').val();
console.log('Use:',otherVar.substring(0,9),'...');
finalContents = otherModule.someFunc(contents, otherVar);
}
I have found a solution to this problem. I am not certain why it makes a difference but I changed two things in 'otherModule'.
1. I changes the function from 'const' to 'let'
2. I changed the order of the parameters, removing the space after the comma
The new function header looks like:
let someFunc = function(otherVar,contents) {...}
I also updated the call to match the new order ( given):
finalContents = otherModule.someFunc(otherVar,contents);
I hope this helps someone in the future!
very basic JavaScript programmer here!
I was busy on some code with variables that look like this:
blocktype1;
blocktype2;
blocktype3;
blocktype4;
... //everything between blocktype4 and blocktype70, the three dots are not actual code!
blocktype70;
Now I was using eval() in a function where a value was given to one of the blocktype variables. The blocktype depended on the variable "number".
This is what I had for that part:
eval("blocktype" + number) = 3
What I want is, say "number" is 27, then I want the variable blocktype27 to get a value of 3.
When I check the console it says:
ReferenceError: Invalid left-hand side in assignment
Could anyone possibly help me?
I would prefer just vanilla JavaScript and still the use of eval.
Thank you for your time!
The 'correct' solution would probably be to use an Array which is ideal for sequences and are accessible by index.
var number = 1;
var val = 3;
var blocktype = []; // so clean
blocktype[number] = val;
However, properties can be accessed as with the bracket notation as well. This assumes the variables are in global scope and are thus properties of the global (window) object.
var blocktype1; // .. etc
window["blocktype" + number] = val;
The problem with the eval is that is effectively the same as doing f() = 3 which does not make sense: only variables/properties can be assigned to1.
However eval is a built-in function and the results of a function cannot be assigned to, per the error message. It could be written as
var blocktype1; // .. etc (see dandavis' comment)
eval("blocktype" + number + " = " + val);
// What is actually eval'd is:
// eval("blocktype1 = 3")
which quickly exposes a flaw with eval. If val was the string "Hello world!" with would result in eval("blocktype1 = Hello world!") which is clearly invalid.
1 For the gritty: the left-hand side of an assignment has to be a Reference Specification Type, which is a more wordy way of describining the above behavior. (It is not possible for a JavaScript function to return a RST, although it could technically be done for vendor host objects.)
Feel free not to accept this, since it's specifically not using eval(), but:
You can allocate an array of size 71 like so:
var blocktype = new Array(71);
(your number values apparently start at 1, so we'll have to ignore the first element, blocktype[0], and leave room for blocktype[70], the 71st)
You can now assign elements like this:
blocktype[number] = 3;
and use them like so:
alert( blocktype[number] );
I've got this error message, that I'm not a fan of.
Bad line breaking before '?'.
I feel like
var s = (a === b)
? 'one'
: 'two';
looks better. Crockford says:
Semicolon insertion can mask copy/paste errors. If you always break lines after operators, then JSLint can do a better job of finding those errors.
Can someone give me an example or two, of the kind of copy/paste errors he's referring to?
Update:
var s = (a === b)
? 'one'
: 'two';
looks better than
var s;
if(a === b) {
s = 'one';
} else {
s = 'two';
}
(As requested, my comments re-posted as an answer:)
The "obvious" copy/paste error in the example you show would be to copy the first line:
var s = (a === b)
...which of course is valid code on its own but clearly doesn't do the same thing as the three lines together. One would hope that people would look at surrounding code before copying one line, but you never know.
The point that I think Mr Crockford is trying to make is that if you deliberately split a multi-line expression up in a way that the individual lines are not valid code on their own, then if you accidentally copy just one line of the expression it will likely cause a syntax error when you paste it somewhere else. Which is good because syntax errors are reported by the browser and/or JSLint/JSHint, and so easier to find than the more subtle bugs created if you copy/paste a line that is valid on its own. So if you "always break lines after operators" as Crockford suggest:
var s = (a === b) ?
'one' :
'two';
...then the only line of the ternary that is valid code on its own (the third) doesn't really look complete, and so would be easier to spot as a mistake if pasted on its own because it so obviously doesn't do anything on its own - and it's less likely to be copied by itself in the first place for the same reason.
(Having said that, I don't stress about the ternary operator in my own code, and I think the above looks ugly. I put a short ternary expression on one line, a longer one over two lines with the line break after the middle operand and the : lined up under the ?, or a really long one on three lines like yours.)
The most (in)famous example is as follows:
function one() {
return
{
val: 1
};
}
alert(one()); // undefined
vs
function one() {
return {
val: 1
};
}
alert(one()); // [objet Object]
The type of copy-paste errors he's referring to are the ones where you hand your code off to someone else, or yourself in 6 months, and that other person haphazardly copies your code, ending on the closing paren of the condition, assuming that the assignment is meant to be the value of the evaluated right-hand side.
This seems implausible, and in a sense, you would hope that it is...
But I know that auto-insertion has borked code for my company multiple times, now, and they still haven't forced adoption of explicit semicolons, still treat JS as if new lines were significant and still make cut/paste errors, through neglect plus lack of tools/version-management/build-systems.
Say you paste a function expression in immediately before,
var a = 1, b = 1; // a === b, expect 'one'
(function(){
console.log('called');
})
(a === b)
? 'one'
: 'two'
// called
// "two"