I'm using a javascript game engine called panda, and i'm getting an error in the console (Uncaught Class BG already created). And when i explore the source code of the engine, i found the code that is throwing the error (below). My question is, in the second if statement what is the meaning of (this[name])? i don't understand what exactly its saying. Any help would be appreciated. Thanks in advanced.
createClass: function(name, extend, content) {
if (typeof name === 'object') return this.Class.extend(name);
if (this[name]) throw 'Class ' + name + ' already created';
if (typeof extend === 'object') {
content = extend;
extend = 'Class';
}
There are two type of notation in JavaScript to refer object properties.
var Employee = { "firstname" : "John", "lastname" : "Smith" }
1. Dot notation
Employee.firstname; // John
Employee.lastname; // Smith
2. Bracket notation
var fname = "firstname";
var lname = "lastname";
Employee[fname]; // John
Employee[lname]; // Smith
So, incase if the object property is a variable we can user bracket notation.
So in your case this[name] is referring to a property on this object.
This is not really clear from the fragment of code, you've posted, but this might be some kind of class container.
if(this[name]) ... Checks for existence of property with the given name (which in this context shows if the class with such name is already registered.)
The fact you are getting the error means that you have tried to register two classes with the same name.
this[X] will check inside if condition value is undefined
if (this[name]) throw 'Class ' + name + ' already created';
if this[name] is undefined will not goes into if statement.
Example
var chkCondition;
alert(chkCondition);
// This will not goes inside if because chkCondition is undefined.
if (chkCondition) {
alert('yes');
}
chkCondition="A";
// Now chkCondition has value "A" that's why it will return
// true and goes inside if and alert "yes"
if (chkCondition) {
alert('yes');
}
Demo
Related
I already searched for similar issues but I didn't find anything that could help me yet.
I'm trying to reach a picture path (using JSON format) depending on the material type of the picked element. Actually, my code is built like this:
if (globalData.Material.Mat_type == "OSCILLOSCOPE") {
var picture = (globalData.Material.Oscilloscope.picture);
}
if (globalData.Material.Mat_type == "ALIMENTATION") {
var picture = (globalData.Material.Alim.picture);
}
But not optimized at all, so Im trying to make it this way :
var mat_type = (globalData.Material.Mat_type);
var picture = (globalData.Material[mat_type].picture);
But it doesn't work... Got some exception:
TypeError : globalData.Material[mat_type] is undefined.
I already tried a lot of things, have you got any idea? Thanks!
I outlined the issue with character case in the comment under the question, so presumably adjusting value of globalData.Material.Mat_type could do the trick:
var mat_type =
globalData.Material.Mat_type.charAt(0).toUpperCase() +
globalData.Material.Mat_type.substr(1).toLowerCase();
I can also see that this general rule may not be applicable in all cases. If it's not a typo, it won't work for the second case where Mat_type == "ALIMENTATION", because then you try to access Alim property of Material instead of Alimentation. In this case you could access property by prefix:
function pictureOf(material) {
if (!material || !String(material.Mat_type)) {
return null;
}
let mat_type = String(material.Mat_type).toUpperCase();
for (var propertyName in material) {
if (mat_type.startsWith(propertyName.toUpperCase())) {
return material[propertyName].picture || null;
}
}
return null;
}
console.log(pictureOf({
Mat_type: "OSCILLOSCOPE",
Oscilloscope: {
picture: "picture of oscilloscope"
}
}));
console.log(pictureOf({
Mat_type: "ALIMENTATION",
Alim: {
picture: "picture of alimentation"
}
}));
But this kind of approach can be error prone, if multiple properties share the same prefix. There's also a hidden issue with case-insensitive prefix matching in case you use some special unicode characters in property names. Lastly this method is not efficient, because it has to iterate over all properties of the object (worst case scenario). It can be replaced with much safer property mapping:
const matTypeMapping = {
"ALIMENTATION": "Alim"
};
function pictureOf(material) {
if (!material || !String(material.Mat_type)) {
return null;
}
let matType = String(material.Mat_type);
// find property mapping or apply general rule, if mapping not defined
let propertyName = matTypeMapping[matType] ||
matType.charAt(0).toUpperCase() + matType.substr(1).toLowerCase();
return material[propertyName].picture || null;
}
console.log(pictureOf({
Mat_type: "OSCILLOSCOPE",
Oscilloscope: {
picture: "picture of oscilloscope"
}
}));
console.log(pictureOf({
Mat_type: "ALIMENTATION",
Alim: {
picture: "picture of alimentation"
}
}));
NB: To avoid headaches, maybe you should prefer strict equality operator over loose equality operator.
Problem Solved
Peter Wolf was right ! It was a case-sensitive issue
I actually don't know how to promote his comment, sorry for this..
Anyway, thank you guys !
var mat_type = (globalData.Material.Mat_type);
if(mat_type!==undefined)
var picture = (globalData.Material[mat_type].picture)
Just do an existential check before accessing the value, for keys that may not be present.
I have created this JS object from an array.
var rv = {};
$( ".part-name:visible" ).each(function( index ) {
//rv[$(this).text()] = arrayPartsName[$(this).text()];
rv[$(this).text()] = arrayPartsName[$(this).text()];
console.log(rv);
})
4GN: "4GN"
4GNTS: "4GNTS"
042645-00: "042645-00"
503711-03: "503711-03"
573699-05: "573699-05"
I have to use this object with Materialize Autocomplete and I have to edit it. The correct object must be, for example, like this
4GN: null
4GNTS: null
042645-00: null
503711-03: null
573699-05: null
How can do this?
Picking up from my comment. You can just set it to null ;) JavaScript is quite a cool language... you can pretty much set any object's properties to anything you want, null, a specific value, or even a function... see some more on the topic
But to focus on your specific question:
Change this line
rv[$(this).text()] = arrayPartsName[$(this).text()];
to
rv[$(this).text()] = null;
Something to be aware of
If you have property or key values in the JSON object with a dash in the name, you have to wrap it in quotes ", otherwise it wont be seen as valid. Although this might not be as evident, or an issue in your example as your keys are being added via the following function $(this).text().
var fruit = {
"pear": null, // something null
"talk": function() { console.log('WOOHOO!'); } // function
}
var apple = "app-le";
fruit[apple.toString()] = 'with a dash';
fruit["bana-na"] = 'with a dash';
// below is not allowed, the values will be evaluated as
// properties that dont exist, and then your js will fail
// fruit[pe-ar] = 'with a dash';
fruit.talk();
console.log(fruit);
In the bottom of this question I have code: console.log("returnAnonModel -----", returnAnonModel, "typeof : ", typeof returnAnonModel) ,it logs that returnAnonModel is an object. I don't understand why the if else conditions don't get hit.
First let me show you what it logs:
returnAnonModel ----- { _id: 57d0d00c50ed1a2421749a69,
__v: 0,
usefulness: [],
reviews: [] } typeof : object
The question is straight forward. you see the object but apparently Object.keys(returnAnonModel).length > 0 in the if condition is not true. shouldn't the object have a length of 4? shouldn't I see the console inside that if? console.log("***********Anon USER SEARCHING*********************************") doesn't show
Code:
var modelType = undefined;
Anon.findOne({_id : app.locals.user._id})
.then(function( returnAnonModel){
console.log("returnAnonModel -----", returnAnonModel, "typeof : ", typeof returnAnonModel)
if(err) console.log(err);
if( Object.keys(returnAnonModel).length > 0 ){
console.log("***********Anon USER SEARCHING*********************************")
modelType = Anon
userOrAnonArr()
}else{
console.log("***********USER USER SEARCHING*********************************")
modelType = User
userOrAnonArr(modelType)
}
function userOrAnonArr(modelType){
console.log("modelType: ", modelType, " app.locals.user._id : ", typeof app.locals.user._id )
modelType.findOne({_id : app.locals.user._id}, function(err, returnUser){
if(err) console.log(err);
console.log("returnUser : ", returnUser )
SOMETHING ELSE IS WEIRD:
I tried to test the length of the object by doing this:
console.log("Object.keys(returnAnonModel).length", Object.keys(returnAnonModel).length)
and it returns Object.keys(returnAnonModel).length 10 so the length is 10. I think mongoose adds properties.
but when I do
console.log("Object.keys(returnAnonModel).length", Object.keys(returnAnonModel).toObject().length)
it logs absolutely nothing. why?
The last Edit
This works. I was trying to do this functionality this whole time. And I don't know why it works now and not before. I think it has something to do with the console.
var modelType = undefined;
Anon.findOne({_id : app.locals.user._id})
.then(function( returnAnonModel){
console.log("*******", returnAnonModel ,"***********88")
// console.log("returnAnonModel -----", returnAnonModel, "typeof : ", typeof returnAnonModel)
// console.log("Object.keys(returnAnonModel).length", Object.keys(returnAnonModel.toObject()).length)
// console.log("returnAnonModel.toObject()---", returnAnonModel.toObject())
if(returnAnonModel){
modelType = Anon;
userOrAnonArr(modelType);
console.log("*************Anon user found*********************");
}else{
modelType = User;
userOrAnonArr(modelType);
console.log("*************Anon user NOT found*************")
}
The Object.keys() function doesn't cover all properties of an object. It only includes properties that meet the following 2 criteria:
The property must be an "owned" property, meaning that Object.keys() does not look along any prototype chain that may exist.
The property must have been defined with the enumerable attribute.
It's not clear from the code provided how the returnAnonModel object has been constructed, but my guess is that the properties do not meet both of the criteria listed.
I've read a lot of articles on JavaScript formatting and the rules etc. But my question here is how to format core JavaScript elements (i.e. functions, arrays, and objects)
Usually for functions I use the following:
function myFunction(argument1 , argument2 , optionalargument3) {
optionalargument3 === undefined ? optionalargument3 : "default value";
return optionalargument1;
}
or:
var myFunction = function(argument1 , argument2 , optionalargument3) {
optionalargument3 === undefined ? optionalargument3 : "default value";
return optionalargument1;
}
but this is controversial. For objects I use:
var Car = {
model : undefined
make : "Sudan"
MPG : 7.5
highway-mpg : 11.5
};
of course, this is highly controversial and most people use different methods.
and for for loops, I use:
for(var i = 0; i < (array.length + 1); i++) {
console.log(array[i]);
}
People also seem to have devolved the idea to write out global in a list before objects or functions.
eg:
var winMessage = "You Win!";
var loseMessage = "Loser!";
var cash = 0;
var intrest = null;
function randomInteger(low , high) {
return Math.floor((Math.random())*(high-low))+low
}
var Car = {
model : undefined
make : "Sudan"
MPG : 7.5
highway-mpg : 11.5
};
Are there any universal accepted, or a generically "proper" way to format your JavaScript code?
It's mostly down to preference but it is important to keep a consistent style throughout your code base particularly if you are working in a team to increase readability of your code.
You can either define your own style or adopt an existing one such as the Google style guide (https://google-styleguide.googlecode.com/svn/trunk/javascriptguide.xml), or Crockfords (http://javascript.crockford.com/code.html).
JavaScript has automatic semi-colon insertion which means that some types of formatting can lead to code that doesn't work as intended such as the following where the interpreter will ignore the object literal because it will insert a semi-colon directly after the return keyword:
return
{
name: "Foo"
};
In your example
optionalargument3 === undefined ? optionalargument3 : "default value";
doesn't actually do anything because there is no assignment, but a nice clean way to deal with default arguments is instead of using
arg = arg === undefined ? "default value" : arg;
you can use the semantically identical and cleaner version:
arg = arg || "default value";
Let us explain the question with an example. I have a text box. The textbox (every textbox) has a property called 'value'. I want to over ride that textbox.value and comeup with and
new thing. When the text in textbox is 'ranjan' then the textbox.VALUE property returns 'ranjan'. Now I want to thus overwrite this so that when you type textbox.VALUE you get a different thing say for example, RaNjAn or say, Mr. Ranjan or whatever.
We can over ride methods using Object.PROTOTYPE property. But how can we do it for non-function objects inside object for example the 'value' property in this case.
If i need to make the question more clear, please mention.
Regards - Ranjan.
You can define custom properties for your element using Object.defineProperty
If you have a case where you need to get the value of an element as Mr. <value> for example, then this approach will be useful. Overriding standard properties may not be such a good idea.
Demo: http://jsfiddle.net/zvCGw/2/
Code:
var foo = document.getElementById('foo');
Object.defineProperty(foo, "xvalue", {
get: function() {
return 'Mr. ' + foo.value;
},
set: function(_newValue) {
foo.value = _newValue;
}
});
foo.xvalue = 'Hello';
alert(foo.xvalue);
What you are trying to do is called type augmentation. In javscript there are types of things, such as the object type, array type, etc.
You can use the prototype to augment these built in types, for example, adding a new method that can be called on any object that is of the type array:
Array.prototype.myNewMethod = function() {
//the method logic
}
Then you can call your method on any array:
[0,1,2].myNewMethod();
There is no INPUT type in JavaScript, DOM elements are classed as Objects. But you could jerry-rig something together that kind of does what you need, like this
Object.prototype.changeValue = function(el) {
if (el.tagName === "INPUT") {
return "Mr " + el.value;
}
}
var testEl = document.getElementById("test");
document.write(testEl.changeValue(testEl))
Used in conjunction with this textbox:
<input id="test" value="Dan" />
You would then get the output 'Mr Dan'
However, this is not great, it's just to illustrate the point and is just something to get you started...
I made a fiddle so you can play around with it
You can redeclare value but it will do no good ;)
This example would do that if test is a textbox
var input = document.getElementById("test");
Object.defineProperty(input, "value", {
get : function () {
return "'" + this["value"] + "'";
},
set : function (val) {
this["value"] = val;
}
});
input.value = "Hello World";
alert(input.value);
Unfortunately, "this.value" will reference the getter causing infinite recursion.
Once redefined, the original value will no longer exist so you will have crippled the element object.
At least as far as I have been able to test.
If the property you're trying to override can also be represented by an HTML attribute (e.g. an input's value), then you can use getAttribute and setAttribute.
Object.defineProperty(myInputElement, 'value', {
get: function () {
return myInputElement.getAttribute('value');
},
set: function (value) {
myInputElement.setAttribute('value', value);
}
});
Note, however, that this override itself cannot be overridden without re-implementing it.