This question is related to What are the best practices to follow when declaring an array in Javascript?
Let's say a client, let's call them "D. B. Cooper", has a first requirement that the following code must run before any other JavaScript code:
Array = function(){
alert('Mwahahahaha');
};
Furthermore, Cooper requires that custom functions must be added to the built in Array object (not the hijacked one). For example, if Array was unhijacked, this would be done with:
Array.prototype.coolCustomFunction = function(){
alert('I have ' + this.length + ' elements! Cool!');
};
Which would afford:
var myArray = [];
myArray.coolCustomFunction();
However, this is not compatible with the first requirement. Thus, how can you best fulfill both of D. B. Cooper's requirements?
Note: D.B. even wrote a test fiddle to help make sure solutions meet his requirements...what a guy!
Update:
For those of you who like a challenge: please try to find an unhijackable cross-browser solution to this problem. For example, here's an even more hijacked test case (thanks for reformatting this Bergi) that hijacks Array, Object, Array.prototype.constructor, and Object.prototype.constructor. Thus far, it looks like there may be a browser-specific solution to this (see Bergi's comment on his answer, and let us know if you find a way to hijack it in FF), but it is unclear at this point if there is a cross-browser solution to this.
Whatever your Array function/constructor is, the literal syntax for arrays will always generate "real" arrays with their [[prototype]] set to the native array prototype object (once, this was a security vulnerability). So, you can always access that by using
Object.getPrototypeOf([])
even if Array or [].constructor are hijacked. (Will of course not work when Object is hijacked, then it get's really complicated)
(Brought D.B. down!)
If you want to use a workaround, in FF the following line will always work (and is not hijackable):
[].__proto__.coolCustomFunction = coolCustomFunction;
Since Array is not necessarily equal to [].constructor, you could use [].constructor to refer to the original Array function since this is hardwired and Array = function(){} won't alter it.
Array = function () { alert("foo")};
// this will always point to the original Array
[].constructor.prototype.foo = "bar";
var myArray = [0, 1];
alert(myArray.foo) // alerts "bar"
http://jsfiddle.net/yXPJ8/5/
Yes ... you just did ... but you created the array using [] .. if you use new Array() it works fine ...
See example here
Related
I just came across this code for a classList polyfill and I can't understand why the developer chose to do the following:
var protoProp = "prototype";
... later in the code...
ClassList[protoProp] = [];
What's wrong with ClassList.prototype = []? I can't think of any reason why they would do this. What am I missing?
It looks to be for minimisation, where that value can be converted into
ClassList[v]=[];
rather than
ClassList.prototype = [];
The protoProp variable is used several places instead of prototype and would save a few bytes in total
in my last project i needed to minify & obfuscate my code and i convert all objects like this
arr.length ===> arr["length"];
str.replace("a","") ===> str["replace"]("a","");
Element.prototype.colorize ===> Element["prototype"]["colorize"]
and every thing works very well
now i have strings
length , replace , prototype , colorize
and we have multiple ways to obfuscate this strings to be more difficult to read.
I've been searching around for a simple-lightweight hashing algorithm for JavaScript. I did find this numerically-based answer on Stack Overflow here.
Unfortunately, I am unable to use this since it's numerically based and I'll need to use this hash as a unique index elsewhere in my code. Often this function returns negative numbers and that would be a big no-no (try 'hello world!'.hashCode() from the snippet linked above to see what I mean).
I've been tempted to use the md5 hashing libraries out there for JS but they're simply to bulky for my purpose and encryption libraries (such as this) are overkill.
It's worth noting that the information within this hash isn't sensitive in anyway and it wouldn't necessarily matter if it was decrypted. The purpose of this function would be to simply generate fixed-length output data that acts as a shortened reference to the original data that I would pass in.
Any help, tips and comments are much appreciated :)
The solution proposed by Kooilnc, to use the absolute value, should do the tric for you. However, if you want to use a hashing function to generate a reference, i assume that the reference you get should be unique as to match the exact element it was generated from. If this is the case, be aware of collisions. Hashing function can create hashes that are similar even though the original messages are different and we call this a collision. If i remember correctly, SHA-1 is also available for java script and is not all that bulk. Good luck
I am unable to use this since it's numerically based and I'll need to use this hash as a unique index elsewhere in my code.
Hash functions are normally numerically based and are rarely perfect (produce unique keys). I think you need something different:
function GuidGen()
{
this.items = {};
this.size = 0;
}
GuidGen.prototype.get = function(str)
{
if (!(str in this.items))
{
this.items[str] = this.size++;
}
return this.items[str];
}
// usage:
id = new GuidGen();
id.get("hello world"); // 0
id.get("spam"); // 1
id.get("eggs"); // 2
id.get("hello world"); // 0
There is already an answer posted to the test itself, which can be found here, but I can't seem to figure out why that answer is correct.
The part of the test that is giving me trouble is:
var keys = [];
var fruits = ['apple', 'orange'];
for(propertyName in fruits) {
keys.push(propertyName);
}
ok(keys.equalTo(['__', '__', '__']), 'what are the properties of the array?');
The (apparently) correct answer, as noted in the above linked question is
ok(keys.equalTo(['0', '1', 'fruits.prototype'), 'what are the properties of the array?');
I tried inserting the answer - fixed the syntax error - and my test still fails.
In the same test file, another test is nearly identical and the answer is what I would expect it to be:
test("property enumeration", function() {
var keys = [];
var values = [];
var person = {name: 'Amory Blaine', age: 102, unemployed: true};
for(propertyName in person) {
keys.push(propertyName);
values.push(person[propertyName]);
}
ok(keys.equalTo(['name','age','unemployed']), 'what are the property names of the object?');
ok(values.equalTo(['Amory Blaine',102,true]), 'what are the property values of the object?');
});
The only difference I can see between these two tests is that the second is using an object rather than an array.
I ran the code from the first test by itself (outside of the unit testing framework) and output the value of keys, which it showed as ["0","1"] - what I would expect. Where is this hidden third value, and how can I access it?
So, I guess I ultimately have two questions:
Why is the answer from the other question not working for me?
What is different about the first test and the second test?
Disclaimer: I'm pretty sure this is right, but haven't bothered testing it. Could you try my answer out, since you've got the tests running?
Looking at the files on GitHub, there is a helper script called koan.js. I'm assuming it gets loaded before the tests because I am too lazy to run them myself :P. (It's in the support directory.)
In this file, there is a method called equalTo defined on all arrays:
Array.prototype.equalTo = function(compareTo) { ... }
So the answers to your questions:
Because the answer to the other question was wrong. Completely misguided. Etc.
Because the method is defined on Array rather than Object.
Seems a little bit underwhelming.
If you define a function like this on the prototype, it will be inherited by all arrays. Try defining something like that in the console and then evaluate [].equalTo. And then, for more fun, try something like:
for (x in []) console.log(x)
Since this method is defined on the prototype, the loop iterates over it as well. So the answer is to the test is probably 0, 1, 'equalTo'. However, if you use the for loop with the hasOwnProperty check, it will naturally not iterate over the method.
This is really an object lesson about no using for in to iterate over arrays :). You never know what's going to sneak in... Coincidentally, this is why prototype.js fell out of favor despite actually being a nice framework.
I am running
var n = [];
jQuery.toJSON( n );
On one page I get "[]" on the other ""[]"". On both pages I run the same jQuery version with a toJson Plugin.
In Firefox DOM I can see both arrays have the same function names, but ... different:
all b(B, A)
any j(B, A)
all all(iterator, context)
any any(iterator, context)
I guess there are some Array.prototype functions before my script. That causing the arrays to be different. I can't change the other code I have to somehow deal with this.
I tried new Array() and jQuery.makeArray(n), still same result. I actually don't care that the arrays are not equal but how do I get the same JSON code for this? It's getting worse if I have strings in the array: ""[\"a\", \"b\"]""
The extra quotes are caused by the
Array.prototype.toJSON
function that is defined by the Prototype library and possibly other libraries as well. This function is called by jQuery.toJSON (or JSON.Stringify() for that matter) and produces the extra quotes. If you would use
delete Array.prototype.toJSON // remove toJSON for all Arrays
//or
delete n.toJSON // remove toJSON for specific Array
before you do the jQuery.toJSON, that should work!
As another suggestion, it is better to use
JSON.stringify(object)
instead of jQuery.toJSON. It is supported natively in most browsers. If you want to be sure it works everywhere, use https://github.com/douglascrockford/JSON-js, it is the basis used for the JSON.stringify() function.
For JSON.stringify(), see https://developer.mozilla.org/En/Using_native_JSON for more info.
My dirty hack for this is:
function cleanJson(s)
{
if (s[0] == '"')
{
s = s.substring(1, s.length-1).replace(/\\"/g,'"');
}
return s;
}
Does the job, but I am still looking for a cleaner solution.
I got a simple question about jQuery but rather javascript approaches in general...
Is it ok, to do this? :
this._checkedTexts.length = 0; // <- array belonging to "me"
var contextCheckedTexts = this._checkedTexts;
$('#valueContainer input:checked').each(function() {
contextCheckedTexts.push($(this).text());
});
Since 'this' points to the element, I am using a closure here to keep additional context for the 'each'-handler around.
Is this the way 'how it's done' or could there be any risk involved using a closure in this way (memoryleak-wise....)?
What other options are there?
I find it very practical - but also I'm always a little worried about introducing reference-count-problems when using closures - which will be hard to find later on.
I don't know what you are trying to achieve but your codes may also be done like this,
this._checkedTexts.length = 0; // <- array belonging to "me"
var arr = $('#valueContainer input:checked').map(function() {
return $(this).text();
}).get();
this._checkedTexts = this._checkedTexts.concat(arr);
It seems to be fine as jQuery methods like each, map, grep does not support context by default (there're bound to the current jQuery object). However you can create you own bind function that will apply context to functions (but in this case you dontn't have to as you use default context to get the elements text).