a quick, probably easy question whose answer is probably "best practice"
I'm following a tutorial for a custom-template mobile Safari webapp, and to change views around this code is used:
function btnSave_ClickHandler(event)
{
var views = document.getElementById('stackLayout');
var front = document.getElementById('mainScreen');
if (views && views.object && front) {
views.object.setCurrentView(front, true);
}
}
My question is just about the if conditional statement. What is this triplet saying, and why do each of those things need to be verified before the view can be changed? Does views.object just test to see if the views variable responds to the object method? Why is this important?
EDIT - This is/was the main point of this question, and it regards not Javascript as a language and how if loops work, but rather WHY these 3 things specifically need to be checked:
Under what scenarios might views and front not exist?
I don't typically write my code so redundantly. If the name of my MySQL table isn't changing, I'll just say UPDATE 'mytable' WHERE... instead of the much more verbose (and in my view, redundant)
$mytable = "TheSQLTableName";
if ($mytable == an actual table && $mytable exists && entries can be updated){
UPDATE $mytable;
}
Whereas if the table's name (or in the JS example, the view's names) ARE NOT "hard coded" but are instead a user input or otherwise mutable, I might right my code as the DashCode example has it. So tell me, can these values "go wrong" anyhow?
Thanks!
The if is testing those 3 pointers to make sure they are non-null. A null pointer is 0 which converts to false. If any of those 3 pointer are 0 (null) then it won't try to use them.
I'm not sure what dereferencing a null pointer does in Javascript but it's an error and may cause an exception. The if is just avoiding that possibility.
Related
I have an idea for a game where people can type in some simple instructions for their character like player.goLeft() or player.attackInFront() and for that I have people type their code into a text box and then I parse it into eval(). This works well but it also allows people to change their own character object by typing things like player.health = Infinity; or something similar. I have a list of functions I want to allow people to use, but I am unsure how to restrict it to only use them.
I understand that the whole point of not letting people use eval is to avoid accidental cross-site scripting but I am unsure on how else to do this. If you have a suggestion please leave a comment about that.
I asked some people around on what to do and most suggested somehow changing scope(which is something I was not able to figure out) or to add some odd parameter to each function in my code that would be required to be a specific string to execute any function, but that seems hacky and since I am making the game in browser with p5js it would be easy to just inspect element and see what the password is.
basically every character has variable called "instruction" which is just a string of javascript. Then every frame of the game I execute it by doing eval(playerList[i].instruction);
tl;dr, how can I only allow specific function to be executed and not allow any others?
EDIT: I forgot to mention that I also am planning to provide player with information so that people can made code that would adapt to the situation. For example there will be parameter called vision that has vision.front and vision.left etc. These variables would just say if there is an enemy, wall, flower, etc around them in a grid. Some people suggested that I just replace some functions with key words but then it compromises the idea of using if statements and making it act differently.
EDIT 2: Sorry for lack of code in this post, but because of the way I am making it, half of the logic is written on server side and half of it works on client side. It will be a little large and to be completely honest I am not sure how readable my code is, still so far I am getting great help and I am very thankful for it. Thank you to everybody who is answering
Do NOT use eval() to execute arbitrary user input as code! There's no way to allow your code to run a function but prevent eval() from doing the same.
Instead, what you should do is make a map of commands the player can use, mapping them to functions. That way, you run the function based on the map lookup, but if it's not in the map, it can't be run. You can even allow arguments by splitting the string at spaces and spreading the array over the function parameters. Something like this:
const instructions = {
goLeft: player.goLeft.bind(player),
goRight: player.goRight.bind(player),
attackInFront: player.attackInFront.bind(player)
};
function processInstruction(instruction_string) {
const pieces = instruction_string.split(' ');
const command = pieces[0];
const args = pieces.slice(1);
if (instructions[command]) {
instructions[command](...args);
} else {
// Notify the user their command is not recognized.
}
};
With that, the player can enter things like goLeft 5 6 and it will call player.goLeft(5,6), but if they try to enter otherFunction 20 40 it will just say it's unrecognized, since otherFunction isn't in the map.
This issue sounds similar to the SQL Injection problem. I suggest you use a similar solution. Create an abstraction layer between the users input and your execution, similar to using parameters with stored procedures.
Let the users type keywords such as 'ATTACK FRONT', then pass that input to a function which parses the string, looks for keywords, then passes back 'player.attackInFront()' to be evaluated.
With this approach you simplify the syntax for the users, and limit the possible actions to those you allow.
I hope this isn't too vague. Good luck!
From your edit, it sounds like you're looking for an object-oriented approach to players. I'm not sure of your existing implementation needs, but it would look like this.
function Player() {
this.vision = {
left: '',
// and so on
}
}
Player.prototype.updateVisibilities = function() {
// to modify the values of this.visibility for each player
}
Player.prototype.moveLeft = function() {
}
Don't give the user an arbitrary interface (such as an input textfield that uses eval) to modify their attributes. Make a UI layer to control this logic. Things like buttons, inputs which explicitly run functions/methods that operate on the player. It shouldn't be up to the player as to what attributes they should have.
I'm trying to modify/use the jstree library to allow a mixed HTML execution settings. Normally, blocking HTML can be achieved by setting force_text to true.
Renaming the node to <b>New Node</b> would cause the text to be rendered as plain text <b>New Node</b> when force_text is set to true and to Node Name when force_Text is set to false.
The problem arose, when it was discovered that force_text = false can cause errors and is not exactly safe/valid for customer use. For example renaming node to <New_Node> causes the node name to go blank and changes the name inside of node data attibutes to HTML markup <new node=""></new>.
I'd have used the force_text option to deal with this, yet I need a different behavior from the nodes. Right now a prefix for the node name can be set with a different input box(It is sent to database before it's showed in the tree, so no problem with HTML rendering here). It is added to the node name when renaming is completed or node is loaded. To make it look good, parentheses and is added to it in the code, so the end result looks like:
(Prefix) Node_Name
However setting force_text to true makes achieving this impossible. The text defaults(as expected) to:
<b>(Prefix)</b> Node_Name
Apart from trying to send a text to jstree through rename_node and set_text methods, which yielded no results, as the library just turns HTML into plain text.
Then I delved into the library itself to look for a way to modify it to suit my needs(I know, it's not advised, not the best option, but checked everything else outside of that. At least everything that I know of). The method "redraw_node", which uses text attribute of the node to show text, looked promising to modify, and even gave good results(I am aware of other places in which I would need to take those changes into account). I changed the part of the code, which sets node text from:
if(this.settings.core.force_text) {
node.childNodes[1].appendChild(d.createTextNode(obj.text));
}
else {
node.childNodes[1].innerHTML += obj.text;
}
To:
if (this.settings.core.force_text) {
node.childNodes[1].appendChild(d.createTextNode(obj.text));
}
else {
if (obj.type === "node_with_prefix_type") {
if (obj.text !== "" || obj.text !== undefined) {
node.childNodes[1].innerHTML += obj.text;
}
else {
node.childNodes[1].innerHTML += obj.data.prefix === undefined || obj.data.prefix === "" ? "" : obj.data.prefix;
node.childNodes[1].appendChild(d.createTextNode(obj.data.name));
}
}
else {
node.childNodes[1].innerHTML += obj.text;
}
}
The code above tried serializing the node text(of a certain type only - prototype code, sorry) from its data attribute. It worked okay for the most part, but copy-paste events proved to be problematic. When first sent to redraw_node data attribute during copy-paste operation, the data value is undefined but is copied later, and I have no access to original node data.
So the question is - is there any way to achieve this boldened prefix with safe HTML-free node name text without modifying the library? Completely disallowing the usage of HTML markups and deleting them inside of the name using regex or even deleting angle brackets? If impossible, how would you go about doing this?
we are facing a pretty strange problem in our web aplication on IE11 (other IE versions work fine).
The application is based on SmartGWT ( http://www.smartclient.com/product/smartgwt.jsp ) - GWT wrapper on SmartClient javascript framework.
IE11 goes into never ending cycles.
It happens very randomly and we have no steps to reproduce it. The complexity of our application makes it impossible to post a sample of the code.
Most often it happens when users work with the application, then they minimize the browser window and after some time they restore it and try to continue working.
The never ending cycles are caused by strange comparison results, when expression 'true === true' results in false.
The comparison code is:
$wnd.isc.isA.Canvas(obj) === true
The code is executed in scope of iframe containing javascript compiled by GWT.
$wnd is the main(top) window of the web application where the SmartClient javascripts are loaded.
The isc.isACanvas(..) is a method returning true or false, depending on whether the object passed as parameter is of Canvas type - Canvas is a special class from SmartClient framework not the HTML Canvas element.
isc.isA.Canvas = function (object) {
return (object != null && object._isA_Canvas);
}
_isA_Canvas is set on object to true (boolean true not 'true' as a string) when the object is being created.
I have added some testing code to the part where the problematic comparison is used - here's a simplified version:
var trueCheckCount = 0;
function isCreated(id){
var obj = $wnd.window[id]; // objects are stored in window by id
var comparisonResult = $wnd.isc.isA.Canvas(obj) === true;
if (!comparisonResult ) {
if ($wnd.isc.isA.Canvas(obj) == true) {
alert("TRUE != TRUE (was OK: " + trueCheckCount + "x before)");
} else {
trueCheckCount++;
}
}
return comparisonResult;
}
In different test runs, the alert was shown after different number of passes. E.g. on the first run it passed 358 698 times, on the second run it passed 330 125 times …
Does anybody have any idea what could be the problem?
How can 'true !== true' ever happen?
Environment:
IE11 (Windows7/8)
SmartGWT: v9.0p_2014-03-02/LGPL Development Only (built 2014-03-02)
GWT: 2.4
Some additional debugging information can be seen on screenshot:
https://drive.google.com/file/d/0B8h18b-AMFzXa3NZZ2dOX2txb1k/edit?usp=sharing
The problem was caused by a bug in IE11.
MS released the fix. It's included in December Internet Explorer Cumulative Update KB3008923.
Installing this update solved our problem.
The technical details we got were:
The bug in question is related to reclaiming of JIT functions and cross-site thunks.
A function with a cross-site thunk is getting reclaimed.
We then change the entryPoint to the InterpreterThunk, losing the cross-site thunk in the process.
Marshalling isn't done when calling this function.
In the repro in question, we end up with a Boolean True object from a different scriptContext, which doesn't match the one in the current scriptContext when comparing with ===.
The problem is 99% in SmartGWT. I recommend you to report this issue to the SmartGWT team and use the latest GWT compiler of course. We dealt with SmartGWT before and from my experience I should say it was a pretty buggy library back then.
You have two issues in your debug code that could be giving you a false impression of the issue:
if ($wnd.isc.isA.Canvas(obj) == true) {
alert("TRUE != TRUE (was OK: " + trueCheckCount + "x before)");
} else {
Firstly, you're doing a double-equal comparison here, where earlier you'd done a === comparison. These are different, and will give different results if the variable being tested is not a boolean.
So for example, if $wnd.isc.isA.Canvas(obj) is outputting an integer 1 or something like that rather than true, then you would get exactly the problem you're describing.
Rather than doing another comparison why not get an accurate picture of the contents of the variable by using JSON.stringify
console.log(JSON.stringify($wnd.isc.isA.Canvas(obj)));
This will show you exactly what the value is, which should then show you fairly clearly why the comparisons aren't doing what you expect.
Secondly, using an alert() box to show errors is not a good idea, especially in a complex application. You should always use console.log() for debugging rather than alert(), because alert() can cause some JS code to alter its behaviour, which can make debugging really difficult.
This is because alert() blocks JS execution while it's displaying, which means that any event handlers or other asyncronous code that get triggered during that time can end up running out of the expected sequence.
I don't think this is necessarily the issue for you here, given the code sample provided, but if you have any Ajax calls, setInterval()s or other similar async code anywhere then you really do need to avoid using alert() for debugging purposes.
Hope that helps.
because of some problems with joomla "in-content javascript" I have to give all my js logic to one file, but there are problems with inconsistence of dom elements across my site (it is ajax driven, so there is only one script and various DOMs).
What is the best solution to make some conditionals solving this problem..
Is it checking $(selector).length, or is there any better solution..
And in case of the $(selector).length , is there a way to save this selector to variable (performance issues)
for example some kind of
var selector = ($(selector).length !== 0) ? this : false ;
if(selector) { makeSomething; }
The this is actually pointing to Window object..So is there any way to make it like this without need of reselection?
Thanks
var $obj = $('selector');
if ($obj.length) { makeSomething(); }
Actually, this is only meaningful if you are searching for the existence of a certain element (that might identify a whole page) and running several operations based on that.
If you just want to do something on the elements like
$('selector').append('x');
the condition might be useless, because if the jQuery collection is empty, the methods won't run anyways (as pointed out by #Gary Green).
On one page of my website the user has the ability to choose and remove up to 2000 items through selecting multiple string representations of them in a dropdown list.
On page load, the objects are loaded onto the page from a previous session into 7 different drop-down lists.
In the window.onload event, the function looping through the items in the drop-downs makes an internal collection of the objects by adding them to a global array - This makes the page ridiculously slow to load, so, I'm fairly certain probably doing it wrong!
How else am I supposed to store these variables?
This is their internal representation:
function Permission(PName, DCID, ID) {
this.PName = PName;
this.DCID = DCID;
this.ID = ID;
}
where: PName is string. DCID is int. ID is int.
EDIT:
Thanks for the quick replies! I appreciate the help, I'm not great with JS! Here is more information:
'selectChangeEvent' is added to the Change and Click event of the Drop down list.
function selectChangeEvent(e) {
//...
addListItem(id);
//...
}
'addListItem(id)' sets up the visual representation of the objects and then calls :
function addListObject(x, idOfCaller) {
var arIDOfCaller = idOfCaller.toString().split('-');
if (arIDOfCaller[0] == "selLocs") {
var loc = new AccessLocation(x, arIDOfCaller[1]);
arrayLocations[GlobalIndexLocations] = loc;
GlobalIndexLocations++;
totalLocations++;
}
else {
var perm = new Permission(x, arIDOfCaller[1], arIDOfCaller[2]);
arrayPermissions[GlobalIndexPermissions] = perm;
GlobalIndexPermissions++;
totalPermissions++;
}
}
Still not enough to go on, but there are some small improvements I can see.
Instead of this pattern:
var loc = new AccessLocation(x, arIDOfCaller[1]);
arrayLocations[GlobalIndexLocations] = loc;
GlobalIndexLocations++;
totalLocations++;
which seems to involve redundant counters and has surplus assignment operations, try:
arrayLocations[arrayLocations.length] = new AccessLocation(x, arIDOfCaller[1]);
and just use arrayLocations.length where you would refer to GlobalIndexLocations or totalLocations (which fromt he code above would seem to always be the same value).
That should gain you a little boost, but this is not your main problem. I suggest you add some debugging Date objects to work out where the bottleneck is.
You may want to consider a design change to support the load. Some sort of paged result set or similar, to cut down on the number of concurrent records being modified.
As much as we desperately want them to be, browsers aren't quite there yet in terms of script execution speed that allow us to do certain types of heavy lifting on the client.
While I haven't tested this idea, I figured I'd throw it out there - might it be faster to return a JSON string from the server side, where your array is fully calculated on that side?
From that point, I'd wager that eval()'ing it (as evil as this may be) might be fast enough to where you could then write the contents onto the page, and your array setup would already be taken care of.
Then again, I suppose the amount of work it'd take the browser to construct the 2k new objects and inject them into the DOM wouldn't necessarily help the speed side of things in the end. At the end of the day, a design change is probably necessary, but sometimes we're stuck with what we've got, eh?