I'm trying to add functionality to the format function but there is something wrong with my code:
Object.defineProperty(Intl.NumberFormat.prototype, "format", { value: function(){
//your logic here
let orig = Intl.NumberFormat.prototype
console.log(orig);// does not remember the original proto
}, configurable: true } );
What am I missing?
You basically catch the property itself. You want to get the original one so before it is overriden, and you may store its subobject references too through copying them:
{
let orig = Object.assign({}, Intl.NumberFormat.prototype);
Object.defineProperty(Intl.NumberFormat.prototype, "format", { value: function(){
//your logic here
console.log(orig);// does remember the original proto
}, configurable: true } );
}
Related
What I'd like to do
describe('my object', function() {
it('has these properties', function() {
expect(Object.keys(myObject)).toEqual([
'property1',
'property2',
...
]);
});
});
but of course Object.keys returns an array, which by definition is ordered...I'd prefer to have this test pass regardless of property ordering (which makes sense to me since there is no spec for object key ordering anyway...(at least up to ES5)).
How can I verify my object has all the properties it is supposed to have, while also making sure it isn't missing any properties, without having to worry about listing those properties in the right order?
It's built in now!
describe("jasmine.objectContaining", function() {
var foo;
beforeEach(function() {
foo = {
a: 1,
b: 2,
bar: "baz"
};
});
it("matches objects with the expect key/value pairs", function() {
expect(foo).toEqual(jasmine.objectContaining({
bar: "baz"
}));
expect(foo).not.toEqual(jasmine.objectContaining({
c: 37
}));
});
});
Alternatively, you could use external checks like _.has (which wraps myObject.hasOwnProperty(prop)):
var _ = require('underscore');
describe('my object', function() {
it('has these properties', function() {
var props = [
'property1',
'property2',
...
];
props.forEach(function(prop){
expect(_.has(myObject, prop)).toBeTruthy();
})
});
});
The simplest solution? Sort.
var actual = Object.keys(myObject).sort();
var expected = [
'property1',
'property2',
...
].sort();
expect(actual).toEqual(expected);
it('should contain object keys', () => {
expect(Object.keys(myObject)).toContain('property1');
expect(Object.keys(myObject)).toContain('property2');
expect(Object.keys(myObject)).toContain('...');
});
I ended up here because I was looking for a way to check that an object had a particular subset of properties.
I started with _.has or Object.hasOwnProperties but the output of Expected false to be truthy when it failed wasn't very useful.
Using underscore's intersection gave me a better expected/actual output
var actualProps = Object.keys(myObj); // ["foo", "baz"]
var expectedProps =["foo","bar"];
expect(_.intersection(actualProps, expectedProps)).toEqual(expectedProps);
In which case a failure might look more like
Expected [ 'foo' ] to equal [ 'foo', 'bar' ]
Here are some new possible solutions too:
There's a module for that: https://www.npmjs.com/package/jasmine-object-matchers
With ES2016, you can use a map and convert the object to a map too
I prefer use this; becouse, you have more possibilities to be execute indivual test.
import AuthRoutes from '#/router/auth/Auth.ts';
describe('AuthRoutes', () => {
it('Verify that AuthRoutes be an object', () => {
expect(AuthRoutes instanceof Object).toBe(true);
});
it("Verify that authroutes in key 'comecios' contains expected key", () => {
expect(Object.keys(AuthRoutes.comercios)).toContain("path");
expect(Object.keys(AuthRoutes.comercios)).toContain("component");
expect(Object.keys(AuthRoutes.comercios)).toContain("children");
expect(AuthRoutes.comercios.children instanceof Array).toBe(true);
// Convert the children Array to Object for verify if this contains the spected key
let childrenCommerce = Object.assign({}, AuthRoutes.comercios.children);
expect(Object.keys(childrenCommerce[0])).toContain("path");
expect(Object.keys(childrenCommerce[0])).toContain("name");
expect(Object.keys(childrenCommerce[0])).toContain("component");
expect(Object.keys(childrenCommerce[0])).toContain("meta");
expect(childrenCommerce[0].meta instanceof Object).toBe(true);
expect(Object.keys(childrenCommerce[0].meta)).toContain("Auth");
expect(Object.keys(childrenCommerce[0].meta)).toContain("title");
})
});
I am late to this topic but there is a a method that allows you to check if an object has a property or key/value pair:
expect(myObject).toHaveProperty(key);
expect({"a": 1, "b":2}).toHaveProperty("a");
or
expect(myObject).toHaveProperty(key,value);
expect({"a": 1, "b":2}).toHaveProperty("a", "1");
If I have the following object:
var record = {
title: "Hello",
children: [
{
title: "hello",
active: true
},
{
title: "bye",
active: false
}
};
I want to use underscore to determine if one of the children within the record has or does not have a title equal to a variable that will come from a form post, but also needs to be case insensitive... So for example:
var child = { title: "heLLo", active: true }
And underscore ( and this is wrong, and what I need help with ):
if ( _.contains(record.children, child.title) ) {
// it already exists...
} else {
// ok we can add this to the object
}
So basically I don't understand how to do this with underscore when dealing with array objects that have multiple key/value pairs. Also what is the best method for ignoring case? Should this be done in the underscore _.contains function? Regex? Use toLowerCase() beforehand to create the variables? If someone types in any variation of "Hello", "HELLO", "heLLO", etc. I don't want the insert to take place.
Thank you!
Use _.find and RegExp with "i" case-ignore flag
var valueFromPost = "bye";
var someOfChildrenHasValueFromPost = _.find(record.children,function(child){
return child.title.match(new RegExp(valueFromPost,"i"));
});
Update
Here is an example #JSFiddle
JS code:
record = {
children:[
{title:'bye'},
{title:'Bye'},
{title:'Hello'}
]
}
var testValue = function(value) {
return _.find(record.children,function(child){
return child.title.match(new RegExp(value,"i"));
});
}
console.debug(testValue('Bye')); //returns object with "Bye" title
console.debug(testValue('What'));//returns undefined
console.debug(testValue('bye')); //returns object with "bye" title
I want to do something like this
Polymer('bc-datalist', {
listitems: [
{name: 'item1'},
{name: 'item2'}
],
observe: {
'listitems': 'change'
},
change: function () {
// do something
}
});
This doesn't work, so my work around is to do something like this:
Polymer('bc-datalist', {
listitems: {
1:{name: 'item1'},
2:{name: 'item2'}
},
observe: {
'listitems.1.name': 'change',
'listitems.2.name': 'change'
},
change: function () {
// do something
}
});
Is there a way of registering a callback when a object/array item has changed?
Correct me if I'm wrong, but it would appear that there's a typo in your first example. Where you mean to reference listitems as the object to observe, you reference listitem instead. Changing this to listitems would make the case for normal top-level properties work:
<polymer-element name="test-el">
<template>
<button on-click="{{clickHandler}}">Click me</button>
</template>
<script>
Polymer('test-el', {
listitems: [
{name: 'item1'},
{name: 'item2'}
],
observe: {
'listitems': 'change'
},
change: function () {
// do something
alert('listitems changed!');
},
clickHandler: function(){
this.listitems.push({ name: 'item3'});
}
});
</script>
</polymer-element>
Onto your question: Polymer does not call the propertyNameChanged callback for properties included in an observe block to the best of my knowledge. This means you will need to specify the exact nested object path (a.b.c) for what you are trying to observe or manually setup the relevant type of Path/Compound observer manually: https://github.com/Polymer/observe-js
Polymer's observe-js library has support for path observation into an object as well as array observation. The former, can be setup similar to what you have (see 2nd example in the docs).
Polymer('x-element', {
observe: {
'a.b.c': 'validateSubPath'
},
ready: function() {
this.a = {
b: {
c: 'exists'
}
};
},
validateSubPath: function(oldValue, newValue) {
var value = Path.get('a.b.c').getValueFrom(this);
// oldValue == undefined
// newValue == value == this.a.b.c === 'exists'
}
});
I'm checking on ArrayObserver support. Will update this post when I know more.
If you have an array of objects and would like to observe changes made to any of those objects' properties, you can try a custom element, <observe-array-items>. It simplifies the process of creating individual PathObservers for all of the objects in the array, and maintains them as items are added/removed from the list.
In your example, you could do something like
<polymer-element name="test-el">
<template>
<observe-array-items array="{{listitems}}"
path="name"
on-array-item-changed="{{handleNameChanged}}">
</observe-array-items>
</template>
<script>
Polymer({
listitems: [
{name: 'item1'},
{name: 'item2'}
],
handleNameChanged: function (e) {
// This will be called whenever the 'name' property
// of an existing object in listitems changes.
// e.detail.oldValue and e.detail.newValue will
// contain the old and current values
// e.detail.index will correspond to the index of the object in the array.
},
listitemsChanged: function() {
// This will be called whenever an object is added or removed from listitems
}
});
</script>
</polymer-element>
I have a nested object. here it is:
var Obj = {
a: {
state: {
started: false,
players: [],
hand: 0,
totalHand: 0,
teams: {
starter: {
name: "",
handPoints: [],
totalPoint: calc(Obj.a.state.teams.starter.handPoints)
}
}
}
}
};
Like you see , i need to use handPoints value to set totalPoint. Do i have to call that like this:
calc(Obj.a.state.teams.starter.handPoints)
is there some way about using this keyword or something else?
What if i had a more nested object? It looks like weird to me.
Thank you.
Have you tried your solution? It causes a syntax error. Obj isn't defined while you're trying to define it, and even if it was you wouldn't get the latest value of obj, because you're trying to set it as the current value of the array at runtime.
see here:
syntax error example
You want to make that property a function so that a user can get the current total when they access the function.
Like this:
totalPoint: function(){
return calc(Obj.a.state.teams.starter.handPoints)
}
working example
If you want to shorten the reference you can alias some part of it. For instance
totalPoint: function(){
var myStarter = Obj.a.state.teams.starter;
return calc(myStarter.handPoints)
}
You could instead make the variable totalPoint into a function and use this.
var Obj = {
a: {
state: {
started: false,
players: [],
hand: 0,
totalHand: 0,
teams: {
starter: {
name: "",
handPoints: [ 5,6 ],
totalPoints: function() {
return calc(this.handPoints);
}
}
}
}
}
};
Here is the jsFiddle example.
I am trying to use javascript inheritance in my code. Following is the jsfiddle for the same.
http://jsfiddle.net/Fetsz/3/
var baseObject = Object.create(Object, {
// this works as an instance variable for derived objects
name: {
writable: true,
configurable: true,
enumerable: true,
value: null
},
// this should act as instance variable for derived objects
values: {
writable: true,
configurable: true,
enumerable: true,
value: []
},
displayAlert: {
value: function (){
alert("Alert from base object");
}
}
});
var derivedObj1 = Object.create(baseObject, {});
var derivedObj2 = Object.create(baseObject, {});
function displayValues (obj) {
alert("values for " + obj.name + "\n" + JSON.stringify(obj.values));
};
$(document).ready(function(){
derivedObj1.name = "Object 1";
derivedObj2.name = "Object 2";
derivedObj1.values.push("DO1 element");
derivedObj2.values.push("DO2 element");
derivedObj1.displayAlert();
// should display values added only for derivedObj1
displayValues(derivedObj1);
// should display values added only for derivedObj2
displayValues(derivedObj2);
});
I also checked following question which nicely explains why my code doesn't work. Javascript Inheritance: Parent's array variable retains value
I need to have an array member variable in every derived class which will contain certain values. I was trying to achieve the same by adding array in base class. As mentioned in above question, to achieve the same, I will have to add array member to each derived class. Is there any other way to achieve this without modifying every derived class?
When they are created, both derivedObj1.values and derivedObj2.values point to the same array object. If you were to first reassign each one using derivedObj1.values = [];, in the same way as you are reassigning the name property, your code would behave as expected.
Instead of adding the values property to the original baseObject, you could create an init method that adds an array to the instance:
var baseObject = Object.create(Object, {
// this works as an instance variable for derived objects
name: {
writable: true,
configurable: true,
enumerable: true,
value: null
},
// this should act as instance variable for derived objects
init: {
writable: true,
configurable: true,
enumerable: true,
value: function(){
this.values = [];
}
},
displayAlert: {
value: function (){
alert("Alert from base object");
}
}
});
var derivedObj1 = Object.create(baseObject, {});
derivedObj1.init();
var derivedObj2 = Object.create(baseObject, {});
derivedObj2.init();
Your variables can't be on the prototype if you don't want them to be shared by all instances. You could create a second object with just the property definition for the array,and pass it as the second parameter to Object.create:
var arrDef = {
values: {
writable: true,
configurable: true,
enumerable: true,
value: []
}
}
var derivedObj1 = Object.create(baseObject, arrDef);
var derivedObj2 = Object.create(baseObject, arrDef);