I have a straightforward "extend" method set up like this:
extend: function(source) {
for (var k in source) {
if (source.hasOwnProperty(k)) {
myThing[k] = source[k];
}
}
return myThing;
}
You use it like
myThing.extend({
newObj: {
myFunc: function () { console.log('things'); }
}
});
and it works great.
However, I would love to add the ability to have some other piece of code call this LATER:
myThing.extend({
newObj: {
mySecondFunc: function () { console.log('things'); }
}
});
and I should be able to call both myThing.newObj.myFunc() AND myThing.newObj.mySecondFunc().
I tried changing it to this:
for (var k in source) {
if (source.hasOwnProperty(k)) {
if (mtUtils.hasOwnProperty(k)) {
for (var t in k) {
mtUtils[k][t] = source[k][t];
}
} else {
mtUtils[k] = source[k];
}
}
}
but that doesn't seem to work.
function extend(dest, source) {
for (var k in source) {
if (source.hasOwnProperty(k)) {
var value = source[k];
if (dest.hasOwnProperty(k) && typeof dest[k] === "object" && typeof value === "object") {
extend(dest[k], value);
} else {
dest[k] = value;
}
}
}
return dest;
}
var myThing = {};
extend(myThing, {
newObj: {
myFunc: function() {
console.log('things');
}
}
});
extend(myThing, {
newObj: {
mySecondFunc: function() {
console.log('things');
}
}
});
myThing;
/*
Object
newObj: Object
myFunc: function () { console.log('things'); }
mySecondFunc: function () { console.log('things'); }
__proto__: Object
__proto__: Object
*/
This should fix your problem, but why not implement a recursive version of extend?
for (var k in source) {
if (source.hasOwnProperty(k)) {
if (mtUtils.hasOwnProperty(k)) {
for (var t in source[k]) {
mtUtils[k][t] = source[k][t];
}
} else {
mtUtils[k] = source[k];
}
}
}
Related
JSFiddle version with spacing: http://jsfiddle.net/eopth925/1/
var obj = {
test: {
test2: "test",
test3: {
base: {
base: {
check: function() {
return this;
},
va: function() {
return "value";
},
do: "this is dummy"
}
}
},
test4: {
test5: function() {
var k = 2;
k++;
return k;
},
test6: {
test7: {
test8: "test8",
test9: {
test10: "test10",
test11: function() {
return window.jQuery;
},
test12: "test12",
test13: function() {
return window.ga;
}
}
}
}
}
},
};
var output = "";
var addbreak = "\n";
var RunFunc = {
propertypri: function(a) {
Object.keys(a).forEach(function(e) {
if (typeof a[e] === 'object') {
output += `Main Key=${e}`;
RunFunc.propertyobj(e, a[e]);
}
else {
output += `Main Key=${e} value=${a[e]}` + addbreak;
}
});
console.log(output);
},
propertyobj: function(key, keyObj) {
Object.keys(keyObj).forEach(function(e) {
if (typeof keyObj[e] === 'object') {
output += ` Subkey=${e}`;
RunFunc.propertyobj(e, keyObj[e]);
}
else {
output += ` Subkey=${e} value=${keyObj[e]}` + addbreak;
}
});
}
};
RunFunc.propertypri(obj);
The way it's outputting is not view friendly. I would like to add proper indentation in the output. I am sure there is a more efficient way of doing what I am trying to accomplish.
How can I update my script so it displays like this:
Main Key=test
Subkey=test2 value=test
Subkey=test3
Subkey=base
Subkey=base
Subkey=check value=function() {
return this;
}
Subkey=va value=function() {
return "value";
}
Subkey=do value=this is dummy
Subkey=test4
Subkey=test5 value=function() {
var k = 2;
k++;
return k;
}
Subkey=test6
Subkey=test7
Subkey=test8 value=test8
Subkey=test9
Subkey=test10 value=test10
Subkey=test11 value=function() {
return window.jQuery;
}
...
Why not just use JSON.stringify?
console.log(JSON.stringify(foo, (key, val) => (typeof val === 'function' ? '' + val : val), 2))
const yourObject = { /* object properties here */ }
function printKeys(obj) {
if (typeof obj === 'object') {
const keys = Object.keys(obj)
for (const key of keys) {
printKeys(key)
}
} else {
console.log(obj)
}
}
So, i have this CustomerProfile Class as:
import _customer from '../swaggerCodegen/Customer'
import Address from '../Address'
export default class CustomerProfile {
constructor(customerProfileResponse) {
_customer.constructFromObject(customerProfileResponse,this)
}
}
where constructFromObject is a static function created by Swagger as:
static constructFromObject(data, obj) {
if (data) {
obj = obj || new Customer();
if (data.hasOwnProperty('accountManager')) {
obj['accountManager'] = Employee.constructFromObject(data['accountManager']);
}
if (data.hasOwnProperty('addresses')) {
obj['addresses'] = ApiClient.convertToType(data['addresses'], [Address]);
}
if (data.hasOwnProperty('billingAccounts')) {
obj['billingAccounts'] = ApiClient.convertToType(data['billingAccounts'], [BillingAccount]);
}
if (data.hasOwnProperty('billingStatus')) {
obj['billingStatus'] = ApiClient.convertToType(data['billingStatus'], 'String');
}
if (data.hasOwnProperty('busNumber')) {
obj['busNumber'] = ApiClient.convertToType(data['busNumber'], 'String');
}
if (data.hasOwnProperty('companyName')) {
obj['companyName'] = ApiClient.convertToType(data['companyName'], 'String');
}
if (data.hasOwnProperty('contacts')) {
obj['contacts'] = ApiClient.convertToType(data['contacts'], [Contact]);
}
if (data.hasOwnProperty('customerCode')) {
obj['customerCode'] = ApiClient.convertToType(data['customerCode'], 'String');
}
if (data.hasOwnProperty('email')) {
obj['email'] = ApiClient.convertToType(data['email'], 'String');
}
if (data.hasOwnProperty('gsm')) {
obj['gsm'] = ApiClient.convertToType(data['gsm'], 'String');
}
if (data.hasOwnProperty('idNumber')) {
obj['idNumber'] = ApiClient.convertToType(data['idNumber'], 'String');
}
if (data.hasOwnProperty('segment')) {
obj['segment'] = ApiClient.convertToType(data['segment'], 'String');
}
if (data.hasOwnProperty('subsegment')) {
obj['subsegment'] = ApiClient.convertToType(data['subsegment'], 'String');
}
}
return obj;
}
Also, here the snippet that handle arrays in the covertToType function:
default:
if (type === Object) {
// generic object, return directly
return data;
} else if (typeof type === 'function') {
// for model type like: User
return type.constructFromObject(data);
} else if (Array.isArray(type)) {
// for array type like: ['String']
var itemType = type[0];
return data.map((item) => {
return ApiClient.convertToType(item, itemType);
});
} else if (typeof type === 'object') {
// for plain object type like: {'String': 'Integer'}
var keyType, valueType;
for (var k in type) {
if (type.hasOwnProperty(k)) {
keyType = k;
valueType = type[k];
break;
}
}
var result = {};
for (var k in data) {
if (data.hasOwnProperty(k)) {
var key = ApiClient.convertToType(k, keyType);
var value = ApiClient.convertToType(data[k], valueType);
result[key] = value;
}
}
return result;
Logging obj['addresses'][0] instanceof Address returns true when called from the static method, while logging this.addresses[0] instanceof Address from the CustomerProfile constructor brings me false.
Any insights? Thanks
P.S Calling constructor.name calls returns 'Address'
The below function returns this output. But I can't understand why. Any clues?
Output: {"A":{"antal":null},"B":{"antal":null},"C":{"antal":null},"D":{"antal":null},"E":{"antal":null},"G":{"antal":null}}
Function is,
function seriestat(){
var statserier = {};
$.each(globalSIEdata["#EXTRA"]["VERSERIER"], function(i, item) {
statserier[i] = {};
});
$.each(globalSIEdata["#VER"], function(i2, item2) {
var serie = i2.substring(0, i2.indexOf('-'));
statserier[serie]["antal"] += 1;
});
return statserier;
}
Here is example from globalSIEdata:
{ "#VER": {
"A-1": {
"verdatum": "2017-01-03"
},
"A-2": {
"verdatum": "2017-01-03"
},
"B-1": {
"verdatum": "2017-01-03"
},
"B-2": {
"verdatum": "2017-01-03"
}
"A-3": {
"verdatum": "2017-01-03"
}
}
You forgot to initialize the "antal" property thus it will be undefined, try something like:
statserier[serie]["antal"] = (statserier[serie]["antal"] || 0) + 1;
Alternatively you could try to initialize your statserier object as follows instead:
statserier[i] = { antal: 0 };
From the link qr-code.js I have the code below.
Then I don't understand, on the highlighted line (60), what means the suffix: "Changed"?
attributeChangedCallback: {
value: function (attrName, oldVal, newVal) {
var fn = this[attrName+'Changed'];
if (fn && typeof fn === 'function') {
fn.call(this, oldVal, newVal);
}
this.generate();
}
Also I don't understand the usage of:
this[attrName+'Changed']
Could you explain me this?, I don't find any clear explanation about this on Google. Thanks.
Below is the full code:
'use strict';
(function(definition) {
if (typeof define === 'function' && define.amd) {
define(['QRCode'], definition);
} else if (typeof module === 'object' && module.exports) {
var QRCode = require('qrjs');
module.exports = definition(QRCode);
} else {
definition(window.QRCode);
}
})(function(QRCode) {
//
// Prototype
//
var proto = Object.create(HTMLElement.prototype, {
//
// Attributes
//
attrs: {
value: {
data: null,
format: 'png',
modulesize: 5,
margin: 4
}
},
defineAttributes: {
value: function () {
var attrs = Object.keys(this.attrs),
attr;
for (var i=0; i<attrs.length; i++) {
attr = attrs[i];
(function (attr) {
Object.defineProperty(this, attr, {
get: function () {
var value = this.getAttribute(attr);
return value === null ? this.attrs[attr] : value;
},
set: function (value) {
this.setAttribute(attr, value);
}
});
}.bind(this))(attr);
}
}
},
//
// LifeCycle Callbacks
//
createdCallback: {
value: function () {
this.createShadowRoot();
this.defineAttributes();
this.generate();
}
},
attributeChangedCallback: {
value: function (attrName, oldVal, newVal) {
var fn = this[attrName+'Changed'];
if (fn && typeof fn === 'function') {
fn.call(this, oldVal, newVal);
}
this.generate();
}
},
//
// Methods
//
getOptions: {
value: function () {
var modulesize = this.modulesize,
margin = this.margin;
return {
modulesize: modulesize !== null ? parseInt(modulesize) : modulesize,
margin: margin !== null ? parseInt(margin) : margin
};
}
},
generate: {
value: function () {
if (this.data !== null) {
if (this.format === 'png') {
this.generatePNG();
}
else if (this.format === 'html') {
this.generateHTML();
}
else if (this.format === 'svg') {
this.generateSVG();
}
else {
this.shadowRoot.innerHTML = '<div>qr-code: '+ this.format +' not supported!</div>'
}
}
else {
this.shadowRoot.innerHTML = '<div>qr-code: no data!</div>'
}
}
},
generatePNG: {
value: function () {
try {
var img = document.createElement('img');
img.src = QRCode.generatePNG(this.data, this.getOptions());
this.clear();
this.shadowRoot.appendChild(img);
}
catch (e) {
this.shadowRoot.innerHTML = '<div>qr-code: no canvas support!</div>'
}
}
},
generateHTML: {
value: function () {
var div = QRCode.generateHTML(this.data, this.getOptions());
this.clear();
this.shadowRoot.appendChild(div);
}
},
generateSVG: {
value: function () {
var div = QRCode.generateSVG(this.data, this.getOptions());
this.clear();
this.shadowRoot.appendChild(div);
}
},
clear: {
value: function () {
while (this.shadowRoot.lastChild) {
this.shadowRoot.removeChild(this.shadowRoot.lastChild);
}
}
}
});
//
// Register
//
document.registerElement('qr-code', {
prototype: proto
});
});
As #Jhecht suggested, it's a combination of the name of a attribute and the suffix "Changed" in order to create generic method names.
For example if the <qr-code> element has an attribute "foo" that is added, updated or removed, then the callback will define the fn variable to this["fooChanged"], which is equivalent to this.fooChanged.
If this method exists, it will be invoked by fn.call().
However I see nowhere in the code you posted such method signature attached to the custom element prototype, so it's useless code until further notice.
I have a big problem and I need your help.
I have a object like this:
{
folder1: {
folderid: 1,
files: {
name: "yeah.txt"
},
folder2: {
folderid: 2
folder3: {
folderid: 3
}
}
},
folder4: {
folderid: 4
}
}
and I want to search for the key "folderid = 3" and find the object.
How can I do this in JavaScript?
Kind regards and thanks for your help
I came to a more generalised solution, that supports multiple properties check:
function search(obj, properties){
if(Object.keys(properties).every(function(key){
return obj[key] === properties[key];
})) {
return obj;
} else {
Object.keys(obj).forEach(function(key){
var child = obj[key];
if(child !== null && typeof child === 'object'){
return search(child, properties);
}
});
return false;
}
}
demo: http://jsfiddle.net/dzs1orbw/
You can use a DSF algorithm to do this: http://jsfiddle.net/L5b07bt6/
var obj = {
folder1: {
folderid: 1,
files: {
name: "yeah.txt"
},
folder2: {
folderid: 2,
folder3: {
folderid: 3,
caption: "I got it!"
}
}
},
folder4: {
folderid: 4
}
};
function find(root, id) {
if (root.folderid == id) return root;
if (typeof root !== 'object') return null;
var key, val;
for (key in root) {
val = find(root[key], id);
if (val != null) return val;
}
return null;
}
var result = find(obj, 3);
if (!result) alert("Not found!");
else alert("Found: " + result.caption);
and here another one:
function findByKey (object, searchKey){
if(typeof object !== 'object'){
return false;
}
for(var key in object){
if(object[key] === searchKey){
return object;
} else {
if(typeof (object[key] === 'object')){
var result = findByKey(object[key], searchKey);
if(result){
return result;
}
}
}
}
}
http://jsfiddle.net/mattposch/ebmd8xtk/