ES5 Defining Unchangeable Arrays / Property Values - javascript

When defining an array as a property of an ES5-style object, I want to make it so the property's value cannot be changed.
'use strict';
var global = Object.create(Object.prototype, {
names: {
value: ['Barney', 'Trogdor'],
writable: false
}
});
global.names.push('Jackson'); // I expected a read-only error here
console.log(global.names[2]); // >> Jackson
global.names = ['Ooga', 'Booga']; // >> TypeError: "names" is read-only
It seems that I have only protected against property assignment.
Is there any way to protect against stuff like Array.push() that modifies my "unwritable" array?

Object.seal() seems to work.
'use strict';
var global = Object.create(Object.prototype, {
names: { value: Object.seal(['Barney', 'Trogdor']) }
});
global.names.push('Jackson'); // >> TypeError: global.names.push(...) is not extensible
EDIT: Actually, nevermind.
In the previous example, were I to append the following line of code:
global.names[0] = 'Jackson'; // Still works
I believe Object.freeze() was what I actually wanted.
var global = Object.create(Object.prototype, {
names: { value: Object.freeze(['Barney', 'Trogdor']) }
});
global.names.push('Jackson'); // >> TypeError: global.names.push(...) is not extensible
global.names[0] = 'Jackson'; // >> TypeError: 0 is read-only
global.names = ['Jackson']; // >> TypeError: "names" is read-only

Once all the data is loaded, why not overwrite the push method on what you have:
global.names.push = function () {return false}

Related

unable to delete javsacript object property

I created a object using Object.create in the following way.
var myObject = {
price: 20.99,
get_price: function() {
return this.price;
}
};
var customObject = Object.create(myObject, {
price: {
value: 100
}
}
);
console.log(delete customObject.price);
I tried to delete customObject price using
delete customObject.price returns false
The second parameter to Object.create() is interpreted exactly the same way as the second parameter of Object.defineProperties(). That false is being returned from the delete expression because the property you're deleting is an own non-configurable property and you're not in "strict" mode. In "strict" mode you'd get an exception.
If you created the property with the "configurable" flag set to true, you would get true from the delete:
var customObject = Object.create(myObject, {
price: {
value: 100,
configurable: true
}
}
);
Or you can create the object and just set the property with a simple assignment:
var customObject = Object.create(myObject);
customObject.price = 100;
Such properties are always "born" as configurable.
You can use Object.getOwnPropertyDescriptor(customObject, "price") to check whether the property you're deleting is configurable:
if (Object.getOwnPropertyDescriptor(customObject, "price").configurable)
delete customObject.price;

Cannot convert null or undefined to object when using hasOwnProperty

I am trying to use hasOwnProperty in a more elegant way.
I have this code here, which works fine:
var obj = {
a: 2,
b: 7,
bamboo: 22
};
var keys = Object.keys(obj).filter(key => obj.hasOwnProperty(key));
// keys: [ "a", "b", "bamboo" ]
However when I try to pass obj.hasOwnProperty as shorthand (which should work), it doesn't behave how I expect.
var keys = Object.keys(obj).filter(obj.hasOwnProperty);
// Uncaught TypeError: Cannot convert undefined or null to object
// at hasOwnProperty (<anonymous>)
To ensure that the parameter is passed to hasOwnProperty correctly, I have set up this test case:
var testFilter = (key) => {
console.log(key);
return true;
};
Object.keys(x).filter(testFilter);
a, b and bamboo are all logged to the console, so I know that it is passing the parameters correctly.
Why does the behaviour not work correctly for hasOwnProperty?
object.hasOwnProperty takes the object as its this value. When you do direct calls, this is implicitly provided by looking at what object the method is called on, but with indirect calls, you have to specify this manually:
var obj = { foo: 3 };
var func = obj.hasOwnProperty;
console.log(func('foo')); // TypeError: Cannot convert undefined or null to object
One of the easiest way to do this is with function.bind, like this:
var obj = { foo: 3 };
var func = obj.hasOwnProperty.bind(obj); // bind `this` of function to `obj`
console.log(func('foo')); // = true
For a correct callback, you need to bind the object to hasOwnProperty and then use the returned function.
var obj = {
a: 2,
b: 7,
bamboo: 22
},
keys = Object.keys(obj).filter({}.hasOwnProperty.bind(obj));
console.log(keys);

Getting "Cannot set property 'items' of undefined" while adding child object in JavaScript objects

I am trying to add an array onto an object but getting "Cannot set property 'items' of undefined" error. Below is what I am trying to achieve
$rootScope.jobs.items = [];
$rootScope.jobs.item = {};
$rootScope.jobs.after = 0;
$rootScope.jobs.noOfRecord = 10;
$rootScope.jobs.busy = false;
$rootScope.jobs.finish = false;
where $rootScope is a valid object and set up by angularjs and its normal to add objects to it. $rootScope doesn't have any issues.
I have gone through the answers at Why I get Cannot set property 'na0' of undefined error? but it's different.
You need to define the $rootScope.jobs object first
$rootScope.jobs = {
items : [],
item: {},
after: 0,
noOfRecord: 10,
busy: false,
finish:false
};
You need to define jobs e.g.
$rootScope.jobs = {} ;
It is exactly what the error message is saying. $rootScope.jobs is undefined.
You are trying to add the property items to an undefined object.
A simple fix would be to init the jobs on the $rootScope:
$rootScope.jobs = {};

How to check if object property exists with a variable holding the property name?

I am checking for the existence of an object property with a variable holding the property name in question.
var myObj;
myObj.prop = "exists";
var myProp = "p"+"r"+"o"+"p";
if(myObj.myProp){
alert("yes, i have that property");
};
This is undefined because it's looking for myObj.myProp but I want it to check for myObj.prop
var myProp = 'prop';
if(myObj.hasOwnProperty(myProp)){
alert("yes, i have that property");
}
Or
var myProp = 'prop';
if(myProp in myObj){
alert("yes, i have that property");
}
Or
if('prop' in myObj){
alert("yes, i have that property");
}
Note that hasOwnProperty doesn't check for inherited properties, whereas in does. For example 'constructor' in myObj is true, but myObj.hasOwnProperty('constructor') is not.
You can use hasOwnProperty, but based on the reference you need quotes when using this method:
if (myObj.hasOwnProperty('myProp')) {
// do something
}
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/hasOwnProperty
Another way is to use in operator, but you need quotes here as well:
if ('myProp' in myObj) {
// do something
}
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/in
Thank you for everyone's assistance and pushing to get rid of the eval statement.
Variables needed to be in brackets, not dot notation. This works and is clean, proper code.
Each of these are variables: appChoice, underI, underObstr.
if(typeof tData.tonicdata[appChoice][underI][underObstr] !== "undefined"){
//enter code here
}
For own property :
var loan = { amount: 150 };
if(Object.prototype.hasOwnProperty.call(loan, "amount"))
{
//will execute
}
Note: using Object.prototype.hasOwnProperty is better than loan.hasOwnProperty(..), in case a custom hasOwnProperty is defined in the prototype chain (which is not the case here), like
var foo = {
hasOwnProperty: function() {
return false;
},
bar: 'Here be dragons'
};
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/hasOwnProperty
To include inherited properties in the finding use the in operator: (but you must place an object at the right side of 'in', primitive values will throw error, e.g. 'length' in 'home' will throw error, but 'length' in new String('home') won't)
const yoshi = { skulk: true };
const hattori = { sneak: true };
const kuma = { creep: true };
if ("skulk" in yoshi)
console.log("Yoshi can skulk");
if (!("sneak" in yoshi))
console.log("Yoshi cannot sneak");
if (!("creep" in yoshi))
console.log("Yoshi cannot creep");
Object.setPrototypeOf(yoshi, hattori);
if ("sneak" in yoshi)
console.log("Yoshi can now sneak");
if (!("creep" in hattori))
console.log("Hattori cannot creep");
Object.setPrototypeOf(hattori, kuma);
if ("creep" in hattori)
console.log("Hattori can now creep");
if ("creep" in yoshi)
console.log("Yoshi can also creep");
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/in
Note: One may be tempted to use typeof and [ ] property accessor as the following code which doesn't work always ...
var loan = { amount: 150 };
loan.installment = undefined;
if("installment" in loan) // correct
{
// will execute
}
if(typeof loan["installment"] !== "undefined") // incorrect
{
// will not execute
}
A much more secure way to check if property exists on the object is to use empty object or object prototype to call hasOwnProperty()
var foo = {
hasOwnProperty: function() {
return false;
},
bar: 'Here be dragons'
};
foo.hasOwnProperty('bar'); // always returns false
// Use another Object's hasOwnProperty and call it with 'this' set to foo
({}).hasOwnProperty.call(foo, 'bar'); // true
// It's also possible to use the hasOwnProperty property from the Object
// prototype for this purpose
Object.prototype.hasOwnProperty.call(foo, 'bar'); // true
Reference from MDN Web Docs - Object.prototype.hasOwnProperty()
there are much simpler solutions and I don't see any answer to your actual question:
"it's looking for myObj.myProp but I want it to check for myObj.prop"
to obtain a property value from a variable, use bracket notation.
to test that property for truthy values, use optional
chaining
to return a boolean, use double-not / bang-bang / (!!)
use the in operator if you are certain you have an object and only want to check for the existence of the property (true even if prop value is undefined). or perhaps combine with nullish coalescing operator ?? to avoid errors being thrown.
var nothing = undefined;
var obj = {prop:"hello world"}
var myProp = "prop";
consolelog( 1,()=> obj.myProp); // obj does not have a "myProp"
consolelog( 2,()=> obj[myProp]); // brackets works
consolelog( 3,()=> nothing[myProp]); // throws if not an object
consolelog( 4,()=> obj?.[myProp]); // optional chaining very nice ⭐️⭐️⭐️⭐️⭐️
consolelog( 5,()=> nothing?.[myProp]); // optional chaining avoids throwing
consolelog( 6,()=> nothing?.[nothing]); // even here it is error-safe
consolelog( 7,()=> !!obj?.[myProp]); // double-not yields true
consolelog( 8,()=> !!nothing?.[myProp]); // false because undefined
consolelog( 9,()=> myProp in obj); // in operator works
consolelog(10,()=> myProp in nothing); // throws if not an object
consolelog(11,()=> myProp in (nothing ?? {})); // safe from throwing
consolelog(12,()=> myProp in {prop:undefined}); // true (prop key exists even though its value undefined)
// beware of 'hasOwnProperty' pitfalls
// it can't detect inherited properties and 'hasOwnProperty' is itself inherited
// also comparatively verbose
consolelog(13,()=> obj.hasOwnProperty("hasOwnProperty")); // DANGER: it yields false
consolelog(14,()=> nothing.hasOwnProperty("hasOwnProperty")); // throws when undefined
obj.hasOwnProperty = ()=>true; // someone could overwrite it
consolelog(15,()=> obj.hasOwnProperty(nothing)); // DANGER: the foolish overwrite will now always return true
consolelog(16,()=> Object.prototype.hasOwnProperty.call(obj,"hasOwnProperty")); //😭 explain?!
consolelog(17,()=> Object.hasOwn(obj,"hasOwnProperty")); //😭 explain?!
function consolelog(num,myTest){
try{
console.log(num,myTest());
}
catch(e){
console.log(num,'throws',e.message);
}
}
You can use hasOwnProperty() as well as in operator.
Using the new Object.hasOwn method is another alternative and it's intention is to replace the Object.hasOwnProperty method.
This static method returns true if the specified object has the indicated property as its own property or false if the property is inherited or does not exist on that object.
Please not that you must check the Browser compatibility table carefully before using this in production since it's still considered an experimental technology and is not fully supported yet by all browsers (soon to be though)
var myObj = {};
myObj.myProp = "exists";
if (Object.hasOwn(myObj, 'myProp')){
alert("yes, i have that property");
}
More about Object.hasOwn - https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/hasOwn
Object.hasOwn browser compatibility - https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/hasOwn#browser_compatibility
Several ways to check if an object property exists.
const dog = { name: "Spot" }
if (dog.name) console.log("Yay 1"); // Prints.
if (dog.sex) console.log("Yay 2"); // Doesn't print.
if ("name" in dog) console.log("Yay 3"); // Prints.
if ("sex" in dog) console.log("Yay 4"); // Doesn't print.
if (dog.hasOwnProperty("name")) console.log("Yay 5"); // Prints.
if (dog.hasOwnProperty("sex")) console.log("Yay 6"); // Doesn't print, but prints undefined.
Working for me.
if (typeof receviedData?.d?.heartbeat_interval != "undefined") {
}
In the answers I didn't see the !! truthiness check.
if (!!myObj.myProp) //Do something

read-only property

Is it possible to make a javascript object property read-only? I want to set a property that cannot be modified...
It's possible, but expensive. You can do it by having a truly private member variable and then providing an accessor function:
var NiftyThing = function() {
var trulyPrivateVariable;
trulyPrivateVariable = 5; // For instance
this.accessorFunction = function() {
return trulyPrivateVariable;
}
};
That works because the accessor function is a closure over the var. The cost is that each instance has its own copy of the accessor function.
EDIT: Usage:
var n = new NiftyThing();
alert(n.trulyPrivateVariable);
// Alerts "undefined"
alert(n.accessorFunction());
// Alerts "5"
See Private Member Variables in JavaScript for more.
You can implement something like this, making use of Object.defineProperty():
function blockProperties(object, properties) {
"use strict";
// If not properties passed, then use the already defined ones:
if (typeof properties === "undefined") {
properties = object;
}
// Loop trough the properties
for (var property in properties) {
if (properties.hasOwnProperty(property)) {
// Make property read-only
Object.defineProperty(object, property, {
value: properties[property],
writable: false,
configurable: false,
enumerable: false
});
}
}
return object;
}
var someObject = {};
blockProperties(someObject, {
propertie1: "someValue",
propertie2: "someOtherValue"
});
someObject.propertie1 = "this doesn't change anything";
console.log(someObject.propertie1); // Output: "someValue"
// Because "window" is also an object, you can set an only-read global var:
blockProperties(window, {
onlyReadVariable: "onlyReadValue"
});
I agree with the answer, and would like to note that some JavaScript frameworks like bob.js support such built-in mechanisms:
var obj = { };
//declare read-only property.
bob.prop.namedProp(obj, 'name', 'Bob', true);
//declare read-write property.
bob.prop.namedProp(obj, 'age', 1);
//get values of properties.
console.log(bob.string.formatString('{0} is {1} years old.', obj.get_name(), obj.get_age()));
//set value of read-write property.
obj.set_age(2);
console.log(bob.string.formatString('Now {0} is {1} years old.', obj.get_name(), obj.get_age()));
//cannot set read-only property of obj. Next line would throw an error.
// obj.set_name('Rob');
//Output:
//========
// Bob is 1 years old.
// Now Bob is 2 years old.
However, if you have special needs regarding property, such as specific get accessor implementation needs, then better define a function which gets the value as you need it.
-
Tengiz

Categories