I have an example, after the line toy.type = 'break';I was expecting the next line would give me the value as "break" but instead gave "soft". Why isnt changing the parent property not reflecting when accessed using child object . Isnt the prototypal inheritance just a refernce to the base object?
const toy = {
init : function(type)
{
this.type = type
},
display : function()
{
console.log(this.type)
}
}
const softToy = Object.create(toy);
softToy.init('soft');
softToy.display();
toy.type = 'break';
softToy.display();
When you access an object, JavaScript searches up the prototype chain until it finds an object with that property.
Because softToy has its own type property, you get the value of that. If it didn't have its own type property then the prototype chain would be followed to the toy object and the type property from there would be accessed instead.
In other words, you get the closest version of the property not the most recently changed version.
Related
My simple example:
let a = { foo : 5}, b = { stuff : 7};
let func = function(obj, prop) { ++obj[prop]; }
func(a, 'foo');
func(b, 'stuff');
When I call func I set the property name as string literal directly. If I want to rename the property late (in my code source) then I have to change the string literal too. Is it possible to get the property name as a string in runtime instead of using the string value as a literal?
UPD (for clarity)
In my project, I have some classes each of them has a property which contains an array. But this property has the different name for each class. I have a logic for handling these arrays content. This logic is the same for each class. Right now I pass the property name as a string literal, but if I later rename these properties in my code source then I must to change and the string literals too. If I forget to do it I will have a problem. So I want to get rid of the use of string literals in this task.
I think what you're trying to do is a bad idea. If something behaves the same in different objects, call it the same name. But hey, there's an ES6 concept for that!
Symbols are used by JavaScript to support similar behaviour in different "classes". So let's do that here.
Let's create a Symbol:
const incrementableProp = Symbol("incrementableProp")
First, let's store the name of the property in your object that should have the behaviour:
const a = {
specialProp: [],
[incrementableProp]: "specialProp"
}
The Symbol itself will always be the same, so the increment function can find it reliably:
function incrementProp(obj) {
if(incrementableProp in obj)
obj[obj[incrementableProp]]++
else throw new TypeError("This object does not support an incremental property.")
}
Lastly, let's make sure you need to change the name only once by removing the Symbol definition in the object. We'll use a decorator for that:
function special(target, key, descriptor) {
target[incrementableProp] = key
return descriptor
}
So now you can do this:
const a = {
#special specialProp: []
}
function me(a, b) {
function he(c, d) {
if(!a[c]) {
}
}
}
Please someone explain 'if(!a[c])' for me.
why this square bracket is used here in [c] though it is a parameter. it is not an array obviously.
what does if(!a[c]) make sense? how two parameters are used like this?
There is nothing special about that code.
It is saying, in English, If the property c of a is falsey, then the condition is true.
In JavaScript, bracket notation can be used to access properties of an object or members of an array.
For example, someArray[5] will access the 6th member of the array, while someObject['someProp'] will access someProp of the object someObject.
The argument a is likely an object. The syntax:
if (!a[c])
Checks to see if the property in the variable c on the a object does not have a truthy value. This could be if it was null, false, undefined or any other falsey value.
The bracket notation can be used with property names. So, if you have an object like this:
var x = { name: "John"};
Then, you can access that property like in any of these ways:
x.name
x["name"];
// Or, if the property name is in a variable
var prop = "name";
x[prop]
Your example is using a version of the last of the above three options when the property name is in another Javascript variable.
In javascript, properties can be accessed dynamically using the square-bracket syntax.
Consider the following:
var person = {name:'Sarah'};
console.log(person.name); // logs 'Sarah';
Sometimes, you might want to dynamically access properties of an object, using a variable that holds the name of the property you want to access. The above example could also be written like this:
var person = {name:'Sarah'};
var prop = 'name';
console.log(person[prop]); // logs 'Sarah';
I'm coming at this from the OOP world and trying to wrap my head around "classes" in Javascript. I'd like to be able to create a class with properties but not have to assign values to them right away. Something like the following:
var MyObject = function(id) {
this.id = id;
// Create the property so it is present on all instances but don't require it to be assigned to right away.
this.friendId;
}
MyObject.prototype = {
constructor: MyObject
// Etc...
}
Is there a way to do this or am I just not getting how it works in Javascript?
Simply omit the property from the declaration:
function MyObject(id)
{
this.id = id;
}
var obj = new MyObject(123);
console.log(obj.friendId); // undefined
Alternatively, explicitly set it to null in the constructor.
This Mozilla Developer Network article is a good read.
It compares Class based and Prototype based languages and provides side by side codes samples in Java and in JavaScript.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Details_of_the_Object_Model
Quoting from the article.
Constructor function or prototype specifies an initial set of properties. Can add or remove properties dynamically to individual objects or to the entire set of objects.
I have been using this for a while as a really nice workaround for how to declare static members for my objects but I really don't understand why they become static so I need somebody to explain to me the following behavior.
I have the following declarations:
// Primitive so nothing interesting here
Array.prototype.someMember = "My value is not static";
// Object containing a primitive, now this is the deal
Array.prototype.someOtherMember = {
value: "My value is static"
};
Array.prototype.changeMember = function (newValue) {
// Change the primitive value
this.someMember = newValue;
// Change the primitive value inside the object
this.someOtherMember.value = newValue;
};
And if this is tested the following way:
var arr1 = [], arr2 = [], arr3 = [];
arr1.changeMember('I changed');
alert(arr1.someMember + ', ' + arr2.someMember + ', ' + arr3.someMember);
alert(arr1.someOtherMember.value + ', ' + arr2.someOtherMember.value + ', ' + arr3.someOtherMember.value);
The result is:
I changed, My value is not static, My value is not static
I changed, I changed, I changed
Now if I reassign the entire object in the changeMember method like this:
Array.prototype.changeMember = function (newValue) {
// Change the primitive value
this.someMember = newValue;
// Change the object
this.someOtherMember = { value: newValue };
};
Then someOtherMember is no longer static, but instead the first instance of Array gets its own. I don't understand the behavior because after all I am accessing someOtherMember through this in both cases, so I can't figure out why it's static in the first case and it's not static in the second.
There's no such thing as a static property in JS. What you're seeing is the normal behaviour of prototypal inheritance. The key concept is this: Arrays, and indeed all objects, are sparse An instance doesn't have a property unless it's explicitly assigned to that instance. as long as that doesn't happen, the prototype holds all properties:
The first case
Why are you seeing I changed, My value is not static, My value is not static? Simple: When arrays are instantiated, all instances will appear to have a property called someMember, but in fact, they don't. When you try to access anArray.someMember JS will first scan the instance for that property, if that instance doesn't have that property defined, JS will turn to the prototype and look for someMember there. In your snippet the changeMember method uses this, to refer to the instance that invokes the method, not Object.getPrototypeOf(this).someMember. The latter being the way to change the property on the prototype level. In short:
arr1.changeMember('I changed');
// is the same as doing:
arr1.someMember = 'I changed';
arr1.someOtherMember.value = 'I changed';
The assignment to someMember is a straightforward assignment, setting a property of an instance.
The second case
The second assignment is reassigning a property of an object, that is referenced by Array.prototype.someOtherMember. The Reference to the object literal doesn't change, only the object itself. Just as in any other language: when dealing with references, the object can change as much as it likes, the reference will remain the same (its value might change, but its memory address doesn't). When you redefine the changeMember method to reassign a new Object literal to a property, you're in essence creating the same situation as in case one: straightforward assignment of a new object to a property, that causes JS not to scan the prototype, but merely assign the property on an instance-level. You could use Object.getPrototypeOf(this) or (for older browsers) this.prototype:
Array.prototype.changeMember = function (val)
{
this.someMember = 'I changed At instance level';
Object.getPrototypeOf(this).someMember = 'Reassing prototype property to '+ val;
Object.getPrototypeOf(this).someOtherMember = {value:val};//changes proto only
};
Having said that, if you want something like a static property, you're better of using Object.defineProperty:
Object.defineProperty(Array.prototype,'sortofStatic',{value:'I cannot be changed',writable:false,configurable:false});
More examples of this can be found on MDN
In someOtherMember one instance of Object is shared between all instances of Array.
In the first case you are changing the value of that object, so the value changes for all instances of Array.
In the second case you are changing an object itself. So the instance of an Array will contain another object that the others.
The first case is well understood.
The second case (where someOtherMember isn't static member), you are overwritting the someOtherMember every time you call changeMember (deleting the static member value) therefore ceases to exist the static member.
Array.prototype.someMember = "My value is not static";
// Here `someOtherMember` is simply a property which points to a memory location
// So initially it will point to the same memory location for all instances of `Array`
Array.prototype.someOtherMember = {
value: "My value is static"
};
Array.prototype.changeMember = function (newValue) {
this.someMember = newValue;
// Here we change a value stored in the memory location pointed by `someOtherMember`
// As all instances point to the same memory location this change will reflect in all instances
this.someOtherMember.value = newValue;
};
Array.prototype.changeMember = function (newValue) {
this.someMember = newValue;
// Here for this particular instance we make `someOtherMember` point to a new memory location.
// All instances will point to the old memory location until `changeMember` is invoked.
this.someOtherMember = { value: newValue };
};
The context (this) is naturally the object that the property is being requested on, but there are no arguments passed to the getter function. I'd like to be able to get the name of the property being requested without using closures but it's looking like that's the only way to do it.
Object.defineProperty( someObj, "prop1", { get: genericGetter } );
Object.defineProperty( someObj, "prop2", { get: genericGetter } );
function genericGetter() {
// i want to figure out whether this is called on prop1 or prop2
}
Can I tell what property a generic getter/setter applies to in its
body?
That's not how getters work. A property of an object can either have a value or a get function. If the property has a value, then reading the property:
var x = obj.prop;
returns that value. However, if a property has a get function instead, then reading that property triggers that function. So, you use getters if the value of a certain property has to be computed dynamically, or if you want to perform certain operations whenever the property is read.
For instance, .innerHTML requires a getter, because its value is not stored statically, but computed on access:
var html = div.innerHTML;
Here, the browser has to serialize the DOM structure that is contained within the div element.
So, if you want a .get() function that retrieves various properties (Backbone.js has such a function), then you're not looking for getters.
The simplest implementation of what you want would be:
someObj.getProp = function ( name ) {
// perform required tasks
return this[ name ];
};