When I run above code in Chrome dev console, I do not get any error. But when same code runs via js loaded on a webpage I receive this exception -
Cannot create property 'name' on string 'some string'
Can someone please tell me why there is different behaviour in above 2 cases?
Your webpage must be running that snippet of code in strict mode, in which assigning to properties of a string will throw an error:
'use strict';
const str = 'foo';
str.bar = 'bar';
In sloppy mode, it'll just fail silently:
const str = 'foo';
str.bar = 'bar';
Strings are a value objects as in they have a value not a reference to an instance of an object, they cannot have properties set with a["name"] like reference objects can.
a[3] is the 4th character in the string, a[0] being the first.
Let's see this case
const a = "a"
Object.isFrozen(a) // true
const b = new String("b")
Object.isFrozen(b) // false
From this section, we could see that String objects are not necessarily frozen. Only those string literals are frozen (I think it's because they are shared in a pool. If they are not frozen, you can create properties on one place to affect the code elsewhere) However, the explicitly constructed String objects are independent from the pool, thus not frozen.
Related
During my coding I made a mistake by calling a function like this
someFunction( 'abc' [someValue] )
I had forgotten the colon inside the function call.
After I found the error I played around.
An assignment like this does not throw an error as well.
let a = 'abc'[someValue];
I would expect a syntax error here. Is there an explanation for this?
A string in Javascript can behave as an object and, as such has properties such as .length and methods such as .slice. So, for any property access on an object in Javascript, one can use either the dot notation as in:
str.length
or the [] syntax as in:
str["length"]
or using a variable:
let len = "length";
str[len]
So, what you have with:
'abc' [someValue]
Is just that syntax. A string followed by a property access. That is legal Javascript. It attempts to get the property from that object with the name of whatever string is in the someValue variable.
Here's are a couple working examples:
// simple property access
let prop = "length";
console.log("abc"[prop]);
// method call
console.log("one fine day"["slice"](4, 8));
One would not generally code this way with a string, but it's perfectly legal as it's just part of how one can access properties on an object in Javascript.
Because that's not a syntax error. The engine thought you were trying to get a letter from that string, so if someValue was a number it will work perfectly fine
let a = "abc"[0]
console.log(a, "abc"[1]) //a, b
I'm trying to add a custom method on the prototype of the Array object:
Array.prototype.demo = function(){
this.forEach(i=>console.log(i))
}
But, I'm receiving the error below when I'm calling the method like this:
[1,2,3].demo()
// Error: TypeError: Cannot read property 'demo' of undefined
However, it runs successfully when I change it to:
const arr = [1,2,3];
arr.demo()
// Output: 1, 2, 3
PS. This is in nodejs
To reproduce the error in the browser, copy/paste the full block at once and click enter.
UPDATE: It sounds like we need to add a semicolon to make it work:
Array.prototype.demo = function(){
this.forEach(i=>console.log(i))
}; <=== added semicolon here to work #jfriend00
[1,2,3].demo();
However, now this next code works WITHOUT semicolon!!
String.prototype.demo = function(){
this.split('').forEach(c=>console.log(c))
}
'hello'.demo();
Quick Fix - Add Semi-colon
Add a semi-colon at the end of your function definition:
Array.prototype.demo = function(){
this.forEach(i=>console.log(i))
}; // <======
[1,2,3].demo();
And, it will work.
What's Happening?
The problem is that the [1,2,3] is being combined with the previous function (whitespace between them collapsed). In that circumstance, the [1,2,3] becomes just [3] and tries to read the [3] property from the function object. If you put the semi-colon at the end of the function definition, then that signals the end of the function definition statement and the [1,2,3] can then be interpreted as a static array definition.
It's all about context. In some circumstances in Javascript, [x] is a property access. In other circumstances, it's a static array definition. Without the semi-colon, it was getting interpreted as the property access instead of the array definition.
Remember that functions are objects in Javascript so they can have properties and can respond to [x] as a property access on them.
So, without the semi-colon at the end of the function you essentially have this:
Array.prototype.demo = function() {...}[3].demo();
Because the whitespace is collapsed between the end of your function and the [1,2,3]. That means the JS interpreter is expecting the [] to be a property name so it evaluates the statement inside the [] and in that context [1,2,3] turns into [3] (the 1,2,3 is evaluated which takes the value of the last comma separated statement which is 3).
More Detailed Explanation
Think of it like this:
// defines function
let f = function() {};
// attempts to read a property from that function object
let o = f [1,2,3]; // this is the same as let o = f[3]
// tries to call `.demo()` on the value read from that property
// which was undefined so this throws
o.demo();
Functions Are Objects
As a demonstration of how functions are objects, see this example that actually works!
// defines function
let f = function() {};
f[3] = {demo: function() { console.log("demo!!!");}}
// attempts to read a property from that function object
let o = f[1,2,3]; // this is the same as let o = f[3]
// tries to call `.demo()` on the value read from that property
// which was undefined so this throws
o.demo();
Here, we actually put a property on the [3] property of the function so when f[1,2,3] reads that property, it actually gets an object with a .demo() method on it so when we then call it, it all works. I'm not suggesting one would ever code this way, but I am trying to illustrate how f[1,2,3] is just reading the [3] property from the function object.
Good Reason Not to Leave out the Semi-colons
These odd cases are a good reason not to leave out semi-colons, even though you usually (but not always) get away with it.
The reason is that functions are objects, so if we don't add a semicolon, JavaScript will try to access a property on the function object, after it evaluates the comma operator like this:
function() { ... }[1,2,3].demo();
function() { ... }[3].demo();
undefined.demo();
For convenience while debugging, I think it would be nice to print some custom string, rather than the default Object that appears when logging an object to the console.
In the following example, see how an object called example is marked by Object when it is logged to the console, whereas window is marked by Window when it is logged to the console. I guessed that the __proto__["Symbol(Symbol.toStringTag)"] property might be the way to go, since window's is set to Window. That didn't work, but maybe I'm just using it wrong.
That's because you're using the Symbol wrong -- you were on the right track. Symbol.toStringTag is a special well-known Symbol used by Object#toString to give you the console output, specifically the tag you're after. You can't wrap it in a string as you've done, or else you'll be literally setting the "Symbol.toStringTag" property, not the actual Symbol:
const example = {
key: "value"
};
example.__proto__["Symbol.toStringTag"] = "Example";
console.log(example); //You set the literal "Symbol.toStringTag" property -- wrong
Instead, don't wrap it in quotes and actually set the Symbol:
const example = {
key: "value"
};
example.__proto__[Symbol.toStringTag] = "Example";
console.log(example);
Which produces (on Chrome):
I'm learning JS and quite confused about variables:
Short Story: How browsers determine the type of data under var tag, how they determine storage requirements for the type of data under var tag, what happens when two different types of data are assigned one-after-another to the same variable and why these variables're all warped up under var name? It would make more sense if JS had different types of data as integers, strings etc.
Long Story:
Normally, when we want to declare a variable, we define its type: integer, string or char etc. This way, we make sure enough storage is allocated for variable and most of the time, there're some special functions for that specific variable type. In JS, variables -and apparently functions too- are simply used under var name. So, we store anything under var name. My question is this: how browsers/JS compilers differentiate types of data in variables as string/char etc, how they decide the bit-length required for that data, and how they handle which functions will suit that data? What happens when I assign an integer to that variable first, then a string later? Also, wouldn't it be easier to define different types of variables?
I'm a beginner on JS, so go easy on me please. Cheers!
JavaScript variables are not typed but their values do have a type. The same variable can be assigned new values.
var i;
console.log(typeof i);
i = true;
console.log(typeof i);
i = 0;
console.log(typeof i);
i = "hello";
console.log(typeof i);
As far as the memory allocation is concerned, its nicely explained here.
Javascript is loosely-typed. Which means variables don't have a specific type for the developer. This doesn't mean a variable has no type for the system.
Let's look at the following example:
var string = "foo";
var number = 2;
var boolean = true;
var object = {rhymes: "on blue"};
console.log(typeof string); //string type
console.log(typeof number); //number type
console.log(typeof boolean); //boolean type
console.log(typeof object); //an object
//you can also "reassign" a new type to a variable just by reassigning a new value:
var string = 2;
console.log(typeof string) //number type
Here you see that the system does in fact know the type of the variable.
The system also doesn't care that much about the type. Like a string or object doesn't have a pre-defined bit length because their value and/or length is arbitary.
This, let's call it feature, is a great benefit of Javascript but it can be a pain in the a** as well.
If you want to use the best part of both, loosely-typed and strongly-typed (if you have to define a type) you should learn about Typescript. This is just a superset of Javascript that compiles to plain Javascript but offers types.
This is really broad, so I will break it down.
How browsers determine the type of data under var tag
The JavaScript Runtime Engine can determine the variable type by the type assigned, either a literal or another variable. This is different than a compiled language that requires type information at compile time, before runtime.
How they determine storage requirements for the type of data under var tag
This is partially defined in the spec, partially implementation specific. For example var i = 0 is a number but how that is implemented depends on the JavaScript Runtime Engine.
What happens when two different types of data are simultaneously assigned to the same variable and why these variables're all warped up under var name?
You actually can't assign at the same time, but you can assign one after the other. When you assign the second time, the value and the type are changed!
var o = 5; // variable 'o' is a number with value 5
o = 'Hello'; // variable 'o' is a string with value 'Hello'
o = {foo: 'bar'}; // variable 'o' is an object with value {foo:'bar'}
It would make more sense if JS had different types of data as integers, strings etc.
JavaScript does have different types!
JavaScript is a loosely typed or a dynamic language. That means you don't have to declare the type of a variable ahead of time. The type will get determined automatically while the program is being processed.
Example:
var o = 5;
console.log(typeof o); // number
o = 'Hello';
console.log(typeof o); // string
o = {foo: 'bar'};
console.log(typeof o); // object
I strongly recommend reading the MDN Data Structures docs for more info.
Variable's in JS are untyped manually.
As #DontVoteMeDown mentionned; they are dynamically typed : https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures
This is your responsibility as a developer to manage your types and control on your JS variables.
I am trying to access a certain member in a JavaScript object. In order to do this, I need to try out a couple of key values.
For example, Object['text/html'] which will give me an export link for a HTML document. However, not every object of this type will have a text/html key pair value.
In Python I would solve this problem using a Try-Catch block, with the KeyError exception. If I can do something similar in javascript, as in use an exception in a Try-Catch block, that would be great.
However, if alternatives exists instead of try catch blocks, that do achieve the same end goal, I would like to know about them as well.
EDIT:
I would prefer to use an exception over using functions. I do this because the text/html key might not be there, but it should be there. An exception seems more appropriate for this scenario
Javascript doesn't generate an exception when reading or writing a property that doesn't exist. When reading it, it just returns undefined. When writing it, it just creates the property.
You could create your own function that tests to see if the property exists and throws an exception if it does not (but you'd have to call that function whenever), but JS doesn't make an exception out of that on it's own like you are asking for.
If you want to test if a key exists on an object in javascript, you can use this construct with the in operator:
var obj = {};
var key = "test";
if (key in obj) {
// key exists
} else {
// key doesn't exist
}
If you try to read a key that doesn't exist, you will get undefined as the value.
var obj = {};
var value = obj.test;
alert(value === undefined);
The in operator does a better job of telling you whether the key exists that testing for undefined because undefined is a legal value for a key that exists.
In many cases, where you control the values that the keys have and a key that is present will never have a falsey value, you can also just check if the key has a truthy value:
var obj = {};
var obj.test = "hello";
if (obj.test) {
// key exists and has a truthy value
}
If you want to make sure that the object itself has the property and not any prototype that it is inheriting from, then you can do this:
var obj = {};
var obj.test = "hello";
if (obj.hasOwnProperty(test)) {
// key exists on the object itself (not only on the prototype)
}
Read this!
The accepted answer is correct however omits some points.
1) Accessing nested object
Like someone pointed out in the comment, Javascript returns undefined when the key doesn't exists in the object.
However, if you need to access an object inside an object (or an Array, or a function), well this break.
let a = {};
let userName = 'js'
let data = a.response[userName];
Cuz you will received actually a TypeError, basically because we are trying to read a property of undefined, which doesn't have any.
VM187:2 Uncaught TypeError: Cannot read properties of undefined (reading 'js')
at <anonymous>:2:22
2 Answering the question
The Python principle "Ask forgiveness not permission" - explain is actually for the most part working well in Javascript (and PHP, you didn't ask but well..). There are for sure some difference, or some situation where the difference is important, but for most use cases is the same
So this is how you would do it:
try {
let data = a.key1.key2['whatever'].nested.damn.object;
console.log(data)
} catch (error) {
let data = "noope";
console.log(data);
}
As you can see, in Javascript you don't really care about the error type, (for the most part, sure other situation you should case). Is almost like anything is in a Python's
try:
a = "hello" + 1 + {} + [] # crazy stuff here
except BaseException as bleh:
print(str(bleh))
Documentatin
MDN Working with objects
How do I check if an object has a key in JavaScript? [duplicate]