var o, d;
o = { get foo() { return 17; } };
d = Object.getOwnPropertyDescriptor(o, "foo");
// d is { configurable: true, enumerable: true, get: /*the getter function*/, set: undefined }
What does that get within the object do? Is that a method or property or something else?
How does it work or how it set property or method to object? Will i fall into trouble if i simply ignore the use of get and set?Are there more advantages in using get and set than simply defining property without there use.What are those advantages if any.Also what will the .getOwnPropertyDescriptor() method returns? If it returns object, can I simply do returnedobj.configurable to access the configurable property-value?
The get defines a property accessor function. When the value of the foo property on o is retrieved, that function is called even though it doesn't look like a function call in the code, e.g.:
var a = o.foo; // Note that `foo` doesn't have () after it, it's not a function call
In this case, it always returns 17, but it could do something else instead. For instance, consider a circle:
var circle = {
radius: 7,
get circumference() { return 2 * Math.PI * this.radius; },
get area() { return Math.PI * this.radius * this.radius; }
};
console.log(circle.circumference); // 43.982297150257104
console.log(circle.area); // 153.93804002589985
circle.radius = 4;
console.log(circle.circumference); // 25.132741228718345
console.log(circle.area); // 50.26548245743669
As you can see, when we access the two properties we defined with accessors, the functions assigned to them get called, even though the property access doesn't look like a function call.
You can also have functions that get called when the property is set. Unsurprisingly, you do that using set rather than get. :-)
You can read more about this in the object initializers part of the specification, and on MDN.
The Object.getOwnPropertyDescriptor call returns an object that describes the property you asked for (in this case, foo). You can read more about it in the spec and on MDN as well.
Quoting from MDN:
A property descriptor is a record (TJC: e.g., object) with some of the following attributes:
value
The value associated with the property (data descriptors only).
writable
true if and only if the value associated with the property may be changed (data descriptors only).
get
A function which serves as a getter for the property, or undefined if there is no getter (accessor descriptors only).
set
A function which serves as a setter for the property, or undefined if there is no setter (accessor descriptors only).
configurable
true if and only if the type of this property descriptor may be changed and if the property may be deleted from the corresponding object.
enumerable
true if and only if this property shows up during enumeration of the properties on the corresponding object.
get is part of the ECMAScript 5 syntax for defining property getters and setters.
Using object literal syntax, it's defined like this:
var obj = {
__other_property__: null,
get foo() { return "bar"; },
set foo(v) { this.__other_property__ = v }
};
This lets you invoke the body of the getter function when doing a get on the property.
obj.foo = "oof";
console.log(obj.foo); // "bar"
console.log(obj.__other_property__); // "oof"
The above uses foo to set a different property __other_property__. This could be a local variable or something else, and the functions can obviously do far more complex operations than I'm showing here.
Related
From my Chrome interpreter:
a = 3; // OK, of course.
a.f = function() { return 4; }; // OK. To a number? Ok
a; // Prints 3
a.f(); // f is not a function.
a.f; // Undefined
Of course, a is not an object, and I cannot assign new members to something that isn't an object. But, why does the interpreter swallows the a.f assignment if after that the method or the member doesn't even exist?
If you look at 8.7.2 of the ECMA 5.1, you will notice this note at the bottom:
The object that may be created in step 1 is not accessible outside of the above method. An implementation might choose to avoid the actual creation of that transient object. The only situations where such an actual property assignment that uses this internal method can have visible effect are when it either invokes an accessor function or is in violation of a Throw predicated error check. When Throw is true any property assignment that would create a new property on the transient object throws an error.
Step 1 is Let O be ToObject(base).
If you look at the ToObject() method in 9.9, you will find these two rows in the table:
Number
Create a new Number object whose [[PrimitiveValue]] internal property is set to the value of the argument. See 15.7 for a description of Number objects.
Object
The result is the input argument (no conversion).
So it looks like when you attempt to set the function on the number, it is actually happening (although as a noop), it just becomes unaccessible after the assignment, due to the assignment happening on an internal transient object. When you do it on a regular object, it returns the actual object, so the assignment makes sense.
There's not really a good reason why it wasn't forbidden, it could easily have been if that was how it was implemented when the language was developed.
But why was it implemented without an error? Because it nicely mirrors what happens when you access a property on a primitive: it does implicitly get cast to an object. It doesn't matter whether you use the property reference for assignment or for retrieval, there's an object involved. The assignment will work as usual, even if the coerced object is thrown away immediately afterwards.
We even can see that when we provide an inherited accessor for that object on its prototype:
"use strict";
Object.defineProperty(Number.prototype, "f", {
set: function(value) {
console.log(typeof this+" "+this+" got "+value+" assigned to .f");
},
get: function() {
console.log(typeof this+" "+this+"'s .f property was accessed");
return function() {
console.log("method called on "+typeof this+" "+this);
};
},
configurable: true
});
(3).f = "test value";
(3).f();
I tried to use the following code to add a start method to an object:
var Bounce = Bounce || {
Info : {},
Game : {}
};
Bounce.Game.prototype.start = function() {
Bounce.log("Starting " + new Bounce.Info());
}
But this results in the following error (on the Bounce.Game.prototype.start line):
Uncaught TypeError: Cannot set property 'start' of undefined
Looking at the object in Chrome's console, I can see that it doesn't contain the prototype object (but has toString, valueOf and constructor etc.).
This is easily fixed by adding the following line before the prototype access:
Bounce.Game = function() {};
I don't know why this is necessary when the object has already been initialized?
W3Schools tells me "Every JavaScript object has a prototype", but that doesn't appear to be the case.
Conceptually, all objects do have a prototype, but only function objects (including constructors like Object, Array, although they don't produce functions) have a property named prototype. They are not the same.
If you read the ECMAScript spec, prototype is usually represented like [[Prototype]], which is an implementation detail lies in the JS engine, rather than a language feature. However, in some engines [[Prototype]] is exposed and can be accessed with __proto__ property (non-standard).
By the way:
If you want to access [[Prototype]], Object.getPrototypeOf() is your friend.
When using a instanceof b, it's actually comparing a's [[Prototype]] chain with b's prototype property.
And why we say null is the prototype of all? It's also not referring to prototype but [[Prototype]]:
Object.getPrototypeOf(Object.getPrototypeOf({})) // null
Object.getPrototypeOf(Object.getPrototypeOf(Object.getPrototypeOf([]))) // null
Object.getPrototypeOf(Object.getPrototypeOf(Object.getPrototypeOf(new String("")))) // null
// or shorter like this
({}).__proto__.__proto__ // null
([]).__proto__.__proto__.__proto__ // null
("").__proto__.__proto__.__proto__ // null
So, inspired by #Leo comments, I think about this solution to use a plain {} object with its prototype.
We have this object:
var Bounce = Bounce || {
Info : {},
Game : {}
};
We define the prototype property for the given object
Object.defineProperty(Bounce.Game, 'prototype', {
get: function() {
return Object.getPrototypeOf(Bounce.Game);
}
});
Now, we can use prototype as usual:
Bounce.Game.prototype.start = function(){
console.log('start');
};
Bounce.Game.start();
Check this out: http://jsbin.com/bapuvo/3/edit
If functions are objects, where does the function's body go?
Let me clarify what I am confused about. Functions are objects, okay. I can think of an object as a hash map consisting of string keys and arbitrarily typed values. I can do this:
function Square(size) {
Rectangle.call(this, size, size);
}
Square.prototype = new Rectangle();
I just treated Square like a regular object and messed with its prototype property by assigning a new value to it. However, if functions are just objects (or hash maps for that matter), where is the function's body (in this example Rectangle.call(this, size, size);) being stored?
I figured it must be stored as the value of some property, something like the following maybe:
console.log(Square.executableBody); // "Rectangle.call(this, size, size);"
Obviously, this is not the case. Interestingly, while reading "The Principles of Object-Oriented JavaScript" by Nicholas C. Zakas, I stumbled upon this:
[...] functions are actually objects in JavaScript. The defining characteristic of a function - what distinguishes it from any other object - is the presence of an internal property named [[Call]]. Internal properties are not accessible via code [...] The [[Call]] property is unique to functions and indicates that the object can be executed.
This might be the property I was looking for above. It does not go into detail, though. Is the function's body actually stored within the [[Call]] property? If so, how does execution work? Unfortunately I was unable to find out more about [[Call]], Google mostly came up with information on a function's call method...
Some clarification would be much appreciated! :)
It becomes the value of another internal property, called [[Code]]:
13.2 Creating Function Objects
Given an optional parameter list specified by FormalParameterList, a body specified by FunctionBody, a Lexical Environment specified by Scope, and a Boolean flag Strict, a Function object is constructed as follows:
[...]
Set the [[Code]] internal property of F to FunctionBody.
If so, how does execution work?
Calling a function basically calls the internal [[Call]] method, which is described in http://es5.github.io/#x13.2.1. I guess the important step is:
Let result be the result of evaluating the FunctionBody that is the value of F's [[Code]] internal property.
Basically, for all practical purposes you can consider the function in its entirety to be the object. You can study the JS spec or JS engine source code to learn about how the function body is actually stored in an internal property on the object, but this won't really help you understand how it works as a JS programmer. You can see the body as a string by evaluating fn.toString. You cannot otherwise access the body other than to execute it or bind to it or call other methods on Function.prototype. However, because it's an object, it can also have properties attached to it like any other object.
Why would I want to attach a property to a function? Here is an example of a memoization function (deliberately simplified):
function memoize(fn) {
var cache = {};
function memoized(x) {
return x in cache ? cache[x] : cache[x] = fn(x);
};
memoized.clear = function() { cache = {}; };
return memoized;
}
So we are placing a function clear as a property on the returned function. We can use this as:
memofied = memoize(really_long_calculation);
result = memofied(1); // calls really_long_calculation
result = memofied(1); // uses cached value
memofied.clear(); // clear cache
result = memofied(1); // calls really_long_calculation again
The function is enough of an object that Object.defineProperty can be called on it, allowing us to write the memoization function above as follows, if we really wanted to:
function memoize(fn) {
var cache = {};
return Object.defineProperty(function (x) {
return x in cache ? cache[x] : cache[x] = fn(x);
}, 'clear', {value: function() { cache = {}; } });
}
(since Object.defineProperty returns the object.) This has the advantage that clear takes on the default non-enumerable and non-writeable properties, which seems useful.
I could even use a function as the first (prototype) argument to Object.create:
someobj = Object.create(function() { }, { prop: { value: 1 } });
but there's no way to call the function serving as prototype. However, its properties will be available in the prototype chain of the created object.
I'm currently setting up JavaScript classes by extending a function prototype with my object of functions / variables like so....
//class shorthand
var clss = function(args){
var c = function() {};
_.extend(c.prototype, args); //using underscore.js
return c;
};
//class definition
var ThisIsMyClass = clss({
varExample: 5,
test: function() {
console.log(this.varExample);
},
alter: function(){
this.varExample = 8;
}
});
//class initialisers
var hello = new ThisIsMyClass();
var hi = new ThisIsMyClass();
var ayup = new ThisIsMyClass();
My question is that everything resides inside the ThisIsMyClass.prototype and the functions can be called and the variables read, but when the values are changed, they then appear outside of the prototype for that object (and also remaining in the prototype with its original value)?
after running this code
//class initialisers
hello.varExample = 6;
hi.alter();
//look at object structure
console.log(hello);
console.log(ayup);
console.log(hi);
//trace the values
hello.test();
ayup.test();
hi.test();
The console looks like this
Is prototype just a reference to the structure, and then when any changes are made, it copies them to object itself?
When you read a property on an object, the interpreter first looks on the actual object itself for that property. If it finds it there, it returns that value. If it does not find the property on the actual object, then it looks on the prototype. If it finds the property on the prototype, it returns that value.
When you set a property on an object, it always sets the property on the actual object (not on the prototype). So, once you've set the property on an object, any reading of that property will come from the one you set on the actual object, not the one on the prototype. Setting a property directly onto the object essentially "hides" or "overrides" the value set on the prototype. You can think of the prototype as the default value for the property, but as soon as you set one on the object itself, the prototype value is no longer used.
function foo() {}
foo.prototype.greet = function() {
console.log("Hello");
}
var x = new foo();
x.greet(); // will log "Hello" - finds method on the prototype
// set new method - will set this property directly on the object itself
// overriding what was on the prototype
x.greet = function() {
console.log("Goodbye");
}
x.greet(); // will log "Goodbye" - finds method on the object
Demo: http://jsfiddle.net/jfriend00/h6akb/
In the implementation of a javascript object, the object has both a set of properties on the object itself and a reference to its prototype. When looking up a property, it is looked for first on the object itself. If it is not found there, then the interpreter gets the reference to the prototype and looks for the property on the prototype object. The prototype object itself is just yet another object, so the interpreter looks for the property directly on the prototype object and, if found returns it. If not found, it checks to see if the prototype object itself has a prototype and so on (allowing for an inheritance chain).
See http://jsfiddle.net/FDhQF/1/ for a trivial example.
What's the difference between something being undefined and something not being defined in Javascript? For instance, trying to access a property for an object (effectively, trying to access a variable) that isn't defined will return undefined. But you can also set something = undefined. When you do that, trying to access it still return undefined, but the pointer is still there. An example, as above, is how iterating over an object still goes over the property that you've (re)declared as undefined. It seems like there are two different sorts of undefined. Can anyone shed some light on the situation?
Both, accessing a property that isn't defined on an object and a property that contains the primitive undefined value, will return you undefined.
For example:
var obj = {
a: undefined
};
obj.a; // undefined
obj.b; // undefined
The difference is that a is an own property, and b isn't:
obj.hasOwnProperty('a'); // true
obj.hasOwnProperty('b'); // false
In the first case a is an own property, even if it contains undefined as its value. In the second case, b is not an own property, accessing obj.b will look for a property named b, all way up in the prototype chain.
When the prototype chain ends (when it reaches an object with a null [[Prototype]]), the property lookup ends and undefined is explicitly returned.
You should know that the hasOwnProperty method checks only if the property physically exist on the object (own properties), but we have also inherited properties, for that case we can use the in operator, for example:
function Test () {}
Test.prototype.a = 'foo'; // instances of Test will inherit from Test.prototype
var obj = new Test(); // { a="foo", b="bar"}
obj.b = 'bar';
obj.hasOwnProperty('a'); // false
'a' in obj; // true
obj.a; // 'foo'
obj.hasOwnProperty('b'); // true
As you can see, obj inherits from Test.prototype, and the a property is not an own property, but it is available through the prototype chain. That's why hasOwnProperty returns false and the in operator returns true.
You can see how internally properties are resolved by the [[Get]] internal operation
Notes:
Accessing undefined as an identifier is not considered to be safe on ECMAScript 3 (the most widely implemented version of the language standard), because instead of being a language keyword (such as null for example) is just a property of the global object, and it is writable on this version of the Spec., meaning that if someone replaces its value (e.g. window.undefined = 'LOL';) , it will break your code.
The typeof operator as #strager mentions can be used instead, for example:
if (typeof obj.prop == 'undefined') { /*....*/ }
This operator returns always a string (it's safe to use == :), and its value depends of the type of its operand, the possible values are described here.
Another common way to solve this is to declare your own undefined variable, available on the scope of your functions, for example, some libraries use the following pattern:
(function(undefined) {
// code here
})();
The function has an argument named undefined, and it is executed immediately without passing any value to it (the last pair or parens make the invocation).
Maybe is worth mentioning that the undefined global property was finally described on ECMAScript 5 as non-writable (immutable, as well non-enumerable and non-configurable -non deletable-).
Using the hasOwnProperty method directly from an object instance is also not considered as safe, because if some object has a property with the same name, the original method will be shadowed. For example:
var obj = { hasOwnProperty: function () { /* evil code :) */ } };
If you call:
obj.hasOwnProperty('prop');
The method defined on the object will be executed (and you wouldn't want this since you know exactly which method you want to invoke...), because it shadows the one from the Object.prototype, however it can be safely invoked by:
Object.prototype.hasOwnProperty.call(obj, 'prop');
Here is a good explanation of "undefined". The gist however is that setting something to "undefined" is not UN-defining it, because "undefined" is actually a primitive value, which is used when a variable (or property) has not been assigned a value.