Overriding jQuery function loses 'this' scope - javascript

I am trying to implement the following answer from another question:
https://stackoverflow.com/a/26469105/2402594
Basically I need to add an extra check to a jQuery function. The following code is in jQuery library:
But I can't modify the original jQuery, so I am creating a patch in a separate file. What I am doing is overriding the find function and add functionality as follows:
(function() {
var originalFind = jQuery.fn.find;
jQuery.fn.find = function () {
try {
document === document;
}
catch (err) {
document = window.document;
}
return originalFind.apply(this, arguments);
};
})();
The function is overridden correctly, however, when the code calls 'find', my 'try' doesn't throw any exception when it should because the scope is different than the one inside the Sizzle function, so the original issue is still there.
I have also tried duplicating all of the Sizzle code, adding my modification and assigning it to jQuery.fn.find as done above, however the scope issue is still there and some crashes happen.
I need 'document' to be set before it reaches the following check or it crashes due to permission denied:
How could I share the scope so that the try/catch can be done correctly? Is it even possible? Any other ideas?
Thank you

As we all known, JavaScript has function scope: Each function creates a new scope. Scope determines the accessibility (visibility) of these variables. Variables defined inside a function are not accessible (visible) from outside the function.
So, if the document is defined in the JQuery library function, I think you can't access it. You could try to define a global variable to store the document, then, you can access it in the JQuery library function and the override function.
More details about Javascript Scope, check these links: link1 and link2

Related

Set function default this value

Background:
I am running a sandboxed iframe which only has the permission "allow-scripts". In the sandbox a script is loaded with custom js provided by the user. Now i want to manage access to global functions/objects like XMLHttpRequest. Currently i achieve that with the following code:
const CLEARED_WINDOW_SCOPE= {};
const scope = { /* Here goes the globals the script should have access too */};
const propertyNames = Object.getOwnPropertyNames(window);
for(let property of propertyNames){
CLEARED_WINDOW_SCOPE[property] = undefined;
}
with(CLEARED_WINDOW_SCOPE){
with(scope){
(function (window, self, frames, globalThis){
${scriptContent}
}).call(scope, scope, scope, scope, scope);
}
}
The script does the following:
Create object with all window property names set to undefined
Create object with all properties the user should have access too
Wrap the user code with two with statements the first clears all globals the second grands access to the defined ones
Wrap the user code with a function that is called with the scope as this value
So far everything works perfectly as excepted.
Problem:
The main problem that i have right now is that when a user defines a function like that:
function aFunction(){
console.log(this);
}
He gains access to the normal window object because the default this value within a function is the window.
Question:
Is it somehow possible to change the default this value of a function to the this value of the surrounding scope. Since the user creates the script i can't wrap all function calls with aFunction.bind(scope). Or is there any other value to prevent the access to the global window object?
Is it somehow possible to change the default this value of a function to the this value of the surrounding scope.
No, but you can do the next best(?) thing: setting it to undefined. Just force strict mode:
"use strict";
// User's code
(function (){
console.log(this)
})();
Also, I'm not a JavaScript security expert, but JS sandboxing is a really complex topic because of things like prototype pollution.
Edit: As CherryDT noted in the comments, this method is not completely secure. Users can still access the <iframe> window by creating a function with the Function constructor, for example. Also, a reference to the main window can be obtained through the <iframe> window (window.parent).
It's maybe OK to use this solution for user-supplied code (since users can just open the DevTools console and start typing), but make sure the code comes from the user and never from a URL search parameter, for example. If the code is completely distrusted, I would recommend to use a well-known library like Google Caja.

JavaScript YUI3 Global Variable

I am using the YUI3 TabView component in the following format:
var tabview;
YUI().use('tabview', function(Y) {
tabview = new Y.TabView({srcNode:'#demo'});
alert (tabview); //defined
tabview.render();
});
alert (tabview); //undefined
However, when I try to access the variable tabview outside its declaration function, I am getting an exception that the object is undefined. Can you kindly tell me what am I missing out please?
Edit: Also check JavaScript YUI3 using global variables?
Considering javascript's asynchronous nature, tabview is not necessarily rendered before alert() is called on it outside the YUI block. Seeing "undefined" in the alert box in this case means that the variable has been declared but not assigned to any value. If the variable wasn't accessible, alert() would fail due to an uncaught "ReferenceError".
So, in trying to guessing your intention, if you want to examine the tabview object, you might want to use console.log() instead of alert() to see the output in your browsers console, and put it within the YUI block right after render():
var tabview;
YUI().use('tabview', function(Y) {
tabview = new Y.TabView({srcNode:'#demo'});
console.log(tabview); //defined
tabview.render();
console.log(tabview);
});
In order to use tabview outside the YUI block, ensure that it is ready. As a quick example:
Y.on("domready", function() {
console.log(tabview);
}

Way to access anonymous objects' methods

There is a website, which uses this code below to create website functionality:
$(document).ready(function(){
{
function I_WANT_TO_ACCESS_THIS_METHOD(){
CODE HERE
},
SOME OTHER CODE
}
});
I want to update this website with a greasemokey script, but I don't want to duplicate code already written. That's why I want to access methods that are part of such objects (in the code above it is the I_WANT_TO_ACCESS_THIS_METHOD()).
I'm not a JS master and I'm not sure if it is even possible, but I think that this is the right place to ask ;)
I_WANT_TO_ACCESS_THIS_METHOD() is not a method of an object, but just a function defined inside another function. So you can't access it outside that function(the domcument ready callback function) scope.

How should I store my javascript variables?

I am currently coding in this way:
<script type="text/javascript">
var linkObj;
Is this a safe way to store data? My concern is what if a jQuery or other plug-in was to also use the variable linkObj. Also if I declare my variable like this then can it also be seen by other functions in scripts located in other js files that I include?
$(document).ready(function(){
var linkObj;
});
as long as you use the var keyword, any variable defined in that scope won't be accessible by other plugins.
I you declare a variable this way it will be accessible to all scripts running on the page.
If you just want to use it locally, wrap it in a function:
(function() {var linkObj; ... })()
However, this way nothing outside of the function will be able to access it.
If you want to explicitly share certain variables between different scripts, you could also use an object as a namespace:
var myProject = {}
myProject.linkObj = ...
This will minimize how many global names you have to rely on.
Wrap it in a closure:
<script type="text/javascript">
(function() {
var linkObj;
// Rest of your code
})();
</script>
This way no script outside your own will have access to linkObj.
Is this a safe way to store data?
This is not storing data per se, it's only declaring a variable in a script block in what I assume is an HTML page. When you reload the page in the future, it will not hold previous values.
My concern is what if a jQuery or other plug-in was to also use the variable linkObj.
That's a valid concern, like others have pointed out. However, you would expect plugins not to rely on scope outside the plug-in. This shouldn't impact a lot as good plug-in design would likely prevent this from happening.
Also if I declare my variable like this then can it also be seen by other functions in scripts located in other js files that I include?
Yes. As long as their execution is triggered after your script block gets loaded. This normally follows the order in which your script declaration appears in the page. Or regardless of the order they appear on the page if they are executed, for example, after the jQuery DOM 'ready' event.
It's common to hear that is good to avoid 'global namespace pollution', which relates to this concern. To accomplish that you can use a function to contain code, and directly invoke that function in your script block.
(function () {
var a = 1; // the scope is within the function
alert('The variable a is equal to: ' + a);
}) (); // the parenthesis invoke the function immediately

jQuery - Using javascript variable elsewhere

I fear this question may be extremely newbie level, but I am just drawing a blank.
Within the $(document).ready function I have some DatePicker code...
$('#date-view1').datePicker({
selectWeek: true,
inline: true,
startDate: '01/01/1996'
}).bind('dateSelected', function (e, selectedDate, $td) {
$('#date1').val(selectedDate.asString());
var pfb = selectedDate.asString();
});
The part I am struggling with is the var pfb = selectedDate.asString();
I want to use the variable pfb further down my page in a different function called showProjects().
How can I do this? I have tried declaring the variable inside and outside of the $(document).ready function without luck.
Thanks
Declare var pfb before your document ready block. That'll make it available elsewhere on the page. In the document ready you'll be SETTING an already DECLARED variable.
In Javascript you can use global variables to store values which are accessible from anywhere in the page. Of the many ways of doing this is
setting the value using window.pfb = selectedDate.asString();
and accessing it later anywhere with window.pfb
I'm not sure if this is a problem area, but I wouldn't have tried passing pfb as a param in that onclick event - I think that may re-initialise pfb, or create a new var.
If you're creating it globally (not ideal but should work) then you shouldn't need to pass pfb as a param anyway.
Also, it's good practice not to attach events on the elements like that. Ideally - and jQuery makes this very easy - you should have something in your $(document).ready like this:
$(document).ready(function() {
$("#myButton").click(function() {
showProjects();
});
});
Or even shorten this to
$(document).ready(function() {
$("#myButton").click(showProjects());
});
if you know that showProjects() is the only call that you want to make.
It should work if you just drop the word var
Declaring variables without var makes them global.
It would probably be better form to declare it before the ready block as Dan Ray suggested, but you said you had a hard time with this? Not sure why you would.

Categories