in javascript, when constructing an object, unable to use other objects' methods - javascript

when constructing an object using methods from other objects as an attribute name get Syntax Error: Unexpected token . - cannot find correct syntax
var R = function(a) { this.arg = a; };
R.prototype.name = function() { return this.arg; }
var r1 = new R('abc');
var name1 = r1.name(); // => "abc"
var o1 = { 'abc': r1 } // this works with constant
var o2 = { name1: r1 } // does not work with variable (see answer)
var o3 = { r1.name(): r1 } // this fails - syntax
var o4 = { 'abc': r1.name() } // this works
have tried { (r1.name()): r1 }, but that fails as well.
please note that strings and integers are evaluated as barewords whereas methods and variables are not:
var o5 = { e.1: 123 } // fails
var o6 = { 'e.1': 123 } // succeeds
var o7 = { 1: 123 } // succeeds
var o8 = { '1': 123 } // same as o7

var o2 = { name1: r1 } // this works with variable
This has the same meaning as:
var o2 = { 'name1': r1 }
In other words, it's still treating name1 as a literal string. The key in an object literal must be a constant or a so-called "bareword" -- this is a restriction of the language. Variables and function invocations cannot be used as keys in object literals (but they can be used as values). Using variables will appear to work, but the variable name will be used as the key and not the variable's value.
You will have to do something like:
var o2 = {};
o2[name1] = r1;
var o3 = {};
o3[r1.name()] = r1;

var o4 = { 'abc', r1.name() }
this one should be:
var o4 = { 'abc': r1.name() }

You could create your own property setter
function setProperty (prop,val,obj) {
if (typeof prop === "undefined" || typeof val === "undefined") return undefined;
if (typeof obj === "undefined") obj = {};
obj[prop] = val;
return obj;
}
// use 1
var o1 = setProperty(r1.name(),r1);
// use 2
var o2 = {};
setProperty(r1.name(),r1,o2);

Related

How I can convert any JavaScript variable to Uint8Array?

I need to send the binary representation of a varibale trough websocket, the problem is the variable can be string, can be intiger, can be anything.
function send(bar) {
var foo = new TextEncoder('utf-8').encode(bar); // Works if 'bar' is string
var foo = new Int32Array([bar]).buffer; // Works if 'bar' is integer
}
How I can convert any JavaScript variable to Uint8Array ?
Objective:
send('Hello') -> 0x48 0x65 0x6C 0x6C 0x6F
send(123) -> 0x7B
Note: I don't have control of the server side
Since WebSockets support sending string data,
let socket = new WebSocket("wss://...");
socket.send(JSON.stringify(123));
socket.send(JSON.stringify("wasd"));
socket.send(JSON.stringify([1, 2, 3]));
and then JSON.parse it on accepting side
socket.onmessage = function(event) {
const data = JSON.parse(event.data)
};
Thank you Pointy, I solve it by checking the datatype before conversion.
// 123 -> ["123"]
// "123" -> ["123"]
// True -> ["1"]
// False -> ["0"]
function convert_var_to_uint8array_string(bar) {
if(typeof bar === 'string') { var foo = new TextEncoder('utf-8').encode(bar); }
else if(typeof bar === 'number') { var foo = new TextEncoder('utf-8').encode(bar); }
else if(typeof bar === 'boolean') { var tmp = 0; if(bar) tmp = 1; var foo = new TextEncoder('utf-8').encode(tmp); }
else { var foo = new TextEncoder('utf-8').encode('undefined'); }
return foo;
}

Javascript Closure code

I have a question about this fonction:
var MyObject3 = function (a, b) {
var obj = { myA : a, myB : b } ;
obj.foo = function () { return obj.myA + obj.myB ; } ;
obj.bar = function (c) { return obj.myA + c ; } ;
return obj ;
} ;
obj.foo and obj.bar are closures(what i understand). I write first:
obj3 = MyObject3(1, 2) ;
and the result is: {"myA" :1,"myB" :2}. This is OK. I try to change the value of obj3.myA : > obj3.myA = 4 ; obj3 ; and the result is : {"myA" :4,"myB" :2} . What I don't understand is: why > obj3.foo() ; returns 6? obj3.foo() gives 6 as a result ? obj3.foo() is supposed to be a closure isn'it ? its result should be;3 ?
Function MyObject3 defines a variable in its scope, which refers to a newly created object:
var obj = { myA : a, myB : b } ;
All references to obj inside of that function's scope refer to that object. Than the object is returned by the function and saved to the variable obj3. obj inside of the MyObject3 scope and obj3 in the global scope thus refer to the same object.
In javascript, primitives (e.g. numbers, booleans, strings) are passed by value, whereas objects are passed by reference. Which means that:
var val1 = 1;
var val2 = val1;
val1 = 4;
console.log(val2); // will log 1
// but:
var obj1 = {foo: 'bar'};
var obj2 = obj1;
obj1.foo = 'baz';
console.log(obj2.foo); // will log 'baz'

Create a stand alone Javascript Object which inherits from parent but not from child to parent

My goal is to have otherFoo inherit from foo, but then not inherit back up to the parent. I've tried a few angles with Object.create but it keeps inheriting back to the parent.
var foo = { "bar": {"data1":"02", "data2":"03"}, "otherBar":"09"};
var otherFoo = {};
otherFoo.bar = foo.bar;
otherFoo.bar.data1 = "04";
I want the end result to be
// foo = { "bar": {"data1":"02", "data2":"03"}};
// otherFoo = { "bar": {"data1":"04", "data2":"03"}};
Here is a JSFiddle for Convenience
Do you mean Object.assign() ?
let foo = { "bar": {"data1":"02", "data2":"03"}, "otherBar":"09"};
let otherFoo = Object.assign({}, foo);
foo.otherBar = 10;
console.log(foo);
console.log(otherFoo);
You could try using a class:
function template(data1) {
this.data = { "bar": {"data1": typeof data1 !== 'undefined' ? data1: '02', "data2":"03"}};
}
var foo = new template();
var otherFoo = new template('04');
console.log(foo.data);
console.log(otherFoo.data);
Close to Talha's answer, but figured i'd just go ahead and post it (as it mimicks your example almost exactly above on what you want the data represented like)
const bar = function(data){
this.bar = data;
}
let foo = new bar({"data1":"02", "data2":"03"})
let otherFoo = new bar({"data1":"04", "data2":"03"})
console.log(foo)
console.log(otherFoo)
If you can use Object spread operator:
var foo = { "bar": {"data1":"02", "data2":"03"}, "otherBar":"09"};
var { otherBar, ...bar } = foo
foo = bar
var fooBar = {
bar: { ...foo.bar, data2: "04" }
}
Otherwise you need a deep clone of your object.
Here's a function that can deep clone any object, including cyclical objects. It also maintains cyclical references as they are in the original object, without referencing any values from the original, except for values in the prototype chain:
function clone (object, objects = new WeakMap()) {
// this will omit copying primitives
if (typeof object !== 'object' && typeof object !== 'function' || object === null) {
return object;
}
if (objects.has(object)) {
return objects.get(object);
}
const proto = Object.getPrototypeOf(object);
const descriptors = Object.getOwnPropertyDescriptors(object);
const copy = typeof object === 'function'
? object.call.bind(object)
: Object.create(proto);
objects.set(object, copy);
Object.values(descriptors).forEach(descriptor => {
if ('value' in descriptor) {
descriptor.value = clone(descriptor.value, objects);
}
});
return Object.defineProperties(copy, descriptors);
}
let foo = { bar: { data1: '02', data2: '03' }, otherBar: '09' };
class Test {
constructor (...args) { this.args = args; }
cool () { return 'feature'; }
}
foo.bar.foo = foo;
foo.bar.bar = foo.bar;
foo.test = new Test('foo', 'bar');
foo.bar.test = foo.test;
foo.bar.func = () => 'func';
console.log(foo);
var otherFoo = clone(foo);
// everything copies as expected
console.log(otherFoo);
console.log(otherFoo.test instanceof Test);
console.log(otherFoo.bar.func() === 'func');
console.log(typeof otherFoo.bar.func === 'function');
// nothing references the original object
console.log(foo !== otherFoo);
console.log(foo.bar !== otherFoo.bar);
console.log(foo.test !== otherFoo.test);
console.log(foo.bar.func !== otherFoo.bar.func);
// doesn't copy prototypes
console.log(foo.test.cool === otherFoo.test.cool);
.as-console-wrapper{max-height:100%!important}

Adding a property to an object by default

I want to add a Symbol property to an object for comparing.
Here is the way:
let _sym = Symbol('sym');
let a = {};
a[_sym] = Symbol('_');
let b = {};
b[_sym] = Symbol('_');
console.log(a[_sym] === b[_sym]); // false
Both a and b are objects. So, I can write:
let _sym = Symbol('sym');
Object.prototype[_sym] = Symbol('_');
Object.Equals = function (x, y) {
return x[_sym] === y[_sym];
};
let a = {};
let b = {};
console.log(Object.Equals(a, b)); // true
But the result was changed.
What's wrong here?
in the first case you assign to every object a new symbol instance
in the second, using prototype each object shares the same property, so they are equal
to compare, this code would be equal to the second case (but only for these 2 objects):
let _sym = Symbol('sym');
let val = Symbol('_');
let a = {};
a[_sym] = val;
let b = {};
b[_sym] = val;
console.log(a[_sym] === b[_sym]); // true
For example:
var a = {};
var b = {};
Different objects
a === b // false
The same underlying prototype
a.toString === b.toString // true

Access JavaScript property case-insensitively?

Assume I have an object:
var obj = {
foo:"bar",
fizz:"buzz"
};
I need to access a property of that object dynamically like so:
var objSetter = function(prop,val){
obj[prop] = val;
}
No problems there, except for that prop needs to be case insensitive in case the property name is passed into the function as, say, Foo instead of foo.
So how can I point to an object's property by name without regard to case? I would like to avoid iterating the entire object if possible.
Try this:
var myObject = { "mIxeDCaSEKeY": "value" };
var searchKey = 'mixedCaseKey';
var asLowercase = searchKey.toLowerCase();
myObject[Object.keys(myObject).find(key => key.toLowerCase() === asLowercase)];
You can alternatively already provide the searchKey in lowercase.
If you want it as a function:
/**
* #param {Object} object
* #param {string} key
* #return {any} value
*/
function getParameterCaseInsensitive(object, key) {
const asLowercase = key.toLowerCase();
return object[Object.keys(object)
.find(k => k.toLowerCase() === asLowercase)
];
}
If the key can't be found, then it'll return undefined, just like normal.
If you need to support older browsers, then you can use filter instead:
function getParameterCaseInsensitive(object, key) {
const asLowercase = key.toLowercase();
return object[Object.keys(object).filter(function(k) {
return k.toLowerCase() === asLowercase;
})[0]];
}
I suggest using the polyfills for Object.keys() and Array.filter() if you need even older support.
Note: If you want to also check non-enumerable keys, use Object.getOwnPropertyNames() instead of Object.keys().
Nerdy Note: This assumes your Object doesn't have a key undefined (eg: const foo = {[undefined]: 'bar'};). That's just weird.
Compare all the properties of obj with prop.
var objSetter = function(prop,val){
prop = (prop + "").toLowerCase();
for(var p in obj){
if(obj.hasOwnProperty(p) && prop == (p+ "").toLowerCase()){
obj[p] = val;
break;
}
}
}
For this, I prefer using the prototype over a standalone function just for ease of use and expressiveness. I just don't like funneling objects into functions if I don't have to.
Also, while the accepted answer works, I wanted a more comprehensive solution for both getting and setting that would behave as much like the native dot notation or bracket notation as possible.
With that in mind, I created a couple prototype functions for setting/getting an object property without regard to case. You have to remember to be VERY responsible when adding to the Object prototype. Especially when using JQuery and other libraries. Object.defineProperty() with enumerable set to false was used specifically to avoid conflict with JQuery. I also didn't bother naming the functions anything that indicates they are case-insensitive, but you certainly could. I like shorter names.
Here's the getter:
Object.defineProperty(Object.prototype, "getProp", {
value: function (prop) {
var key,self = this;
for (key in self) {
if (key.toLowerCase() == prop.toLowerCase()) {
return self[key];
}
}
},
//this keeps jquery happy
enumerable: false
});
Here's the setter:
Object.defineProperty(Object.prototype, "setProp", {
value: function (prop, val) {
var key,self = this;
var found = false;
if (Object.keys(self).length > 0) {
for (key in self) {
if (key.toLowerCase() == prop.toLowerCase()) {
//set existing property
found = true;
self[key] = val;
break;
}
}
}
if (!found) {
//if the property was not found, create it
self[prop] = val;
}
return val;
},
//this keeps jquery happy
enumerable: false
});
Now that we've created those functions, our code is super clean and concise and just works.
Case-insensitive getting:
var obj = {foo: 'bar', camelCase: 'humpy'}
obj.getProp("FOO"); //returns 'bar'
obj.getProp("fOO"); //returns 'bar'
obj.getProp("CAMELCASE"); //returns 'humpy'
obj.getProp("CamelCase"); //returns 'humpy'
Case-insensitive setting:
var obj = {foo: 'bar', camelCase: 'humpy'}
obj.setProp('CAmelCasE', 'super humpy'); //sets prop 'camelCase' to 'super humpy'
obj.setProp('newProp', 'newval'); //creates prop 'newProp' and sets val to 'newval'
obj.setProp('NewProp', 'anotherval'); //sets prop 'newProp' to 'anotherval'
Yet another variation on those already presented which pushes the iteration down into the Underscore/Lodash findKey function:
var _ = require('underscore');
var getProp = function (obj, name) {
var realName = _.findKey(obj, function (value, key) {
return key.toLowerCase() === name.toLowerCase();
});
return obj[realName];
};
For example:
var obj = { aa: 1, bB: 2, Cc: 3, DD: 4 };
getProp(obj, 'aa'); // 1
getProp(obj, 'AA'); // 1
getProp(obj, 'bb'); // 2
getProp(obj, 'BB'); // 2
getProp(obj, 'cc'); // 3
getProp(obj, 'CC'); // 3
getProp(obj, 'dd'); // 4
getProp(obj, 'DD'); // 4
getProp(obj, 'EE'); // undefined
This answer requires ES6.
const x = { 'aB': 1, 'X-Total-Count': 10, y3: 2 }
console.log(x[Object.keys(x).find(key=>{return key.match(/^ab$/i)})])
console.log(x[Object.keys(x).find(key=>{return key.match(/^x-total-count$/i)})])
console.log(x[Object.keys(x).find(key=>{return key.match(/^y3$/i)})])
It seems to me like a good candidate for Proxy with traps to convert string keys to either upper case or lower case and behaving like a regular object.
This works with either notation: dots or braquets
Here is the code:
'use strict';
function noCasePropObj(obj)
{
var handler =
{
get: function(target, key)
{
//console.log("key: " + key.toString());
if (typeof key == "string")
{
var uKey = key.toUpperCase();
if ((key != uKey) && (key in target))
return target[key];
return target[uKey];
}
return target[key];
},
set: function(target, key, value)
{
if (typeof key == "string")
{
var uKey = key.toUpperCase();
if ((key != uKey) && (key in target))
target[key] = value;
target[uKey] = value;
}
else
target[key] = value;
},
deleteProperty: function(target, key)
{
if (typeof key == "string")
{
var uKey = key.toUpperCase();
if ((key != uKey) && (key in target))
delete target[key];
if (uKey in target)
delete target[uKey];
}
else
delete target[key];
},
};
function checkAtomic(value)
{
if (typeof value == "object")
return new noCasePropObj(value); // recursive call only for Objects
return value;
}
var newObj;
if (typeof obj == "object")
{
newObj = new Proxy({}, handler);
// traverse the Original object converting string keys to upper case
for (var key in obj)
{
if (typeof key == "string")
{
var objKey = key.toUpperCase();
if (!(key in newObj))
newObj[objKey] = checkAtomic(obj[key]);
}
}
}
else if (Array.isArray(obj))
{
// in an array of objects convert to upper case string keys within each row
newObj = new Array();
for (var i = 0; i < obj.length; i++)
newObj[i] = checkAtomic(obj[i]);
}
return newObj; // object with upper cased keys
}
// Use Sample:
var b = {Name: "Enrique", last: "Alamo", AdDrEsS: {Street: "1233 Main Street", CITY: "Somewhere", zip: 33333}};
console.log("Original: " + JSON.stringify(b)); // Original: {"Name":"Enrique","last":"Alamo","AdDrEsS":{"Street":"1233 Main Street","CITY":"Somewhere","zip":33333}}
var t = noCasePropObj(b);
console.log(JSON.stringify(t)); // {"NAME":"Enrique","LAST":"Alamo","ADDRESS":{"STREET":"1233 Main Street","CITY":"Somewhere","ZIP":33333}}
console.log('.NaMe:' + t.NaMe); // .NaMe:Enrique
console.log('["naME"]:' + t["naME"]); // ["naME"]:Enrique
console.log('.ADDreSS["CitY"]:' + t.ADDreSS["CitY"]); // .ADDreSS["CitY"]:Somewhere
console.log('check:' + JSON.stringify(Object.getOwnPropertyNames(t))); // check:["NAME","LAST","ADDRESS"]
console.log('check2:' + JSON.stringify(Object.getOwnPropertyNames(t['AddresS']))); // check2:["STREET","CITY","ZIP"]
You could do this in order to "normalize" prop
var normalizedProp = prop.toLowerCase();
obj[normalizedProp] = val;
const getPropertyNoCase = (obj, prop) => obj[Object.keys(obj).find(key => key.toLowerCase() === prop.toLowerCase() )];
or
const getPropertyNoCase = (obj, prop) => {
const lowerProp = prop.toLowerCase(obj[Object.keys(obj).find(key => key.toLowerCase() === prop.toLowerCase() )];
}
The ES6 example posted by #nilloc is incorrect and will break in use.
Here is a working example:
const x = {'first':5,'X-Total-Count':10,'third':20};
console.log(x[Object.keys(x).reduce((result,key)=>{
if (!result) {
return key.match(/x-total-count/i)
} else {
return result;
}
},null)]);
or better yet, it should return undefined if the key doesn't exist:
const x = {'first':5,'X-Total-Count':10,'third':20};
console.log(x[Object.keys(x).reduce((result,key)=>{
if (!result) {
return key.match(/x-total-count/i) || undefined
} else {
return result;
}
},undefined)]);
One consideration is that the above example will return the last matching key in the object if there are multiple keys that match.
Here is an example with the code made into a function:
/**
* #param {Object} object
* #param {string} key
* #return {string||undefined} value || undefined
*/
function getKeyCase(obj,key) {
const re = new RegExp(key,"i");
return Object.keys(obj).reduce((result,key)=>{
if (!result) {
return key.match(re) || undefined
} else {
return result;
}
},undefined);
const x = {'first':5,'X-Total-Count':10,'third':20};
console.log(x[getKeyCase(x,"x-total-count")]);
Its really sad that the iteration can't be skipped as it seems. For me what is acceptable but may not be for everyone is to shape the object one time via iteration and then use it in regular hashmap fashion.
const hashmap = {
'FOO': 'foo as in function programming',
'bar': 'bar is in baz',
};
const shapedmap = Object.entries(hashmap).reduce(
(acc, [key, val]) => (acc[key.toUpperCase()] = val, acc), {}
);
for (const term of ['foo', 'bar', 'baz']) {
const match = shapedmap[term.toUpperCase()]
match && console.log('awesome, we got the term.', match);
};
Even if it just one time lookup has to be performed, it shouldn't less performant as any other iteration solution since after 1 pass, the lookup speed is constant. (I guess).
This is an old question, but it was the first one I found.
As #ZachSmith says, you can use a Proxy.
Here's some example code:
function lowercase(oldKey) {
// Check that it's a string.
return typeof oldKey === 'string' ? oldKey.toLowerCase() : oldKey;
}
const propertiesMap = new Map(
Object.keys(obj).map(propKey => [lowercase(propKey), obj[propKey]])
);
const caseInsensitiveGetHandler = {
get: function(target, property, receiver) {
return propertiesMap.get(lowercase(property));
}
};
obj = new Proxy(obj, caseInsensitiveGetHandler);
For my use case, I only needed to proxy the object's getter, but you may need to implement more of the Proxy methods.
There is no need for any iteration. Since prop might not be a string, it should be coerced to a string first where appropriate since that's what objects do natively. A simple getter function is:
function objGetter(prop) {
return obj[String(prop).toLowerCase()];
}
If there is a requirement is to restring access to own properties:
function objGetter(prop) {
prop = String(prop).toLowerCase();
if (obj.hasOwnProperty(prop)) {
return obj.prop;
}
}
and a setter:
function objSetter(prop, val) {
obj[String(prop).toLowerCase()] = val;
}
Heres a very simple code to do this
Assuming that data is the array of objects like
data=[{"A":"bc","B":"nn"}]
var data=data.reduce(function(prev, curr) {
var cc = curr; // current value
var K = Object.keys(cc); // get all keys
var n = {};
for (var i = 0; i < K.length; i++) {
var key = K[i];//get hte key
n[key.toLowerCase()] = cc[key] // convert to lowercase and assign
}
prev.push(n) // push to array
return prev;
}, [])
Output will be
data=[{"a":"bc","b":"nn"}]
You might only need to do case-insensitive matching (usually expensive because of object iteration) IF a case-sensitive match (cheap and quick) fails.
Say you have:
var your_object = { "Chicago" : 'hi' , "deTroiT" : 'word' , "atlanta" : 'get r dun' } ;
And you have, for whatever reason, the_value, Detroit:
if( your_object.hasOwnProperty( the_value ) )
{
// do what you need to do here
}
else
{ // since the case-sensitive match did not succeed,
// ... Now try a the more-expensive case-insensitive matching
for( let lvs_prop in your_object )
{ if( the_value.toLowerCase() == lvs_prop.toLowerCase() )
{
// do what you need to do here
break ;
} ;
}
} ;
why would we do it that complicated when we simply can make it all lower case:
var your_object = {
"chickago" : 'hi' ,
"detroit" : 'word',
"atlanta" : 'get r dun',
GetName: function (status) {
return this[status].name;
} };
to call it: your_object.GetName(your_var.toLowerCase());
Another simple way:
function getVal(obj, prop){
var val;
prop = (prop + "").toLowerCase();
for(var p in obj){
if(obj.hasOwnProperty(p) && prop == (p+ "").toLowerCase()){
val = obj[p]
break;
}
}
return val;
}
Use it like this:
var obj = {
foo:"bar",
fizz:"buzz"
};
getVal(obj,"FoO") -> returns "bar"
Here is a nice recursive function that allows you to traverse a javascript object in a case-insensitive way:
let testObject = {'a': {'B': {'cC': [1,2,3]}}}
let testSeq = ['a','b','cc']
function keySequence(o, kseq) {
if(kseq.length==0){ return o; }
let validKeys = Object.keys(o).filter(k=>k.toLowerCase()==kseq[0].toLowerCase());
if(validKeys.length==0) { return `Incorrect Key: ${kseq[0]}` }
return keySequence(o[validKeys[0]], kseq.slice(1))
}
keySequence(testObject, testSeq); //returns [1,2,3]
This will convert everything to lowercase, but in a bind this could help if you are not concerned with retaining case.
var somedata = {
"MixEdCase": 1234
}
var temp = JSON.parse(JSON.stringify(somedata).toLowerCase());
console.log(temp.mixedcase);
// or
console.log(temp["mixedcase"]);
So, you will need to get the object key that matches the case of the existing object, then use this to do your object update.
const obj = {
foo:"bar",
fizz:"buzz"
};
// to get obj.foo or obj.FOO or obj.foO returning "bar"
// create regex expression of case insensitive version of the key string
const regex=passedKey=> new RegExp(`^${passedKey}$`,'gi');
// find the key that matches the string you are passing
const formattedKey=passedKey=>Object.keys(obj).find(key=>regex(passedKey).test(key));
formattedKey('Foo'); // returns foo
formattedKey('FoO'); // returns foo
// consequently you can can use it like wise
obj[formattedKey('Foo')] // returns bar
obj[formattedKey('FoO')] // returns bar
obj[formattedKey('foo')] // returns bar

Categories

Resources