Scopes javascript - different when string and array/object - javascript

Was reading this
https://github.com/angular/angular.js/wiki/Understanding-Scopes
and there is same thing on stack overflow:
What are the nuances of scope prototypal / prototypical inheritance in AngularJS?
Here is the thing which I do not understand:
Suppose we then do this:
childScope.aString = 'child string'
The prototype chain is not consulted, and a new aString property is added to the childScope. This new property hides/shadows the parentScope property with the same name.
Suppose we then do this:
childScope.anArray[1] = '22'
childScope.anObject.property1 = 'child prop1'
The prototype chain is consulted because the objects (anArray and anObject) are not found in the childScope.
So in the object array example - parent scope is updated because the objects (anArray and anObject) are not found in the childScope
But in the first example its the same. Except that it is the string. It is not found in the child scope, so should be updated in parent scope. Why it is not updated in parent scope?
Or why array and object in 2nd example are not created in child scope?
Hope its ok to create new thread based on original thread, because just for comment it is long text and would not be easy to read.

In a sense, all three of those examples are really the same. In the second two examples, there's simply an extra object-to-object "hop". The first one:
childScope.aString = "child string";
There's just one object involved: the "childScope" object. (By the way, the word "scope" here makes me uneasy, but let's move on.)
The second pair of examples involve two objects:
childScope.anArray[1] = "22";
childScope.anObject.property1 = 'child prop1';
The two objects in the first of those two statements is the "childScope" object, and then the "anArray" property of the "childScope" object. Presumably, if the statement doesn't cause an error then the value of that property is an array. I stress value because that's the key difference between this reference to a property of "childScope" and the first example ("aString") - here, we want the value of the property because it must be used for the subsequent reference. In the first "aString" example, the statement was setting the value, so there was no interrogation of the current value.
Once the value of childScope.anArray has been fetched, then that object reference is in turn used in a property reference expression. Here, as in the first "aString" example, we're setting the value of the "1" property of the "anArray" object. That's pretty much exactly the same operation as in the "aString" example. (The "anObject" example is much the same.)
When setting a property value (or an array element value; that's really the same thing), JavaScript does not look for a property up the prototype chain. When using the value of a property, it does. An interesting effect of that is this. In the first "aString" example, if there were an "aString" property on the prototype, then once that property is set on the instance ("childScope"), then the prototype property is effectively hidden from view as far as that instance object is concerned.

Related

difference between using setters or methods in javascript

I am reading about getters and setters in javascript. I would like to know if there is a difference between this two ways of coding with and without setters
first way, without setters.
>obj1 = {
arr: [];
}
>obj1.arr.push('first')
>obj1.arr
[ 'first' ]
Second way, with setters.
>obj2 = {
set add(data) {
this.arr.push(data);
},
arr: []
}
>obj2.add = 'first'
>obj2.arr
[ 'first' ]
The setter syntax in your example does not really prevent the client code to still add a value using the direct push call as in the first code block. So the difference is that you just added another way to do the same thing.
To make a fair comparison, you would have to define the same method in both alternatives: once as a normal method and once as a setter method, and then the difference is just the syntax how the argument is passed to the method, either with obj.add('first') or obj.add = 'first'.
In this actual case I would vote against the setter, because it gives the false impression that if you "assign" another value, the first assigned value is overwritten:
obj.add = 'first';
obj.add = 'second';
... but obviously this is not the case: both values exist in the object now.
First, The set Syntax bind an object property to a defined function. In this particular example, there is no difference between two codes, but let's say for example you want to check if the value is negative before adding it to the array, so you can use set to Encapsulate that behavior.
So basically, using setter is only to add additional encapsulated behavior to the functions of the objects.
The way of accessing the array index called bracket notation. it is equal to dot notation, except the bracket notation allows you to set new properties to objects or arrays dynamically.
Hope this help you.
I think difference only about "how it looks like". Using setters it's closest way for understanding for people who came to js from object oriented languages.
The getter/setter property is not the same as "normal" instance property, one is called "named data property", the other is called "named accessor property".
Please let met quote below part of documents from the ECMAScript 5.1.
https://www.ecma-international.org/ecma-262/5.1/#sec-8.10.1
An Object is a collection of properties. Each property is either a
named data property, a named accessor property, or an internal
property:
A named data property associates a name with an ECMAScript language
value and a set of Boolean attributes.
A named accessor property associates a name with one or two accessor
functions, and a set of Boolean attributes. The accessor functions are
used to store or retrieve an ECMAScript language value that is
associated with the property.
An internal property has no name and is not directly accessible via
ECMAScript language operators. Internal properties exist purely for
specification purposes.
There are two kinds of access for named (non-internal) properties: get
and put, corresponding to retrieval and assignment, respectively.
And
If the value of an attribute is not explicitly specified by this
specification for a named property, the default value defined in Table
7 is used.

strange ng-model behaviour (ng-model mapped to array element)

What should be the right behaviuor when you have a ng-model declaration like this one?
data-ng-model="elements[0]"
The way it works, if elements is already defined in the scope as an array, it works as I'd expected assigning the first element of the array.
But if elements is not declared it assigns this value :
elements = {0:'anyvalue'}
(which makes sense if I'd had written data-ng-model="elements['0']")
In this case :
elements[0]='anyvalue';
elements['0']='anyvalue';
and I cannot read the value of the propery using "dot" notation (elements.0 or elements.'0').
So it looks correct, but a bit weird.
Is this behaviour correct, or it should instantiate an array when the scope variable is not defined?
An array is just a special type of object. If you look at an array in a debugger, all of the values are listed as properties with numeric keys, like the one you show. If you don't initialize the object as an array, it would still accesses the object in the same way, which just means you now have an object with numeric keys and none of the helpful functions from the Array prototype.

Literal instance creation behavior varies

I have object literal within that i have another literal .
The parent instances are setting the values fine, but not the inner one.
I am confused with this behavior.
Why the behavior of object literal is different ?
here is the http://jsfiddle.net/Lq6frf76/
var vehicle={
tires : 0,
seats : {
total :0
}
}
var Car = Object.create(vehicle);
Car.tires=4;
Car.seats.total = 4 ;
var bike = Object.create(vehicle);
bike.tires=2;
bike.seats.total = 2 ;
console.log(Car.tires); --->> it is not overwritten not consistent
console.log(Car.seats.total); -->> it is overwritten here
console.log(bike.tires);
console.log(bike.seats.total);
This is not a duplicate question
I knew the alternatives
I knew inner literal will override I saw lot of examples
What I don't know why the same behavior is not repeated for the parent object or in other words
why car.tires value is showing correctly instead of overwritten in my example
Edit: Added some more at the end and made a correction
I feel like we need to put down an answer here. I apologize if this is bad etiquette (and if this is the wrong answer). Please let me know.
The way prototypical inheritance works in javascript:
When you read a property of an object, lets say the tires property of your Car object, first it checks if Car has that property itself. What that means is, is there a tires property directly attached to the Car object? Or in other words, is Car something like this:
{
tires: 0,
...
}
And the answer is no. You might think Object.create() does this, similar to what you might do in a constructor, i.e.
function Vehice(t) {
this.tires = t;
...
};
var Car = new Vehicle(4);
All Object.create() does is make the object you pass in the prototype of the object it returns to you.
So after Object.create(), your object looks something like this
{
__proto__: //reference to vehicle
}
So when it doesn't find tires directly attached to the object, it then looks at the prototype, in this case a reference to the vehicle object you created earlier. The prototype (vehicle) does have the tires property, so it returns that value.
Correction
So what happens when you say Car.tires = 6? When you write a value to an object property, things work differently. Javascript only looks to see if the object itself has that property to write to. If the object itself doesn't have that property, it first checks down the prototype chain to make sure the property is not an inherited readonly property. If it isn't, it creates that property on the object itself (so long as it's legal to write that property to the object). So now you have something that looks like this:
{
tires: 6,
__proto__: //reference to vehicle
}
End Correction
Now when you read the tires property on the Car object, it first sees the tires property on the Car object itself and returns that value, never needing to look at the prototype.
This is why you can set the tires property on one vehicle and not effect the value of the others.
Now for the seats.total property. When you read from the seats property, everything works as before. There is no seats property on the Car object itself, so it looks to the prototype, which does have it. Then it checks the object referred to by seats to see if it has a total property directly attached to it, and it does, so it just returns that value.
Now when you want to write to the total property, things are once again different. The statement is this: Car.seats.total = 4. What happens here is that you are setting the total property on the object referenced by the seats property.
Javascript first has to find the object referenced by seats. It does this by checking to see if it is a property of the Car object itself. It is not, so it checks the prototype, where it finds the seats property. Now it can write the total property to the seats object as we saw before, but notice that this is happening to the seats property of the prototype, which is a referene to the vehicle object defined before and shared by bike.
In other words, javascript does not see that you are writing to a property of the Car object, so it doesn't create a seats property on the Car object and assign it a new object, and then a total property on that object and assign it 4.
Now, when you try to read bike's seats property, javascript first looks to see if bike has a seats property directly attached to it. It does not, so it looks to bike's prototype, which does have it and returns the modified vehicle.seats object.
I hope this clarifies what is happening and answers your questions. Let me know if any part isn't clear, and I hope someone will correct me if I'm just plain wrong!
Addendum: I think coming from a traditional OO language the way it works for tires is what you would expect to happen: You inherit the initial value, but if you change it, you don't expect it to change for every other instance of vehicle.
The way javascript does this is very space economical. By only initially having the prototype have the property, if you have a thousand objects inheriting from vehicle and only 2 of them set the tires property, you've only used up space for three Numbers instead of a thousand.
As for the way it works with seats, I suppose they could have designed the language to detect if you were setting a property on an inherited object (seats) and then copy the entire object into the instance. My guess is that this would actually make the system less flexible and more complicated. If you wanted Car to have it's own version of seats, you could specify it like so:
var car2 = Object.create(vehicle, {
seats: {
value: {
count: vehicle.seats.total
}
}
});
or like so:
var car2 = Object.create(vehicle);
car2.seats = { count: vehicle.seats.total }; //create a new object like the one attached to vehicle
Does that last example make it clearer what's happening?
To me, in this case, an explicit constructor version of this would be more natural, but with javascript we can use constructors or `Object.create(), or various combinations of them to do what we need.
Ultimately though, Every set happens in two parts. First, find the object we are setting the property on; Last, set the property. Everything before that final . is just there to do the first step:
Car.seats.count = 10 means set the count property of the object referred to by Car.seats to 10. What object is Car.seats? We are now following the rules of reading a property, not writing one. Car doesn't have a seats property, so see if it inherits one. If it doesn't, Car.seats will return undefined, and trying to set a property on undefined will throw an error. If it does inherit it, Car.seats will return the object from somewhere down the prototype chain, in this case the object referred to by vehicle. This object has a count property so just set it to 10.
Car.tires = 4 means set the tires property of the object referred to by Car to 4. Car doesn't have a tires property, so make sure we are allowed to create one and then do so.
I hope this clarifies things. Sorry for writing so much, but doing so has really helped solidify these concepts for me. Plus I learned some ECMAScript 5 stuff that i've been blissfully ignoring :-)

Angular data propagation through scope tree with controllers

I'm in the process of learning Angular, and have come across a bit of a problem. I'm trying to create a set of directives that represent different levels within a javascript object. The object contains a number of different properties that depend on the state of other parts of the model. For example, if one of the sub properties is in an error state, the parent is also. I have an extremely over-simplified example HERE. Any help would be greatly appreciated. Especially if someone could explain what's going wrong with the example and offer advise on high-level best practices for angular design. Thanks.
The problem with your example has to do with the new scope that is created by ng-repeat. I'll refer you here for a very detailed explanation, but here's the takeaway:
For each item/iteration, ng-repeat creates a new scope, which prototypically inherits from the parent scope, but it also assigns the item's value to a new property on the new child
scope.
If item is a primitive, essentially a copy of the value is assigned to the new child scope property. Changing the child scope property's value (i.e., using ng-model) does not change the array the parent scope references.
It's a confusing issue with a simple solution: Make your bindable values objects instead of primitives.
In your example, replace
scope.innerValues = [1,2,3];
with
scope.innerValues = [{value: 1}, {value:2}, {value:3}];
Here's your example modified to work: http://plnkr.co/edit/IXKk75721MHNsI0zeBEG?p=preview

General JavaScript Doubts

In C++ I have learned that Variables are the used for Data Storage and Objects are the instance of a Class. But in JavaScript I have seen people referring variables as an Object. Why are the Variables referred as Objects in JavaScript. I am getting confused with that.
In javascript, a variable can either hold a single piece of data itself (like the number 3 or a text string like "Having Fun") or it can hold a reference to an entity like an array or an object.
An object in javascript is essentially a container in javascript. It can hold multiple properties that are each accessed with a key. For example, an object could have a property named "name" that contains the value "Bob", it could also contain a property named "Age" with a value of 29. Objects can have as many properties as one wants. As such objects are essentially a collection of multiple variables, where each variable has its own name and value.
There are technically no "classes" in javascript so it doesn't work the same way that C++ does. Javascript uses prototypes and objects instead of classes and instances in C++.
In reference to the specifics of your question, a variable can contain a value or a reference to an object. There is no right or wrong, it depends upon the problem to be solved.
Some examples:
var person = {}; // a variable `person` that contains a reference to an empty object
person.name = "Bob"; // add a property "name" and value to the object
person.age = 29; // add a property "age" and value to the object
var numPeople = 12; // a variable that just contains a number
Javascript is prototype based OOP language.
Prototype-based programming is a style of object-oriented programming
in which classes are not present, and behavior reuse (known as
inheritance in class-based languages) is performed via a process of
cloning existing objects that serve as prototypes.
In Javascript we use DOcument Object Model(DOM) for refering to different elements of web page.
so when we refer to window,document,form they all are objects and variables are declared like
var x=0;
following will be example of object assignment.
var w=window;

Categories