I'm following this tutorial to "detect" if a unique number is in an array object. This number is a string.
I'm used to detect in Ruby on Rails so I look for the equivalent in React (JavaScript):
ES6:
...
// this will be "data" in "this.props.data"
data = [
{
id: 1,
order_id: "44",
name: "Some order number name",
},
{
id: 2,
order_id: "65",
...,
}
]
// let num = "44"; Just for this example
renderCreditNote(num){
if (num instanceof this.props.data) {
return num.map(function(p){
return p.order_id
});
}
}
render(){
return({this.renderCreditNote().bind(this)})
}
...
In reality, this will look like this: this.renderCreditNote(this.state.num).bind(this)
So if this num is in the Array, display only that array. Am I doing this the right way? The error is:
Uncaught TypeError: Right-hand side of 'instanceof' is not callable
I don't know Ruby, but based on the description of detect it seems you are looking for array.find in JavaScript. .find iterates over an array - if it finds the item you are looking for it returns it and stops iterating, if it does not find anything undefined is returned.
So for example:
renderCreditNote(num){
return this.props.data.find(function(p){
return num === p.order_id;
});
}
Here's a fiddle: https://jsfiddle.net/7ykt9ze3/
Some ES6 prettification:
renderCreditNote(num){
return this.props.data.find(p => num === p.order_id);
}
Be aware that this isn't completely supported in slightly older browsers, I know from experience IE11 doesn't have it. However it is definitely worth the polyfill.
About the blog you linked - without going into prototypical inheritance, instanceof basically returns true/false if the input is of the data structure. In the blog you linked they are detecting whether or not the input is an object or an array - but only so they can take different actions depending on that input. So if it's an object they simply return the field on that object, if it's an array they iterate over the array with .map and return all the names of those objects in that array.
Edit to check render method:
render(){
return(<div>{JSON.stringify(this.renderCreditNote().bind(this))}</div>)
}
You are supposed to pass a function to instance of in the right hand side. Try and do this.props.data.constructor
Related
This question already has answers here:
Accessing nested JavaScript objects and arrays by string path
(44 answers)
Closed 1 year ago.
I am aware that you can define an object reference from string like this;
obj['string']
Which basically translates to obj.string
My question is how would one extend this past the first object value? This is what I would like to pass.
obj['string1.string2']
Which fails due to that key (string1.string2) not existing within the object. I understand how this works but what I am failing to figure out is how could one get this to work and return obj.string1.string2
My use case is that I have an array of objects;
let players = [
{
name: 'Player 1',
points: {
current: 100,
total: 1000
}
},
{
name: 'Player 2',
points: {
current: 50,
total: 500
}
}
];
What I am trying to do sort the array based on the current value of points. players.points.current
The sorting method I am using is players.sort((a, b) => { return b.points.current - a.points.current });
Which works great, but in order to create a method that can take a 'sorting' string term like points.current or points.total in order to minimise code and make the function more reusable, I was trying to pass the string into the object reference which does not work for obvious reasons as mentioned before that the key does not exist. players['points.current']
Would thank anyone kindly if they could help me. Should I tackle this problem in a completely different way?
You can chain the properties, as everything inside the quote is considered a single property name string
i.e:
object['thing1']['thing2']
If you want to get this to work with a string with an unknown number of property depth, you would loop over each one, hard to explain but as an example:
let obj0 = {
obj1: {
obj2: "answer"
}
}
let string1 = "obj1.obj2"
let strArr = string1.split('.')
let objSearch = obj0;
strArr.forEach(str => {
objSearch = objSearch[str]
})
console.log(objSearch)
Keep in mind this only works on success cases where the object properties exist, you will want to have some error handling on if objSearch[str] exists etc
This question already has answers here:
Why can I access object property with an array?
(2 answers)
Closed 2 years ago.
I ran into a scenario where JavaScript behaves in a way that is somewhat baffling to me.
Let's say we have an object with two keys foo & bar.
a = { foo: 1, bar: 2 }
Then, I have an array of strings, in this case one 'foo'
b = ['foo']
I would expect the following:
a[b] == undefined
a[b[0]] == 1
BUT, this is what happens:
a[b] == 1
a[b[0]] == 1
Why does JavaScript convert ['foo'] -> 'foo' when used as a key?
Does anyone out there know the reason?
How can this be prevented?
let a = { foo: 1, bar: 2 }
let b = ['foo']
console.log(a[b] == 1) // expected a[b] to be undefined
console.log(a[b[0]] == 1) // expected a[b] to be 1
All the object keys are string, so it eventually convert everything you place inside [] (Bracket notation) to string, if it's an expression it evaluates the expression and convert it's value to string and use as key
console.log(['foo'].toString())
Have a look at this example to understand, here [a] eventually converts a toString using a.toString() and then set it as key to b object
let a = { a : 1}
let b = {
[a] : a
}
// object converted to string
console.log(a.toString())
// object built using [] computed property access
console.log(b)
How can i stop this
In practical scenarios you should never do this, but just to illustrate, you can intercept or override the toString method of your object and return value as string with [] around:
let a = { foo: 1, bar: 2 }
let b = ['foo']
b.toString = function() {
let string = this.join(',')
return "[" + string + "]"
}
console.log(b.toString())
console.log(a[b])
When using an array as a key, javascript call the 'toString()' method of that array, and then try to find the stringified version of the array as the key. And if you call ['foo'].toString() you see this method returns "foo".
Why does JavaScript convert ['foo'] -> 'foo' when used as a key?
Does anyone out there know the reason?
Any time there is confusion as to why JavaScript acts in a way which may be unexpected, then looking at the language definition is the surefire way to exactly figure out what happened.
https://www.ecma-international.org/ecma-262/10.0/ is the most current language definition at the time of posting this.
First, you will want to find the area pertaining to Array access. It is in language lingo though.
12.3.2.1 Runtime Semantics: Evaluation
MemberExpression : MemberExpression [ Expression ]
...
3. Let propertyNameReference be the result of evaluating Expression.
4. Let propertyNameValue be ? GetValue(propertyNameReference).
6. Let propertyKey be ? ToPropertyKey(propertyNameValue).
So, what is happening here is you are accessing your array (the MemberExpression) using [] with an Expression.
In order to access with [] the Expression will be evaluated, and then GetValue will be called. Then ToPropertyKey will be called.
propertyNameReference = Evaluate Expression b = b
propertyNameValue = GetValue(propertyNameReference) = ['foo']
propertyKey = ToPropertyKey(propertyNameValue) = 'foo'
ToPropertyKey, in our situation, leads to ToPrimitive and then to ToOrdinaryPrimitive which states that we should call "toString" on the argument (['foo'] in our case).
This is where the implementation comes in to play. On the implementation side,
The Array object overrides the toString method of Object. For Array objects, the toString method joins the array and returns one string containing each array element separated by commas" MDN - Array toString
When there is only one value in the array, the result will simply be that value.
How can this be prevented?
This is the current way it is implemented. In order to change that, you must either change the default implementation, use detection to prevent the call, or use guidance to prevent the call.
Guidance
Document and enforce calling mechanisms in your code. This may not always be possible. It is at the very least reasonable to expect programmers to not call property access with arrays though.
Detection
This will depend on the current environment. With the most recent iteration of JavaScript, you can use type enforcement to ensure that property access is Number or String. Typescript makes this rather easy (here is a good example). It would essentially just require the access to be defined as:
function ArrayAccess(value: string | number) {
and this would prevent anyone from using the array as an accessor value.
Default Implementation
Changing the default implementation is a terrible idea. It will more than likely cause all sorts of breaking changes, and should not be done. However, just for completeness, here is what it would look like. Primarily I am showing this so you can hopefully recognize it if you see it somewhere and then kill it with fire (or check in some code to fix it if there were no spiders near it).
var arrayToString = [].toString;
Array.prototype.toString = function(){
if(this.length === 1) return;
return arrayToString.call(this);
};
Changing the instance implementation is not much of a better idea either. That is covered by #Code Maniac in a separate answer. "In practical scenarios you should never do this" #Code Maniac states, which I also agree with.
When using an array as a key, javascript call the 'toString()' method of that array, and then try to find the stringified version of the array as the key. And if you call ['foo'].toString() you see this method returns "foo".
So, i'm trying to make a simple Discord Bot using javascript, and I want to detect if a player username is on the banned list.
I have an array
var banned = ['Andrew','David']
and an if
if (message.author.username instanceof banned) {.....
but when I run it, it outputs
if (message.author.username instanceof banned)
^
TypeError: Right-hand side of 'instanceof' is not callable
What can I do?
This is not what instanceof is for. instanceof is used to see if an object is an instance of a specific constructor (ex: banned instanceof Array).
If you just want to see if an element is in an array, you can use .indexOf().
if(banned.indexOf(message.author.username) != -1)
I was getting the same error on vue / nuxt js.
The problem was setting the prop type wrong:
blog: {
type: {},
required: false,
},
The right way doing it is setting the type Object instead {}
blog: {
type: Object,
required: false,
},
instanceof is used to check if an object is an instance of a class. What you want to do is to check if a string is in an array like this:
if (banned.indexOf(message.author.username) >= 0) {...
instanceof is used to see if an object is of a particular type. You're trying to see if an object is a member of an array.
Try the includes or indexOf methods of the Array object.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/includes
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/indexOf
I know I am late here to answer, but I would definitely consider includes() when it comes to code maintainability and first impression of the code.
ES2016 Specifications included the includes() for Array data structure. The includes() check whether an array includes a certain element, returning true or false as appropriate.
But in ES5 we are used to performing operations like this with indexOf() method.
Why use includes?
The includes method finds NaN and undefined whereas the indexOf method doesn't.
Example to find NAN in the array:
const array = [NaN];
if (array.indexOf(NaN) == -1){
console.log("NaN not found in the array");//NaN not found in the array
}
const array1 = [NaN];
if (array1.includes(NaN)){
console.log("true. NAN was found in the array");// true. NAN was found in the array
}
Example to find undefined in the array:
const array = [, , , ,];
if(array.includes(undefined)){
console.log("true array elements are undefined");// true array elements are undefined
}
const array1 = [, , , ,];
if(!array1.indexOf(undefined) == -1 ){
console.log("true. array elements are undefined");
}else {
console.log("Sorry can't find undefined");// Sorry can't find undefined
}
The includes method does not distinguish between -0 and +0(This is not a bug, but clearly how javascript works.
const a = [-0].includes(+0);
console.log(a);//true
In many cases, I have seen indexOf is little faster than include. It depends where you need to compromise. Also, ES6 includes performance is very fast as compared to lodash's includes method.
Performance comparison source.
I am reading through Eloquent JavaScript and have been stuck trying to understand lists for about two days so I figured I would finally ask a question. The example they give in the book is:
var list = {
value: 1,
rest: {
value: 2,
rest: {
value: 3,
rest: null
}
}
};
Now I think I understand the example... There is a list object and it has properties value and rest. Then, rest has properties of value and rest, etc... However, I don't understand what rest is or even stands for. Does the rest property contain an object? So, list.rest.value would == 2? How is this useful? Some ways I could see this as useful are having a list Car, with prop engine, gauge, etc, with further properties of accelerate, brake, low fuel... How would something like this be achieved?
I do apologize for the "all overness" of this post, I don't exactly know what to ask or how to phrase it. It seems like the book only explained objects and properties, but never actually having objects as an objects property.
Thank you all in advance, and if you need any clarification or more info I will try to provide it.
This code simply uses JavaScript Object Notion to define an object named list.
// Would simply define an empty object.
var list = {};
Now you can add some properties to the object.
// Would define an object with a single property: `value`.
var list = {
value: 1
};
Using nested object declarations, you can give the list object child objects as well:
var list = {
value: 1,
rest: {}
};
Now list.rest is an empty object. You can fill that out by adding some properties:
var list = {
value: 1,
rest: {
value: 2
}
};
And your nesting can continue ad-infinitum. The object in your original post, the following is possible:
console.log(list.value); // 1
console.log(list.rest.value); // 2
console.log(list.rest.rest.value); // 3
It's important to understand that this in no way creates a class or includes any additional methods with the object. It seems to be structured as a linked list but provides no functionality to add/remove/modify (except by directly modifying the original object).
In the example above the list variable is an associative array. This is JavaScript's version of an "object". While the property list.value ends up being typed as an integer, the property list.rest is typed as a nested associative array. The properties themselves can be any valid type. Many jQuery plugins are coded where the properties themselves are actually delegate functions.
The object you have described above in the example does not seem to me to be terribly useful beyond being an example of how this kind of object can contain references to other objects. However, when you begin applying this in an "object oriented" concept (keep in mind that it is not truly object oriented), it becomes more useful. You can then create your own "namespace" with properties, functions and delegates that can be re-used time and again.
Thank you all for your information. I don't know if there is a best answer selection on this site or not, but I really do appreciate the help Justin, Joel, and Evan. I think the main part I was confused about is just practical application for real applications. I have messed around a little bit and came up with this and have a much better basic understanding now:
var car = {
engine: {
turn_on: "Turned engine on",
turn_off: "Turned engine off",
desc: {
size: "V6",
year: 2000
}
},
fuel: {
level: 55
}
};
function CheckFuel(fuel){
if(fuel > 50){
console.log("In good shape");
}
else{
console.log("We should fuel up");
}
}
console.log(car.engine.turn_on);
console.log(car.engine.turn_off);
console.log(car.engine.desc.size);
console.log(car.engine.desc.year);
CheckFuel(car.fuel.level);
Now time to practice iterating through. Thanks again!
This is an implementation of a linked list. Each node in the list has a reference to the next node. 'Rest' is an object (the next node in the list) that also contains every other node in the list (via it's rest property).
The first value in the list would be list.value;. The second value in the list would be list.rest.value;. The items in the list can be shown as:
item1 = list;
item2 = list.rest;
item3 = item2.rest;
This continues until itemX.rest is null.
These two functions could be used to manage the list and may help you understand how iterating through it would work:
function addToList(item)
{
if(!list)
{
list = item;
return;
}
var temp = list;
while(temp.rest)
{
temp = temp.rest;
}
temp.rest = item;
}
function printList()
{
var temp = list;
while (temp)
{
print temp.value; //i'm not sure what the javascript print function is
temp = temp.rest
}
}
The add function would be called like this: addToList({ value:10, rest:null });
So recently I was doing a node school challenge,
Here's the task:
Return a function that takes a list of valid users, and returns a function that returns true
if all of the supplied users exist in the original list of users.
Here's the solution:
module.exports = function (goodUsers) {
return function (submittedUsers) {
return submittedUsers.every(function (submittedUser) {
return goodUsers.some(function (goodUser) {
return goodUser.id === submittedUser.id;
});
});
};
};
Basically its a function that takes in an object of ids and compares it with another one.
it returns true if if the second objects' ids are in the first object.
Here's an example: http://s8.postimg.org/ql8df5iat/Screen_Shot_2014_02_01_at_5_32_07_PM.png
However I've read the MDN examples for awhile and just can't seem to understand why this solution works! Can someone walk me through step by step on what's actually happening here? Why does this work? How do the every() and some() methods handle the differences is array length? etc
-Thanks
Actually the functions every and some don’t care about array length.
every will just execute an arbitrary code for each element of your first array.
some will just return true if there is at least one object with the same id' in the second array.
Note === this will "short circuit" in the case of null or undefined values.
Hope this helps.
Personally, I prefer the double “for” loop syntax as I think it is more readable.