Enforce object structure in function parameter - javascript

I am new to javascript. I have a function taking an object. But how do I make sure caller is following the structure I want in the object. As there is no concept of class in javascript, I can't create a model class and make the caller use it ?
function foo(myObject)
{
}
Whoever is calling should give me
{
Count,
[
{
FirstName,
LastName
},
{
FirstName,
LastName
},
]
}

Well you could simply check the type of object you have received as an argument, and then check if those values are actually there, like so:
function foo(myObject) {
if (typeof myObject !== 'object') {
// doesn't match
return;
}
if (typeof myObject.Count === 'undefined') {
// no count property
}
}
However, from your question, it seems you would like to make it more fix which kind of object should be sent as an argument, and this you could also do in javascript, by doing for eg:
function MyParamOptions() {
// define properties here
this.persons = [];
Object.defineProperty(this, 'Count', {
get: function() {
return this.Names.length;
},
set: function() {
// dummy readonly
}
});
}
Then you could instantiate an instance of this class by saying
var options = new MyParamOptions();
options.persons.push({ firstName: 'bla', lastName: 'bla' });
and change a check inside your foo function like
function foo(myObject) {
if (myObject instanceof MyParamOptions) {
// here myObject is MyParamOptions, so you can access the persons array, the Count property etc...
}
}
// and call foo with your MyParamOptions
foo(options);
However this will not throw any warnings at compile time, so people can call your function with any kind of parameter. If you are looking for errors at compile time, you might look into TypeScript or a similar technology that then transpiles your TypeScript code to javascript)

Related

create object function that generate properties to its caller object

I want to create a function inside an object. I need this function to generate setters and getters
for the properties of the caller object without generating getters or setters for the property of the function value.
I reached for something like this. But It gives me RangeError Maximum call stack size exceeded.
function Emp() {
return {
name: "Mohamed",
id: "5",
getSetGen: function() {
for (var i in this) {
if (typeof this[i] !== 'function') {
(function(j) {
Object.defineProperty(this, j, {
get: function() {
return this[j];
},
set: function(val) {
this[j] = val
}
})
})(i);
}
}
}
}
}
I want to apply getSetGen() to var user = { name:”Ali”,age:10} for example.
Is there any possible solution? Thanks in advance.
Edit:
This is the text that describes what I need ...
Create your own custom object that has getSetGen as
function value, this function should generate setters and getters
for the properties of the caller object
This object may have description property of string value if
needed
Let any other created object can use this function property to
generate getters and setters for his own properties
Avoid generating getters or setters for property of function
value
In trying to solve this I reworked some of your code, but I think this does basically what you're looking for, and you can tweak it to your preferences.
(I think the issue was that the new accessor property had the same name as the existing data property. See comments in the code for further explanation.)
const
baseObj = getBaseObj(),
user = { name: "Ali", age: 10 };
baseObj.addAccessorsForAllDataProps.call(user);
console.log("\nsetting age to 11...");
user.age = 11;
console.log("\nretrieving user age...");
console.log(user.age);
function getBaseObj(){
return {
name: "Mohamed",
id: 5,
addAccessorsForAllDataProps(){
for(let originalPropName in this){
if(!isFunction(this[originalPropName])){
// Renames the data property with an underscore
const dataPropName = `_${originalPropName}`
// Binds existing value to renamed data property
this[dataPropName] = this[originalPropName];
// Passes originalPropName to be used as accessorPropName
addAccessors(this, originalPropName, dataPropName);
}
}
// Accessor prop can't have same name as data prop
// (I think your stack overflow happened b/c getter got called infinitely)
function addAccessors(obj, accessorPropName, dataPropName){
Object.defineProperty(obj, accessorPropName, {
get: function(){
console.log("(getter invoked)"); // Just proving accessors get called
return obj[dataPropName];
},
set: function(val){
console.log("(setter invoked)");
obj[dataPropName] = val;
}
});
};
}
}
}
function isFunction(val) {
return val && {}.toString.call(val) === '[object Function]';
}

Validate/Preprocess property before assigning it to object in JavaScript

What is the best-practice to validate and/or preprocess a property before assigning it to an object in JavaScript?
The application for that would be to create an object and to guarantee that a specific property of it will always have a specific type or maybe do some preprocessing with it.
For example, if I create an object:
var obj = {
settings: {}
};
Then when I do something like:
obj.settings = "{foo: bar}";
It would automatically check the type of the assignment - if it is a string, it will try to parse it to an object; if it's an object, it will just assign it; else it will throw an error. This would protect the object's property against being assigned to "anything".
Also, does this make sense at all to do in JavaScript or am I just trying to have strong typed features in a language that is weak typed?
You can do this with Object.defineProperty:
var obj = {}
Object.defineProperty(obj, 'settings', {
set: function (x) {
if (typeof x === 'string') {
this._settings = JSON.parse(x)
} else {
this._settings = x
}
},
get: function () {
return this._settings
}
})
obj.settings = {foo: 'bar'}
console.log(obj.settings)
obj.settings = '{foo: "baz"}'
console.log(obj.settings)
However, if this is desirable depends on your specific use case. I frankly never used it so far. My recommendation is: don't get fancy :)
IMHO this is not strong typing, but the opposite as you are more dynamic. If you want strong typing you could try flow or TypeScript
A simple solution could be to use a getter/setter like below that gets triggered if a value is assigned to a property and how to process it :
let obj = {}
Object.defineProperty(obj, "settings", {
set: function (value) { // preprocess
this._value = value;
},
get: function () {
return "changed";
}
});
You could do this afterward:
obj.settings = "{foo: bar}";
Let me know if this makes any sense.
Reference:
MDN Reference: Object.defineProperty()

How to set Object.prototype.somefunction is `readonly`?

var obj = {};
console.log(obj.constructor === Object); // true
console.log(typeof obj.constructor); // function
obj['foo'] = 'bar';
obj['constructor'] = 'String';
console.log(obj.constructor === Object); // false
console.log(typeof obj.constructor); // string
I want to mention a case in this example: In the obj object, I've added a new property name constructor with value String. And the type of value is string.
So: 'string' !== 'function'.
Since I override it as the second, I cannot use it like a function as the first.
That also means: some js developers (almost) don't want to declare a property which the name is constructor in an object. If I try to doing that, the default constructor would be overridden.
Same to another case:
var array = [];
console.log(typeof array.forEach); // function
array['forEach'] = 'String';
console.log(typeof array.forEach); // string
Why doesn't js accept multiple keys with same name but difference value types?
What I want to achieve:
var action = {
isDone: false,
isDone: function (flag) {
this.isDone = flag
}
};
action.isDone(progressing is done);
if (action.isDone) {
// done...
}
// 'boolean' !== 'function'
My questions:
1/. How to define new property to an object with same key? (not duplicate with another topics because same key but differnce value types);
2/. Is it the best way to prevent to override an object property? (Or readonly as the title)
var obj = {};
Object.defineProperty(obj, 'constructor', {
get: function () {
return function () {
// default constructor here...
}
},
set: function (newValue) {
// do nothing here...
}
})
var obj = {
};
// being explicit
Object.defineProperty(obj, 'testFunction', {
writable: false,
value: function(){
console.log("Print read only Function");
return;
}
});
console.log(obj.testFunction.toString());
obj.testFunction();
obj.testFunction= function(){
console.log("Override Function");
}
console.log(obj.testFunction.toString());
obj.testFunction();
How to define new property to an object with same key? (not duplicate with another topics because same key but differnce value types);
You can't
Is it the best way to prevent to override an object property?
Sure, but you're still probably using it wrong. And whatever code you write around it is probably bad JavaScript.
Whatever language you're coming from, I suggest do not try to implement other idioms in JavaScript. JavaScript is its own thing. Learn how to write idiomatic JavaScript.

Best way to define functions on JavaScript prototypes [duplicate]

STORE = {
item : function() {
}
};
STORE.item.prototype.add = function() { alert('test 123'); };
STORE.item.add();
I have been trying to figure out what's wrong with this quite a while. Why doesn't this work? However, it works when I use the follow:
STORE.item.prototype.add();
The prototype object is meant to be used on constructor functions, basically functions that will be called using the new operator to create new object instances.
Functions in JavaScript are first-class objects, which means you can add members to them and treat them just like ordinary objects:
var STORE = {
item : function() {
}
};
STORE.item.add = function() { alert('test 123'); };
STORE.item.add();
A typical use of the prototype object as I said before, is when you instantiate an object by calling a constructor function with the new operator, for example:
function SomeObject() {} // a constructor function
SomeObject.prototype.someMethod = function () {};
var obj = new SomeObject();
All the instances of SomeObject will inherit the members from the SomeObject.prototype, because those members will be accessed through the prototype chain.
Every function in JavaScript has a prototype object because there is no way to know which functions are intended to be used as constructors.
After many years, when JavaScript (ES2015 arrives) we have finally Object.setPrototypeOf() method
const STORE = {
item: function() {}
};
Object.setPrototypeOf(STORE.item, {
add: function() {
alert('test 123');
}
})
STORE.item.add();
You can use JSON revivers to turn your JSON into class objects at parse time. The EcmaScript 5 draft has adopted the JSON2 reviver scheme described at http://JSON.org/js.html
var myObject = JSON.parse(myJSONtext, reviver);
The optional reviver parameter is a
function that will be called for every
key and value at every level of the
final result. Each value will be
replaced by the result of the reviver
function. This can be used to reform
generic objects into instances of
pseudoclasses, or to transform date
strings into Date objects.
myData = JSON.parse(text, function (key, value) {
var type;
if (value && typeof value === 'object') {
type = value.type;
if (typeof type === 'string' && typeof window[type] === 'function') {
return new (window[type])(value);
}
}
return value;
});
As of this writing this is possible by using the __proto__ property. Just in case anyone here is checking at present and probably in the future.
const dog = {
name: 'canine',
bark: function() {
console.log('woof woof!')
}
}
const pug = {}
pug.__proto__ = dog;
pug.bark();
However, the recommended way of adding prototype in this case is using the Object.create. So the above code will be translated to:
const pug = Object.create(dog)
pug.bark();
Or you can also use Object.setPrototypeOf as mentioned in one of the answers.
Hope that helps.
STORE = {
item : function() {
}
};
this command would create a STORE object. you could check by typeof STORE;. It should return 'object'. And if you type STORE.item; it returns 'function ..'.
Since it is an ordinary object, thus if you want to change item function, you could just access its properties/method with this command.
STORE.item = function() { alert('test 123'); };
Try STORE.item; it's still should return 'function ..'.
Try STORE.item(); then alert will be shown.

Removing and reattaching properties mapped to functions from javascript objects

I have an existing client side application that makes use of javascript objects that look something like this:
var myObject = {
Id: 1,
Name: 'Foo',
Property1: 123,
Property2: 'ABC',
MyMethod: function() { ///do something },
MyMethod2: function() { /// do something else }
};
I am now looking to try to persist these objects using a service such as Firebase. Firebase doesn't like the properties that contain the functions, so I want to know if there is a 'simple' way of stripping out the offending functions when saving to Firebase and then reattaching them on retrieval without having to create copies of each of the objects.
A fairly common pattern is to have a constructor function with the relevant functions attached to it, and to have that constructor accept a raw version of the object that it uses to populate itself as well as a "toRaw" or similar function that gives you the raw copy.
For example:
function Thingy(raw) {
var name;
for (name in raw) {
if (raw.hasOwnProperty(name)) {
this[name] = raw[name];
}
}
}
Thingy.prototype.MyMethod = function() { /* ... */ };
Thingy.prototype.MyMethod2 = function() { /* ... */ };
Thingy.prototype.toRaw = function() {
var raw, name, value;
for (name in this) {
if (this.hasOwnProperty(name)) {
value = this[name];
if (typeof value !== "function") {
if (value.toRaw) {
raw[name] = value.toRaw();
} else {
raw[name] = this[name];
}
}
}
}
};
Then when saving to Firebase:
write(myObject.toRaw());
...and when reading from Firebase:
var obj = new Thingy(read());
More complicated handling would involve putting a memo on the raw object to tell you whether one of the object's properties is, itself, using this pattern, so you know to call the constructor for it rather than just copying it. (The eagle-eyed will note that the example above is assymetrical, it allows for toRaw on properties when serializing in toRaw, but doesn't when deserializing in Thingy.)

Categories

Resources