Actual Error Code
JSC_INEXISTENT_PROPERTY
Summary
I get this error for the code listed and commented below.
I make the call like this. o_p.page holds user input and one of the properties is indeed tag
Mo.AppBAdder.image_element = vDomBMAdd(o_p.page);
o_p.page is populated by calling the object which hold user input like this:
o_p.page = text_object.getArray();
Is there a way I can do this so Google Closure does not feel the property does not exist?
Setting options is O.K. Also, I don't mind modifying the code a bit if needed.
The constructor for text reads in the user input like this:
Su.text = function (form_elements) {
this.text_object = {};
var key;
for (key in form_elements) { //*u
if (form_elements.hasOwnProperty(key)) {
this.text_object[form_elements[key].name] = form_elements[key].value;
}
}
return this;
};
Snippet of Code
function vDomBMAdd(bookmark_object) {
var link_element = document.createElement('a'),
image_element = document.createElement('img'),
page_element = $a('#' + bookmark_object.tag + '_page'), // error here - inexistent property
Reference
Inexistent means same thing as nonexistent
You have two options: create an extern file that declares the 'tag' property or, perhaps more appropriately given how the property is defined, use a quoted property access:
bookmark_object['tag']
Both of these approaches allow you to access "external" properties and are both compatible with ADVANCED optimizations but using an extern file allows you to declare the expected type of the value held by the property and thus provides better type checking.
Related
I have a Angular service and in it I have variables like this:
export class MyService {
someVariableA = 1;
someParams = {
someVariableB,
otherVariable: this.someVariableA
};
}
and in a component I set the 'someVariableA' to 3
this.myService.someVariableA = 3;
and I want 'otherVariable' to get that value 3 as well, but it doesn't. It remains 1 when I go to get the value.
let v = this.myService.someParams.otherVariable;
Is it possible to set 'otherVariable' this way or any other way via 'someVariableA'?
As #Zulwarnain answered, 1 is a number or a primitive data type. Primitive data types in javascript are passed by value, not by reference which you seem to be expecting here.
An easy fix for this is to assign a function to otherVariable instead. Now just invoke the function someParams.otherVariable() and it will return the value of someVariableA. No need to make this complicated.
export class SingletonService {
public someVariableA = 1;
public someParams = {
otherVariable: () => this.someVariableA
};
}
This is basic javascript with multiple sources covering the subject.
https://codeburst.io/explaining-value-vs-reference-in-javascript-647a975e12a0
I concur with this answer that you will have a better time if you use a reference type like an object/array instead of a primitive value type like a number. By adding one layer of indirection (e.g., someVar = 123 becomes someVar = {value: 123}) you could very easily get similar functionality to what you're seeking.
If, however, your use case requires an object's property to directly act like a reference to a primitive value type stored somewhere else, you can get this behavior by implementing the property as a getter and setter pair. It's more complicated, but it acts the way you want.
Here's an example:
class MyService {
someVariableA = 1;
someParams: {
someVariableB: number;
otherVariable: number;
};
constructor() {
this.someVariableA = 1;
const that = this;
this.someParams = {
someVariableB: 2,
get otherVariable() {
return that.someVariableA
},
set otherVariable(val: number) {
that.someVariableA = val;
}
}
}
}
Note that in order for the otherVariable getter and setter to be able to access the right context, I had to move the code into the constructor and copy this into a new variable I called that. The this context of a getter/setter refers to the object it's a member of, and not some this from an outer scope.
Let's make sure it works:
const ms = new MyService();
ms.someVariableA = 100;
console.log(ms.someParams.otherVariable); // 100
ms.someParams.otherVariable = -5;
console.log(ms.someVariableA); // -5
Looks good; changes to ms.someVariableA are immediately reflected in ms.someParams.otherVariable, and vice versa. All right, hope that helps; good luck!
Playground link to code
You are assigning the value type this will not work like you want. you need to assign reference type
obj ={someVariableA : 1};
someParams = {
otherVariable: this.obj
};
in the above code, if you change the value of obj.someVariableA it will also change the value of someParams.otherVariable
I am expexting that you have knowledge about reference type and value types variables
click here for demo
I don't think you want to do that. I believe you are getting a new instance of the service each time you call it, so the variables get reset.
you might want to set that variable in localStorage instead, and then have the service retrieve it from localStorage. That way it will always be getting whatever it was last set to.
or just pass that variable into your service call, instead of trying to use a local service variable.
Edit: The reason I am doing the below process is so I can store the reference to the getter/setter in a dictionary. This allows me to have the key of my dictionary be an ID of an HTML element. Thus, if a property is changed in the HTML, I can do something like:
var propData = allMyGetterSetters[e.originalTarget.id];
propData.getSet.set(propData.obj, e.originalTarget.value);
This also allows me to do a loop and update all the HTML, should my logic change it.
I need to store a reference to the getter/setters of a few properties of one of classes. I've managed to do this with the following code:
Object.getOwnPropertyDescriptor(Object.getPrototypeOf(myClassObj.position), "x");
For simplicity, since I have to do this several times, I have the following method:
_makeGetSetObj(object, property){
return {
getSet: Object.getOwnPropertyDescriptor(Object.getPrototypeOf(object), property),
obj: object
};
}
And subsequent code would look something like this:
var xPos = this._makeGetSetObj(myClassObj.position, "x");
// ...
xPos.getSet.get(xPos.obj);
All of this works perfectly.
However, I now need to store a reference to a getter/setter of my myclassObj object. However, the following does not work
this._makeGetSetObj(myClassObj, "name");
This actually gives me an error that name does not exist on the object. I've managed to figure out that the problem is my inheritance, which looks something like this
|-- BaseClass
|-- MyClass
|-- DerivedClass
The problem seems to be that myClassObj is actually an object of type DerivedClass, which doesn't have the property name on it.
So, if I do this:
this._makeGetSetObj(myClassObj.__proto__, "name");
It works to get the prototype, but when I try to use it as shown above (with my xPos example), it fails because it seems to still be storing an reference in obj as a DerivedClass object.
If I pull outside of my method, and try things manually, this works:
var name = Object.getOwnPropertyDescriptor(Object.getPrototypeOf(myClassObj.__proto__), "name");
name.get(myClassObj);
This obviously breaks my method though, as one part requires the __proto__ while the other part does not.
So, my question is: Is there a way to keep my current logic, or will I have to create a special method for the places with the described problem?
Thanks.
Hardcoded prototype doesn't smell good. Prototype chains should always be iterated:
let proto = obj;
let descriptor;
do {
descriptor = Object.getOwnPropertyDescriptor(proto, prop);
} while (!descriptor && proto = Object.getPrototypeOf(proto))
...
This functionality has been already implemented by Reflect. Instead of parsing descriptors manually, it may be
const getSet = {
get: () => Reflect.get(obj, prop),
set: (val) => { Reflect.set(obj, prop, val) }
};
Or... just
const getSet = {
get: () => obj[prop],
set: (val) => { obj[prop] = val }
};
Because this is what happens when accessors are called directly.
I am creating an application that stores a unique object based on url of every page visited in Simple-Storage.
var ss = require("sdk/simple-storage");
ss.storage[naming()] = new entryConstructor;
naming() is a function that will churn out a custom name for each object.
You can usually declare variables as a property global object(Window). Is this possible for storage?
I don't really understand what's the question is. Is it :
can I create a variable that directly points to ss.storage ?
or can I access a storage member by using a function returning the name of that member ?
Short answer : Yes, you can and yes you can !
You can of course write without problem :
var ss = require("sdk/simple-storage");
var storage = ss.storage;
/* using 'storage' doesn't matter as long as you don't have identifyers collision */
storage[naming()] = new entryConstructor();
// and you still can refer to storage using ss.storage
ss.storage is much like a javascript object. You just can't add functions members to it (if I'm not mistaken).
If you have a function that returns a string, you can of course access/set a storage property/entry (that's how I like to name it) using that function, assuming the returned value is a javascript compliant member name :
ss.storage[naming()] = new entryConstructor();
where :
function naming() {
/* returns a valid javascript object property names */
// building of the property name here...
}
and entryConstructor is one of the allowed types (presumably an object of your own creation) I like to think of storage entries as JSON serializable datas.
Be carefull when you set entries in ss.storage. You should check for the existence of the entry before attempting to set its value in case you want persistent datas across multiple sessions. If you start by setting values each time a session has begun, old values registered on previous sessions would get lost forever :
let name = naming();
let myEntry;
if (ss.storage.hasOwnProperty(name)) {
// use stored value...
myEntry = ss.storage[name];
} else {
// create value...
myEntry = new entryConstructor()...
}
// make edits... then :
ss.storage[name] = myEntry;
// or handle update on user input, contentScript detach or exports.onUnload
Side notes :
carefull of syntax errors (missing parenthesis, etc.)
When you talk about property global object (window), you're actually talking about context.
I'm a bit of a newbie in Javascript. I was looking through a bit of Coffeescript code for an Atom package, and I stumbled upon this piece of code:
loadProperties: ->
#properties = {}
fs.readFile path.resolve(__dirname, '..', 'completions.json'), (error, content) =>
{#pseudoSelectors, #properties, #tags} = JSON.parse(content) unless error?
return
I was a bit confused by the last line {#pseudoSelectors, #properties, #tags} = JSON.parse(content) unless error? because it seems like it assigns multiple values from the parsed JSON content. In my confusion, I decided to convert this back to Javascript using js2Coffee, and I ended up with the following:
function() {
this.properties = {}; // make list of properties (global to provider)
return fs.readFile(path.resolve(__dirname, '..', 'completions.json'), (function(_this) { //load completions.json (using path module)
return function(error, content) { // edit: nvm, js2coffee's fault. not sure why they wrapped the call back in another anonymous function, but this is a node stream callback
var ref;
if (error == null) { // if there are no errors
ref = JSON.parse(content), _this.pseudoSelectors = ref.pseudoSelectors, _this.properties = ref.properties, _this.tags = ref.tags;
}
};
})(this));
This code is a bit more understandable than the above. I can see that ref is assigned the object parsed from the content stream, and is then used to assign the other variables with their designated data. My question is, how does this type of assignment work? In Coffeescript, how does the preprocessor know where to assign the values, and in what order to assign them in?
By inspecting completions.json, the data is not in the order in which the assignments occur.
This is known as Destructuring Assignment.
To make extracting values from complex arrays and objects more convenient, CoffeeScript implements ECMAScript Harmony's proposed destructuring assignment syntax. When you assign an array or object literal to a value, CoffeeScript breaks up and matches both sides against each other, assigning the values on the right to the variables on the left.
CoffeeScript interprets an object or array on the left side of an = as a pattern, matching the names used...
#pseudoSelectors
#properties
#tags
...to properties or indices within the value being assigned:
JSON.parse(content).pseudoSelectors
JSON.parse(content).properties
JSON.parse(content).tags
(Defining the additional ref to avoid reevaluating JSON.parse(content) for each.)
As for order, CoffeeScript will generally use the order they're mentioned within the assignment. Moving #pseudoSelectors to the 3rd property in the pattern will be echoed in the generated JavaScript.
{#properties, #tags, #pseudoSelectors} = JSON.parse(content) unless error?
var ref;
if (typeof error === "undefined" || error === null) {
ref = JSON.parse(content),
this.properties = ref.properties,
this.tags = ref.tags,
this.pseudoSelectors = ref.pseudoSelectors; // now last
}
Though, JavaScript Objects, like the result of JSON.parse(content), aren't enforced as sorted data structures. If you need to ensure the order of the values, you'll have to instead use an Array.
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]