I've been reading tutorials for a few weeks now and I've just figured out that when I use the prototype property on a constructor function, the key/value pairs on that prototype property are copied to the proto property of the newly instantiated object.
function F(){};
F.prototype.k = "v";
console.dir(F.k)//logs "undefined"
console.dir(F.prototype.k)//logs "v"
var o = new F;
console.dir(o.k)//logs "v"
So, key "k" is on the prototype property in the constructor and then transfers this to the proto property of newly instantiated object "o" which is why it can be accessed as if it were just a normal key/value pair on the object. Ok, that makes sense to me...but I thought about it and I've seen people use the new keyword for built-in things like String (although this is usually not done)
var s = new String;
the above code is an example of the way a new string item could be created the same way objects can be instantiated based on constructor functions. This made me wonder "is String just a constructor function????!" So I tested this out:
console.dir(String.prototype)
And I got a whole list of exactly the same properties that are attached to s. So, is "String" just a constructor function? The same behavior seems to be true of these items:
console.dir(String.prototype);
console.dir(Number.prototype);
console.dir(Boolean.prototype);
console.dir(Array.prototype);
console.dir(Object.prototype);
console.dir(Function.prototype);
console.dir(Date.prototype);
They all appear to behave exactly the same as constructor functions. They are even all capitalized rather than camelcase. Are they just constructor functions with a few built-in bells and whistles added to them?
There are 6 data types in JavaScript:
Boolean
Number
String
Null
Undefined
Object
The first five are so called primitive types. Three of the primitive types, Boolean, Number and String, also have an equivalent Object implementation.
Whenever you use (Boolean|Number|String) literals, you are creating a value of that corresponding type.
You can also create Boolean, Number and String objects by calling the corresponding constructor function with the new operator:
var s = 'foo'; // type string
var s2 = new String('foo'); // type object
Now, the reason why you can access properties on both of them is that JavaScript auto-boxes primitive values. I.e. when you are trying to access a property on a primitive value, it will temporarily convert the value to an object and access the property.
So
var v = "foo";
alert(v.length);
is essentially
var v = "foo";
alert((new String(v)).length);
If the String, Number or Boolean function is called without the new keyword, they will return a primitive value instead, which makes them act as conversion functions.
And to round this up: Every function has a prototype property, every function can potentially act as a constructor. Whether it really does depends on the implementation of the function.
Related
String is immutable which means we can only read its property, not modify or create or delete any of the property or method. So basically string is freeze.
My question is how is it possible to add a new method to the string prototype?
var a = '';
String.prototype.hi = function(){
console.log('hi');
}
a.hi()
Output: hi
Why is it not throwing any error?
String is immutable which means we can only read its property, not modify or create or delete any of the property or method
This is not true. By strings being immutable we mean that the string object itself is freezed. This doesn't mean that String.prototype, which is a separate object, is freezed. When we add properties to the String.prototype object, that doesn't mean we've mutated any strings. It's just another object not the string itself.
String in Javascript is immutable, it is a true statement. So, you are correct.
So, the value of the string is immutable but not it's prototype. String inherited the prototype from its parent object. The functions available in the prototype do not modify the value of string, it returns a new instance of string.
When it comes to inheritance, JavaScript only has one construct:
objects. Each object has a private property which holds a link to
another object called its prototype. That prototype object has a
prototype of its own, and so on until an object is reached with null
as its prototype. By definition, null has no prototype, and acts as
the final link in this prototype chain.
The value of string in javascript is loosely coupled with prototype. If you replace the prototype of string with empty object, there will be no change of the value. You will get the exactly same value for the string when you will access it.
About prototype, you've got already enough answers what is it...I gues that you even knew it.
So in your example you are not mutating the string it self, what you've noticed is called primitive wrapper objects
MDN
Example:
var a = 'A';
String.prototype.test = function() {
return this;
}
console.log('a primitive type =>', typeof a)
console.log('a primitive object wrapper type =>', typeof a.test());
Yes, It is possible to add new functions to String prototype as like for other objects.
Though it is worth looking at this information present on JavaScript|MDN String
Just remove invocation from your code.
Code:
var a = '';
String.prototype.hi = function(){
console.log('hi');
}
a.hi();
This question already has answers here:
new Number() vs Number()
(5 answers)
Closed 9 years ago.
I'm trying to understand the difference between writing m = Number() (which causes typeof m to evaluate as "number") vs m = new Number() (which causes typeof m to evaluate as "object").
I would have expected it to be an object either way. I was just messing around, and I added a .helloWorld() method to the Number prototype, and I was able to access it on m regardless of which method I used to instantiate it.
What's the difference here? What am I doing differently between writing Number() and new Number()? Why is one an object while the other is a number?
Number() by itself returns a number primitive. When you call new Number() you receive a new instance of an Object which represents Number's (relevant ES5 spec).
When you call a property on a primitive, the primitive is auto-boxed (like in Java) to an instance of that object, which is what lets you call helloWorld() on either the object or number.
However, try this;
var x = Number(5);
x.bar = function (x) { alert(x); };
x.bar("hello");
var y = new Number(5);
y.bar = function (x) { alert(x); };
y.bar("hello");
You'll see the latter works whilst the former does not; in the first, the number is autoboxed to a number, and the bar method is added to it (the object). When you call x.bar() you're creating a new auto-boxed Number, which bar doesn't exist on.
In the latter, you're adding a bar method to that Number instance, which behaves like any other Object instance, and therefore it persists throughout the lifetime of the object.
This is just how it is implemented. This particular constructor function, when called without new, returns a primitive number. When called with new, it returns the object-wrapped number.
You can access prototype methods/properties on primitives because behind the scenes, JavaScript converts them to objects, calls the prototype method, and then throws away the object copy. This allows you to do things like:
var myString = "foo";
console.log( myString.length ); //=> 3
console.log( typeof myString ); //=> "string"
An object copy of the primitive gets made on line two, the length property of the object is checked, and then the object copy is thrown away. myString stays as a string primitive.
I'm reading that in JavaScript, a common point of confusion arises because variables of primitives are passed by value, and variables of objects are passed by reference, while in function arguments, both primitives and references are passed by value.
In the course of my tinkering, I've made up the following code, but am having trouble wrapping my head around it.
> function setName2(obj) {
... obj.name="matt";
... obj = new Object();
... obj.name="obama";
... }
If I set
var person = new Object();
person.name = "michelle";
Then run
> setName2(person);
I get
> person.name;
'matt'
Which makes sense because the new object created is a pointer to a local object, hence not affecting the property of the global 'person'.
However, what if I first set
var obj = new Object();
obj.name = "michelle";
Then run
> setName2(obj);
?
I get the same outcome. Does this mean that the compiler recognizes the two variables of the same name (obj global and obj local) as references to different locations within the heap, each having some different pointer association, or is there a different explanation for this phenomenon?
JavaScript does not have pass-by-reference; everything is passed by value. However, some values are themselves references to objects. This distinction (pass-by-reference vs. is-a-reference) leads to much confusion.
An example to clear things up:
function f(o) { ... }
var obj = { foo: 42 };
f(obj);
No matter what you do in f, obj will always refer to the same object because the argument is not passed by reference. However the value obj, which is copied into o, is itself a reference to an object. This is why any property changes made to o inside the function will be visible on obj after it returns.
while in function arguments, both primitives and references are passed by value.
This is not true. There is nothing special about function arguments.
function setName2(obj) {
This accepts a reference to an object as an argument.
obj.name="matt";
This modifies the name property of the object that reference points to.
obj = new Object();
This replaces the reference to the original object with a reference to a new object.
obj.name="obama";
This modifies the name property of the new object. The original object is unchanged.
The confusion comes from the fact that "passed by reference" is misinterpreted by people or used in a wrong sense.
Parameters are passed by value. This means that changing the value inside the method doesn't change the original value.
In case of primitives, the value of a primitive is its value.
In case of objects, the value of an object is a reference to it. You can access and change object's content but you can't change the value of the reference itself.
In other programming languages, like C++ or C#, "passing by reference" means that you pass:
- a reference to a primitive type
- a reference to a reference to an object
In such case, not only the content of an object can be changed but also a reference itself can be changed.
There is NO passing by reference in Javascript.
Javascript uses pass-by-value.
The confusion is that objects are hold by reference variables (kind of pointers). In fact most common languages (java, javascript, etc.) do not have a real pass-by-reference behaviour. Another way to understand this could be pass-reference-by-value, although, formally, there is not such a thing.
That means when you pass an object as a parameter, you are actually passing a reference to the object by-value.
function setName2(obj) {
...
}
setName2(person);
here the contents of person (a reference, or "pointer" if you like) is copied by-value to a new local variable: obj.
obj and person are different variables that hold a reference to the same object.
So, doing obj = new Object(); makes obj to point to the new object. But person is unaffected since it is still a completely different variable.
I don't know where you read that, but it's absolutely not true. Objects are passed by reference, full stop. Whether or not it's a function parameter is completely irrelevant.
I inherited some javascript code another developer wrote. He didn't like the grid component we used throughout the project, so he decided to write his own. The grid he wrote can't sort dates, because it can only bind to strings / numbers. He converts all dates to strings before using them. I looked at the string formatting of date function he wrote, and figured I could just add a date property to the string with the original value, and then when sorting see if the string has a date property and sort based on that. However, it seems like you can't add properties to strings in javascript. I wasn't aware there were certain types you can't add properties to. For example:
<html>
<script>
var test = "test";
test.test = "test inner";
console.log(test);
console.log(test.test);
</script>
test.test will be undefined. Weird. My question is why this code doesn't work? And also, if you can think of any workarounds for sorting dates on that grid (besides actually binding to date objects instead of strings, which would be a pain to fix,) that would be really helpful.
There are 8 language types in JavaScript:
7 primitive types: Undefined, Null, Boolean, Number, BigInt, String, and Symbol
1 non-primitive type: Object
Values of the primitive types are called primitive values and they cannot have properties.
Values of the Object non-primitive type are called objects an they can have properties.
When you try to assign a property named 'bar' to a variable foo, like so:
foo.bar = 'abc';
then the result will depend on the type of the value of foo:
(a) if the value of foo is of the type Undefined or Null, then an error will be thrown,
(b) if the value of foo is of the type Object, then a named property 'bar' will be defined on the object foo (if necessary), and its value will be set to 'abc',
(c) if the value of foo is of any other type, then a TypeError will be thrown in strict mode: “can't assign to property "bar" on foo: not an object”. In loose mode, the above assignment operation will be a no op. In either case, the variable foo will not be changed in any way.
So, as you can see, assigning properties to variables only makes sense if those variables are objects. If that is not the case, then the assignment will either do nothing at all, or even throw an error.
In your case, the variable test contains a value of the type String, so this:
test.test = "test inner";
does nothing at all.
However, since ES5 introduced accessor properties, there is an exception to what I've said above. Accessor properties allow us to define functions which are invoked whenever the property is either retrieved or set.
For instance:
var str = '';
str.prop;
Here str is a variable holding a String value. Therefore, accessing a property of that variable should be a no-op (str.prop merely returns undefined). This is true with one exception: if String.prototype contains a accessor property 'prop' with a defined getter, then that getter will be invoked.
So, if this is defined:
Object.defineProperty( String.prototype, 'prop', {
get: function () {
// this function is the getter
}
});
then this
str.prop;
will invoke that getter function. This also works in strict mode.
Live demo: http://jsfiddle.net/fmNgu/
However, I don't think that adding accessor properties to the built-in prototypes would be a good practice.
If you use a String object you can add properties:
var test = new String("test");
test.test = "test inner";
console.log(test.toString()); // prints out "test"
console.log(test.test); // prints out "test inner"
Javascript seems to take a few liberties when it comes to its built-in types and objects.
To get at the functions inside the Array type you can do this:
> Array().slice
function slice() {
[native code]
}
So here Array looks like a standard function that is being used as a constructor. Except... slice is not a member function of the Array() function, it's a member function of the Array object.
Another unusual thing about Array() is it seems to return an Array object whether you call it with new() or not:
> var a = Array()
undefined
> a
[]
> a.length
0
> var b = new Array()
undefined
> b
[]
> b.length
0
Math on the other hand seems to be a built in singleton object that is always present (ie: no need to instantiate). So you would use Math.min.apply while with Array using Array().slice.apply.
My question is what makes Array() so different than either a constructor you would write yourself and the other built-in objects of Javascript.
I'll make some comments inline, quoting your question:
Except... slice is not a member function of the Array() function, it's a member function of the Array object.
More exactly, slice is a member of the Array.prototype object, by executing Array(), you are creating a new array object, that inherits from Array.prototype, that's why slice is available.
Another unusual thing about Array() is it seems to return an Array object whether you call it with new() or not:
This behavior is shared also by other built-in constructors, for example Function:
var fn = Function('return "foo";');
Is equivalent to:
var fn = new Function('return "foo";');
The cases are described in the specification (The Array constructor called as a function vs new Array), although other constructors present a different behavior when you use them with or without new, for example, the primitive wrappers:
new Number("20"); // produces a Number object
typeof new Number("20"); // "object"
Number("20"); // makes type conversion
typeof Number("20"); // "number"
Math on the other hand seems to be a built in singleton object that is always present (ie: no need to instantiate). So you would use Math.min.apply while with Array using Array().slice.apply.
Yes, Math is a simple object, not a function like Array.
It inherits from Object.prototype and IIRC the only peculiar difference that it has with a simple user-defined object is that it's internal [[Class]] property contains "Math", e.g.:
Object.prototype.toString.call(Math); // "[object Math]"
My question is what makes Array() so different than either a constructor you would write yourself and the other built-in objects of Javascript.
Array isn't that different, you could write a constructor that behaves the same way if invoked with new or not, for example:
function Foo (arg) {
if (!(this instanceof Foo)) { return new Foo(arg); }
this.foo = arg;
}
new Foo('bar'); // { foo: 'bar' }
Foo('bar'); // { foo: 'bar' }
You're writing
Array().slice()
What that means is:
Call the "Array" function
Look for a property called "slice" on the return value
Treat the value of that property as a reference to a function, and call it
The "slice" function is defined on the Array prototype object, which means that every instance of Array has access to it via that property name. The key here is that the "Array function" as you call it is referenced by the symbol "Array". When you write "Array()", that means to call the function, and thus that expression refers to an array instance. There's not really much difference between a constructor and a regular function; really, it's the new keyword that makes a difference by altering the way that the function is invoked (that is, with a freshly-created Object instance as the this context value). A function is free to check to see if this refers to the global object, and if so to return a newly-created object on its own initiative.
The "Math" object is just an object; you can think of it as being defined like this:
var Math = {
min: function(n1, n2) { ... },
max: function(n1, n2) { ... },
// ...
};