Can I safely assume that in any implementation of JavaScript,
1.) for any object generated by the var obj = { ... }; construct, obj[s] is undefined for any string s unless obj[s] has been explicitly set by my own code?
2.) if typeof obj === 'object' (and obj does not stem from some global, pre-defined variable or function in the global namespace), Object.hasOwnProperty(obj, s) is false for any string s except when I have set property s explicity before or, maybe, when Array.isArray(obj) is true?
In short: Can I assume that user-generated objects that are neither arrays nor of function type do not have pre-defined own properties?
Background: I need to write an interpreter for a very tiny subset of JavaScript that should safely execute user code. I would like to leverage on the optimization capabilities of the JavaScript engine. Hence I am planning to (1.) parse the user's code, (2.) re-write the AST such that (a) no global names can be accessed, (b) property access is restricted by a construct like ((typeof obj === 'object') && Object.hasOwnProperty(obj, s)) ? obj[s] : undefined, (3.) eval the re-written code. For this to work, it is necessary for the objects not to have predefined properties like, e.g., (function () {}).caller, as otherwise the user could make my interpreter to execute arbitrary code or mess with the global objects of my environment in general.
Does, maybe, anybody know of a package where something like this has been done already? My requirements are not high: I need to execute user code, the user needs to work with numbers, strings, arrays, objects, and functions, and I need to exchange these things with the user code.
Edit: First assumption is wrong, see answers.
You can't assume #1. obj[s] will access inherited properties, not just own properties.
var obj = {a: 1, b: 2}
console.log(obj["__proto__"] === undefined);
console.log(obj["toString"] === undefined);
I think #2 is a safe assumption. The whole point of hasOwnProperty() is to distinguish inherited properties from properties that were assigned explicitly in the object.
Related
I'm working on logic that detects any stateful variables that can be safely saved and restored via JSON as the storage vector.
Part of this means detecting types that are "safe" to dump and restore, which is easy for:
numbers, strings and booleans (via typeof)
Array elements (via instanceof Array combined with ^ in iterated elements)
ES6 Class instances (via typeof object and value.__proto__.constructor.name)
There is one type I'm struggling with though. It's the one created from calling:
var nn = new convnetjs.Net();
Which comes from this:
https://github.com/karpathy/convnetjs/blob/master/src/convnet_net.js#L8
What's interesting is that Chrome dev tools detects this as a "Net" object:
This is what you'll see if you inspect the nn var shown above.
Here's what I've tried:
nn instanceof Object === true
Object.getPrototypeOf(nn) - interestingly, this exposes the functions assigned to Net.prototype in the link above, line 12 onwards. Seemed like a lead.
Object.getPrototypeOf(nn).toString() == [object Object]
Object.getPrototypeOf(nn) instanceof Object === true. Makes sense, since it's an object containing custom functions attached to the prototype.
Object.getPrototypeOf(nn).constructor.name === Object
Would anyone know or have ideas how I could detect this type of object safely? Plain objects are fine, but I don't want to overwrite objects with modified prototypes.
If resorted to using this to verify it this is a plain object or one with custom prototypes:
const isPlainObject = Object.getPrototypeOf(value) === Object.getPrototypeOf({});
Is there an elegant solution to destructure an object without specifying all the object's properties?
I wondered if it was possible to use the spread operator but it seems like that's not possible because objects are not arrays!
I guess it may be considered a bad idea to blindly declare variables but I think this would be useful for very large objects.
This is what the with(){} construction allowed:
var obj = {a: 1};
with (obj) {
console.log(a);
}
This construct is however severely discouraged and basically deprecated (it throws an error in strict mode), because it has some major drawbacks:
Your code is hard to read, because it's impossible to tell apart 1) Variables from outer scopes 2) Local variables 3) Properties coming from the object.
Your code can't be optimized, because the JavaScript engine can't tell where your variables are coming from.
Your code is much harder to refactor, because if you introduce a property to your obj, it might shadow some existing local variable, exemple:
var obj = {};
var a = 1;
addSomeProperties(obj);
with (obj) {
console.log(a); // the result here depends on whether or not "addSomeProperties" puts a property named "a" on "obj"
}
TL;DR version: you really don't want this, it makes your code brittle, hard to read&refactor. Just pick the pieces you want apart using the "normal" destructuring syntax.
Lets say I want to check whether a property exists within an Object or not. I was looking at two methods:
if(object.hasOwnProperty(key)) { /* do this */ }
OR
if(object[key]) { /* do this */ }
Assuming that we'll never have object = { key: false };
What are the tradeoffs of using one over the other ?
object[key] checks the entire object chain, including the prototype chain.
object.hasOwnProperty(key) checks to see if the key property is assigned directly to the object and does not look in the prototype chain.
So, which one to use depends upon which result you want.
See a simple demonstration using the hasOwnProperty property: http://jsfiddle.net/jfriend00/6zhv87rk/ which is on the prototype for an object.
You would typically use object.hasOwnProperty(key) when your key can be any arbitrary string and you want to make absolutely sure that it will never conflict with a built-in property on the Object prototype. In fact, if you really want to protect yourself, you even use this Object.prototype.hasOwnProperty.call(object, key) so even the hasOwnProperty property could be used with your object. Cases like this would be when you're using a Javascript object as a hash lookup or dictionary-type object with arbitrary key values.
You would typically use object[key] when you are not concerned about such a conflict because you know what types of keys will be on your object and you know they won't conflict because this version is just shorter and a bit easier to read.
Crockford poses a solution in Javascript: The Good Parts for identifying if an object is an array which goes something like this:
var isArray = function (obj) {
return obj && typeof obj === "object" && obj.constructor === Array;
}
But then he goes on to state that
...it fails to identify arrays that were constructed in a different window or frame...
Why doesn't this solution work in that situation?
The symbol "Array" is something that's local to each window. Checking to see if an object constructed in a different window has a particular native constructor therefore doesn't work.
That is: in window #1, there's an "Array" constructor function. There's also one in window #2. They're the same, of course, but they're different because they're distinct objects. When the comparison is made, it's made the way any object comparison is made: either the two values are references to exactly the same object, or they're not.
It's kind-of odd that JavaScript works this way, but it's the nature of the language.
jQuery does a toString.call(obj) and if the result is "[object Array]", then its isArray() function returns true.
In other cases, when jQuery may just be looking for an array-like object (including DOM collections), it just checks to see if there is a .length property. That's obviously not foolproof, but it does distinguish it from a plain object or other plain type.
I don't know how to extend the map object with prototype and hope you can help.
I have something like this:
var map = {'one':1, 'two':2};
and I would like to have a method to check for the existence of a key:
if (map.containsKey('one')){...}
How would I extend the map object?
It's dangerous to modify Object.prototype, because it affects all objects and will usually break other libraries you may be using. In general, if you want to add methods to a dictionary-like object, you should create an object for your hash instances to inherit from, like the Prototype Hash object.
For this specific instance, you should really just use either if (key in map) or if (map.hasOwnProperty(key)).
There is already an operator to test the existence of a key inside an object.
(In JavaScript, objects are implemented as maps so actually there is no real map.)
if( 'one' in map )
{
alert(map['one']);
}
These are not "maps" they are objects. Building on Maurice's answer, if you want this to apply to all objects:
Object.prototype.containsKey = function(key) {
return this.hasOwnProperty(key);
};
The simplest way to do this is to add a function directly in the object:
map.containsKey = function(key) {
return this[key] ? true : false;
};
In Javascript, you do not need such method really.
if ( map['one'] ) {
// do something
}
should do it
As other's have said, extending Object.prototype might not be a good idea if your code has to play nice with code written by people ignorant of hasOwnProperty().
Anyway, there are three 'correct' ways I know of to check if a property is available:
obj.hasOwnProperty(name)
checks if a property with given name exists in the object.
name in obj
additionally includes properties inherited via an object's prototype chain.
typeof obj[name] !== 'undefined'
will additionally evaluate to false if the property is present but has been set to undefined.
Some non-JS object's (e.g. window.external in IE) might not implement hasOwnProperty(), so one of the other checks has to be used.