how the prototype works ? why the "xc" can not be accessed from e object?
please look down to the code , see the comments , i testing it in the chorme
var x={a:"xa",b:"xb",c:"xc"};
var e={a:"ea",b:"eb"};
console.log(Object.prototype); // this is {} why? i am expecting it to be null
console.log(e.prototype);
e.prototype=x;
console.log(e.prototype);
console.log(x.c);
console.log(e.c);//this is undefined , why? i am expecting it to be "xc"
console.log(e.a);
console.log(e.b);
console.log(e.prototype.a);
console.log(e.prototype.b);
i first think it would useful in css merging ,later i think for working out the dependency, then re-write css is more reasonable, however the knowledge is real. thanks very much.
var css={
'classSelectorExpressionIDOnly1':{
css_Ruls_name1:xxxx,
css_Rulss_name2:xxxx
}
'classSelectorExpressionIDOnlyX':{
css_Ruls_name1:xxxx,
css_Rulss_name9:xxxx
}
'classSelectorExpressionIDOnly2':{ '()inherit':["classSelectorExpressionIDOnly1","classSelectorExpressionIDOnlyX"]
css_Ruls_name3:xxxx,
css_Rulss_name5:xxxx
}
}
var mergeResult = Object.create(css.classSelectorExpressionIDOnly2);
for(var entry in mergeResult){
mergeResult[entry]= mergeResult[entry];
}
mergeResult.__proto__=css.classSelectorExpressionIDOnly1;
for(var entry in mergeResult){
mergeResult[entry]= mergeResult[entry];
}
mergeResult.__proto__=css.classSelectorExpressionIDOnlyX;
for(var entry in mergeResult){
mergeResult[entry]= mergeResult[entry];
}
------dependency re-write--------
.classSelectorExpressionIDOnly1,.classSelectorExpressionIDOnly2{
css_Ruls_name1:xxxx,
css_Rulss_name2:xxxx
}
.classSelectorExpressionIDOnlyX,.classSelectorExpressionIDOnly2{
css_Ruls_name1:xxxx,
css_Rulss_name9:xxxx
}
.classSelectorExpressionIDOnly2{
css_Ruls_name3:xxxx,
css_Rulss_name5:xxxx
}
That's not what the .prototype property is for. Despite the name, the .prototype property of functions isn't actually the prototype of the objects you're used to working with. This is one of the hardest things to understand about JavaScript, so it's not just you.
The key to understanding the prototype system in JavaScript is that the new operator creates two objects, not one. I'm going to talk about this in terms of four variables:
[[myPrototype]]
The prototype of an object. Every object theoretically has one (though for some objects, it might be undefined).
[[Constructor]]
The function that is being called with the New operator
[[newObject]]
The object that will eventually be returned
[[newPrototype]]
The object that will become [[newObject]].[[myPrototype]]
Note that these aren't valid JavaScript names (in fact, they're not valid names in most programming languages). All of this happens behind the scenes, and most implementations don't use these names either. I'm doing this to make clear that you can't normally see these objects.
When you use the new operator, JavaScript does roughly the following steps.
Create an object [[newPrototype]].
Set [[newPrototype]].[[myPrototype]] to [[Constructor]].prototype
Create an object [[newObject]].
Set [[newObject]].[[myPrototype]] to [[newPrototype]]
Set [[newObject]].[[myPrototype]].constructor to [[Constructor]]
Call [[Constructor]], with [[newObject]] as "this".
Note that [[newObject]].[[myPrototype]] isn't a perfect match for either [[newObject]] or [[Constructor]].prototype. That's why we need a third object between them: it carries the information you want to inherit (through [[newPrototype]].[[myPrototype]]), but it also carries information specific to the object you're creating (in [[newObject]].constructor).
And so we get to what the .prototype function is for. It's not the function's [[myPrototype]], and it's not the [[myPrototype]] for the objects you create with new. It's actually two levels back in the prototype chain, not one.
I hope this explanation helps you understand what the .prototype function is for. This isn't simple stuff, and not every explanation clicks with everybody. That's part of why we have so many explanations here.
When you first create an object, you can set its prototype directly with Object.create(). This function works with IE9 and higher (plus all other modern browsers), and it can be polyfilled if you need to work with older browsers. To see that prototype later, you use Object.getPrototypeOf(), which also has decent browser support (though IE only supports it in version 9 and higher). Using only these two functions, you might create your objects like this:
var x = {a:"xa",b:"xb",c:"xc"};
var e = Object.create(x);
x.a = "ea";
x.b = "eb";
console.log(Object.getPrototypeOf(Object));
console.log(Object.getPrototypeOf(e));
console.log(x.c);
console.log(e.c);//this is undefined , why? i am expecting it to be "xc"
console.log(e.a);
console.log(e.b);
console.log(Object.getPrototypeOf(e).a);
console.log(Object.getPrototypeOf(e).b);
Once an object has been created, there isn't a standard way to reset its prototype yet. ECMAScript 6 defines one (the Object.setPrototypeOf() function), but so far only Chrome and Firefox support it: IE and Safari do not. Still, if that's OK, you could do things like this:
var x = {a:"xa",b:"xb",c:"xc"};
var e = {a:"ea",b:"eb"};
console.log(Object.getPrototypeOf(object));
console.log(Object.getPrototypeOf(e));
Object.setPrototypeOf(e, x);
console.log(Object.getPrototypeOf(e));
console.log(x.c);
console.log(e.c);
console.log(e.a);
console.log(e.b);
console.log(Object.getPrototypeOf(e).a);
console.log(Object.getPrototypeOf(e).b);
There is a non-standard way to reset an existing object's prototype, and it even enjoys good browser support nowadays. To do this, you set the .__proto__ property on any standard object. You could use it like this:
var x = {a:"xa",b:"xb",c:"xc"};
var e = {a:"ea",b:"eb"};
console.log(object.__proto__);
console.log(e.__proto__);
e.__proto__ = x;
console.log(e.__proto__);
console.log(x.c);
console.log(e.c);
console.log(e.a);
console.log(e.b);
console.log(e.__proto__.a);
console.log(e.__proto__.b);
Now, onto your last question: why is Object.prototype equal to {}, rather than undefined? Because the Object constructor function has a .prototype property, which becomes the default prototype of all Objects created through it. The specs call this object [[ObjectPrototype]], and it's where things like the .hasOwnProperty() function live.
Have a look here:
https://stackoverflow.com/a/9959753/2768053
After reading that, you will turn your code into this:
var x={a:"xa",b:"xb",c:"xc"};
var e={a:"ea",b:"eb"};
console.log(Object.prototype.__proto__);
console.log(e.__proto__);
e.__proto__=x;
console.log(e.__proto__);
console.log(x.c);
console.log(e.c);
console.log(e.a);
console.log(e.b);
console.log(e.__proto__.a);
console.log(e.__proto__.b);
and you will get the results you expect :)
Related
Node.js querystring.parse() method returns what looks like to be an object, but one without a constructor. According to https://nodejs.org/api/querystring.html :
"... The object returned by the querystring.parse() method does not prototypically inherit from the JavaScript Object. This means that typical Object methods such as obj.toString(), obj.hasOwnProperty(), and others are not defined and will not work."
This easily causes bugs because typically you would assume that every Object understands some basic methods like toString() and that it has a "constructor" which more or less tells us its "type".
What's the best way to handle these rather incapable Objects? I tried:
let myOb = new Object(dumbObject);
But that produces a result which does not have the toString() -method either and does not have the property 'constructor'.
What's the best way to turn these dumb objects into ordinarily behaving ones? And, why would anybody want to create such objects in the first place?
I think (from the top of my head)
let newObject = JSON.parse(JSON.stringify(dumbObject))
should work.
If you want a more generic way to call toString() on an object, you can call it from Object.prototype using .call().
var s = Object.prototype.toString.call(smartObject);
But why? It's just going to give you "[object Object]" on any plain object. Why is it important to get that string?
var p = {};
var s = Object.create(null);
console.log(p.toString());
console.log(Object.prototype.toString.call(s));
typically you would assume
No, you wouldn't. If you make such assumptions, document them in your interface.
What's the best way to turn these dumb objects into ordinarily behaving ones?
Use Object.assign with an ordinary object as the target. Alternatively, you can also change the prototype by using Object.setPrototypeOf, but that's not recommended.
Or just create the properties like .toString or .constructor that you need. See this example.
And, why would anybody want to create such objects in the first place?
Because you need this safety when using objects instead of Maps. See this example.
Explicitly set the prototype of your dumb object with Object#setPrototypeOf
var dumbObject = Object.create(null);
Object.setPrototypeOf(dumbObject, Object.prototype);
dumbObject.toString() //runs fine
Thanks for all the answers, one of which contained a link to another question which really was my question as well, even if I didn't know that at first. That other question is: How to create a JS object with the default prototype from an object without a prototype?
From it I found the answer which I think is the simplest solution so far: Use Object.assign(). Like this:
let orphan = require('querystring').parse("{}") ;
// console.log ( "Got value: " + orphan ) ;
// Above causes the error:
// -> TypeError: Cannot convert object to primitive value
let oa = (x) => Object.assign({}, x);
console.log ("Got value: " + oa (orphan) ) ;
Note the issue is not particularly about "querystring" but with objects which have no prototype in general. Yes we should probably call these poor objects "orphans" instead of "dumb". But I think "dumb" is still quite good term as well. An object which has no prototype has very few (or no?) methods so it can answer very few if any questions we would like to ask it.
Im a bit confused learning all the new ES6 vs ES5 syntax with javascript and when it comes to functions/classes with methods and calling upon those methods I can't really tell what is the "right way".
For example take this code:
function account(amount) {
let cash = amount;
this.setCash = function(amt)
{
cash = amt;
}
this.getCash = function()
{
return cash;
}
}
var person = new account(100);
console.log(person.getCash()); //returns 100
person.setCash(150);
console.log(person.getCash()); //returns 150
Works like normal as expected (This is how I originally saw the methods being used when going through tutorials).
However i've seen this occasionally:
function account2(amount) {
let cash = amount;
function setCash(amt)
{
cash = amt;
}
function getCash()
{
return cash;
}
return{
getCash,
setCash
}
}
var person2 = new account2(50);
console.log(person2.getCash()); //returns 50
person2.setCash(175);
console.log(person2.getCash()); //returns 175
Both of these work perfectly fine, and do as I think they should. However is one just an older way of doing it? or less correct maybe? This is my biggest barrier in learning JS right now, since ES6 is here there are so many different ways to do something as simple as making a "class" in JS with methods.
Personally the first way seems easier since you don't have to return the functions....but for example at work I see the 2nd way used mostly?
If you removed new from the second version (more on that in a moment) then both of your examples are perfectly fine ways of creating an object with private data accessed via public get/set methods. Which one you would choose is personal preference, or dependent on whether you want to extend the functionality further with prototype methods, etc.
The reason I suggest removing new from the second version is that although both examples work, the first is a "normal" use of the new operator, but the second is an "incorrect" use of the new operator - not a syntax error, just semantically incorrect and potentially misleading for other people reading your code.
So why is that second use of new semantically incorrect? When you say var person = new account(100):
A new object is created with a prototype that is account.prototype. That means the new object inherits any methods and properties of the account.prototype, and from its prototype, etc. (In your case you haven't defined any methods on the prototype, but you could.)
Within the account() function, this will refer to the object created in step 1. Which is why you can attach methods to it with this.setCash = ...
The new object is returned from account() by default. This step will not occur if there is an explicit return statement returning something else as in your account2() function.
So in the first example, person instanceof account is true, because the default object was returned. In the second example, person2 instanceof account2 is false, because a different object was returned - this is misleading for people reading your code, because when they see person2 = new account2() they might reasonably expect that person2 will be an instance of account2 but it's not. It's also a bit inefficient, because the JS engine goes to the trouble of creating an object for you and then you don't use it.
So the second example would be more "correct" without new, providing the same behaviour minus the unnecessary auto object creation:
var person2 = account2(50);
(Almost) any JS function that you write can be called with new, but there is a convention that we describe functions intended to be called with new as "constructors", and usually the function name is capitalised, so Account(), not account(). (The spelling doesn't change the behaviour, it's just an extra hint for people reading the code.)
Note that use of new isn't the only way to link objects to particular prototypes: it is the old-school-but-still-perfectly-valid way, but you can use Object.create() instead.
By the way, the behaviour in question is not new in ES5 or 6, though let and the shortcut object literal syntax in account2 are new.
When you create an instance with new keyword this is returned implicitly where as when assign a function to a variable without new, you need to use return explicitly.
I read a few questions and answers about javascript dictionary implementations, but they don't meet my requirements:
the dictionary must be able to take objects as keys
the values must be accessible by the []-operator
So I came up with the idea to overwrite the valueOf-method in Object.prototype, as follows:
Object.__id__ = 0;
Object.prototype.valueOf = function() {
if(!this.__id__)
this.__id__ = ++Object.__id__;
return "__id__" + this.__id__;
}
Object.prototype.toString = Object.prototype.valueOf;
//test
var x = {p1: "5"};
var y = [6];
var z = {};
z[x] = "7";
z[y] = "8";
console.log(z[x], z[y]);
I tested this with google-chrome and it seems to work well, but I'm a bit sceptical, whether this will cause some drawbacks, since it was so easy to implement.
Considering that the valueOf method is not used for other purposes in the whole code, do you think there are any disadvantages?
It's an interesting idea. I suggest my jshashtable. It meets your first requirement but not the second. I don't really see the advantage of insisting on using the square bracket property access notation: do you have a particular requirement for it?
With jshashtable, you can provide a hashing function to the Hashtable constructor. This function is passed an object to be used as a key and must return a string; you could use a function not dissimilar to what you have there, without having to touch Object.prototype.
There are some disadvantages to your idea:
Your valueOf method will show up in a for...in loop over any native object;
You have no way determining which keys should be considered equal, which is something you may want to do. Instead, all keys will be considered unique.
This won't work with host objects (i.e. objects provided by the environment, such as DOM elements)
It is an interesting question, because I had so far assumed that any object can be used as an index (but never tried with associative arrays). I don't know enough about the inner workings of JavaScript to be sure, but I'd bet that valueOf is used somewhere else by JavaScript, even if not in your code. You might run into seemingly inexplicable problems later. At least, I'd restrict myself to a new class and leave Object alone ;) Or, you explicitly call your hashing function, calling it myHash() or whatever and calling z[x.myHash()] which adds clutter but would let me, personally, sleep better ;) I can't resist thinking there's a more JavaScript-aware solution to this, so consider all of these ugly workarounds ;)
If you came upon this question looking for a JS dictionary where objects are keys look at Map Map vs Object in JavaScript
Here's a ugly bit of Javascript it would be nice to find a workaround.
Javascript has no classes, and that is a good thing. But it implements fallback between objects in a rather ugly way. The foundational construct should be to have one object that, when a property fails to be found, it falls back to another object.
So if we want a to fall back to b we would want to do something like:
a = {sun:1};
b = {dock:2};
a.__fallback__ = b;
then
a.dock == 2;
But, Javascript instead provides a new operator and prototypes. So we do the far less elegant:
function A(sun) {
this.sun = sun;
};
A.prototype.dock = 2;
a = new A(1);
a.dock == 2;
But aside from elegance, this is also strictly less powerful, because it means that anything created with A gets the same fallback object.
What I would like to do is liberate Javascript from this artificial limitation and have the ability to give any individual object any other individual object as its fallback. That way I could keep the current behavior when it makes sense, but use object-level inheritance when that makes sense.
My initial approach is to create a dummy constructor function:
function setFallback(from_obj, to_obj) {
from_obj.constructor = function () {};
from_obj.constructor.prototype = to_obj;
}
a = {sun:1};
b = {dock:2};
setFallback(a, b);
But unfortunately:
a.dock == undefined;
Any ideas why this doesn't work, or any solutions for an implementation of setFallback?
(I'm running on V8, via node.js, in case this is platform dependent)
Edit:
I've posted a partial solution to this below, that works in the case of V8, but isn't general. I'd still appreciate a more general solution.
You could just use Object.create. It's part of ES5 so it's already available natively in some browsers. I believe it does exactly what you want.
Okay, some more research and cross-platform checking and there's some more information (though not a general solution).
Some implementations have basically what I did for my __fallback__. It is called __proto__ and is about perfect:
a = {sun:1};
b = {dock:2};
a.__proto__ = b;
a.dock == 2;
It seems that, what happens in when a new object is constructed is roughly this:
a = new Constructor(...args...);
produces behavior roughly equivalent to:
object.constructor = constructor;
object.__proto__ = constructor.prototype;
constructor.call(this, ...args...);
So it is no wonder that coming along later and adjusting an object's constructor or constructor.prototype has no effect, because the __proto__ setting is already set.
Now for my v8 application, I can just use __proto__, but I understand it that this isn't exposed on the IE VM (I don't run windows, so I can't tell). So it is not a general solution to the problem.
I have a method, that perfectly works in Firefox, with which I can determine the name of an instance of a particular javascript object (please don't ask why I need it...).
Fr example:
var temp = new String("hello!");
var theName = getVarName(temp); //returns "temp"
This method uses "window.hasOwnProperty()" which doen't work in Internet Explorer: any suggestions?
If for whatever reason you do need to use window, use:
Object.prototype.hasOwnProperty.call(obj, p)
I have a method, that perfectly works in Firefox, with which I can determine the name of an instance of a particular javascript object
I don't think you do, because that's not possible in JavaScript. JS is a call-by-value language; when you write:
var temp= 'hello';
getVarName(temp);
that's exactly the same as saying:
getVarName('hello');
At which point the reference to ‘temp’ as a variable is lost. What I'm guessing your getVarName function does is basically this:
function getVarName(value) {
for (var name in window) {
if (window[name]===value)
return name;
}
}
This will work on IE and other browsers without Object.hasOwnProperty(); it will simply return the name of any global variable that matches the argument. The hasOwnProperty() call can be added to this function to refine it a little by only allowing direct properties of window (which act as global variables, including the ones you set explicitly), and not of any of its prototypes. I'm guessing that's what your version of the function is doing, but in practice it has very little effect since almost nothing inherits into ‘window’ by prototype.
You're confusing things a little bit by boxing your 'hello' in an explicit String object (which is very unusual and rarely a good idea), which makes it possible to have two different 'hello' objects that are disinguishable using the === identity comparator, so this will work:
var a= new String('hello!');
var b= new String('hello!');
getVarName(a); // 'a'
getVarName(b); // 'b' - distinguishable object from a
But that still doesn't stop you from doing:
var a= new String('hello!');
var b= a;
getVarName(a); // 'a' or 'b', depending on implementation
getVarName(b); // the same 'a' or 'b' as in the previous call
So, whilst you can fairly harmlessly lose the hasOwnProperty() call as above, what you're doing can't really work properly and you should probably look at a better way of achieving whatever it is you're up to.
Do not use global variables. Always put them in namespaces so that you don't run into such problems.
If I understood correctly, you want the global variable name when given the value under any scope. For example, the following should work too
var temp = "hello";
function foo(x) {
alert(getVarName(x)); //returns "temp" as well.
}
foo(temp);
This is sort of reverse hash lookup on Window object which is not only expensive, since you need to iterate over all the properties of window object each time, but also unreliable (two variables can have a same value).