Detect if parameter passed is an array? Javascript [duplicate] - javascript

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
How to detect if a variable is an array
I have a simple question:
How do I detect if a parameter passed to my javascript function is an array? I don't believe that I can test:
if (typeof paramThatCouldBeArray == 'array')
So is it possible?
How would I do it?
Thanks in advance.

if (param instanceof Array)
...
Edit. As of 2016, there is a ready-built method that catches more corner cases, Array.isArray, used as follows:
if (Array.isArray(param))
...

This is the approach jQuery 1.4.2 uses:
var toString = param.prototype.toString;
var isArray = function(obj) {
return toString.call(obj) === "[object Array]";
}

I found this here:
function isArray(obj) {
return obj.constructor == Array;
}
also this one
function isArray(obj) {
return (obj.constructor.toString().indexOf(”Array”) != -1);
}

You can test the constructor property:
if (param.constructor == Array) {
...
}
Though this will include objects that have an array prototype,
function Stack() {
}
Stack.prototype = [];
unless they also define constructor:
Stack.prototype.constructor = Stack;
or:
function Stack() {
this.constructor = Stack;
}

Some days ago I was building a simple type detection function, maybe its useful for you:
Usage:
//...
if (typeString(obj) == 'array') {
//..
}
Implementation:
function typeString(o) {
if (typeof o != 'object')
return typeof o;
if (o === null)
return "null";
//object, array, function, date, regexp, string, number, boolean, error
var internalClass = Object.prototype.toString.call(o)
.match(/\[object\s(\w+)\]/)[1];
return internalClass.toLowerCase();
}
The second variant of this function is more strict, because it returns only object types described in the ECMAScript specification (possible output values: "object", "undefined", "null", and "function", "array", "date", "regexp", "string", "number", "boolean" "error", using the [[Class]] internal property).

Duck Typying
Actually, you don't necessarily want to check that an object is an array. You should duck type it and the only thing you want that object to implement is the length property. After this you can transform it into an array:
var arrayLike = {
length : 3,
0: "foo"
};
// transform object to array
var array = Array.prototype.slice.call(arrayLike);
JSON.stringify(array); // ["foo", null, null]
Array.prototype.slice.call(object) will transform into an array every object that exposes a length property. In the case of strings for example:
var array = Array.prototype.slice.call("123");
JSON.stringify(array); // ["1", "2", "3"]
Well, this technique it's not quite working on IE6 (I don't know about later versions), but it's easy to create a small utility function to transform objects in arrays.

Related

How to check whether an object is empty? [duplicate]

This question already has answers here:
How do I test for an empty JavaScript object?
(48 answers)
Closed 7 months ago.
I'm learing JavaScript. I cannot grasp the idea of an empty object. As I understand, there are situations when I need to check a variable whether it holds an object and has a value.
So far, I know that a variable can be undefined.
var car; // the value is undefined, as well as the type (which is it? number, array, etc.)
I also know, that everything that has a value, is true:
var car = "Opel";
Boolean(car); // true
And anything without a value is false:
var car = ""; // typeof string, but it is empty, so
Boolean(car); // false
Boolean(null); // false
So why doesn't it work the same way with arrays and objects? Why is all of this true? Shouldn't empty arrays and objects return false?
var car = {make: "Opel", year: 2015};
Boolean(car); // true
car = {};
Boolean(car); // true
car = ["BMW", "Opel"];
Boolean(car); // true
car = [];
Boolean(car); // true
Now I see that there are methods, that can be applied to check an object's length, I just haven't reached that part yet.
I'm learning at W3Schools website and this bit just got me puzzled:
But you cannot test if an object is null, because this will throw an error if the object is undefined:
Incorrect:
if (myObj === null)
To solve this problem, you must test if an object is not null, and not undefined.
But this can still throw an error:
Incorrect:
if (myObj !== null && typeof myObj !== "undefined")
Because of this, you must test for not undefined before you can test for not null:
Correct:
if (typeof myObj !== "undefined" && myObj !== null)
I still cannot understand the last line here.
Checking if an object is empty:
Object.keys(yourObject).length
var car = {};
var isEmpty = Object.entries(car).length > 0; //false
var car = {make: "Opel", year: 2015};
var isEmpty = Object.entries(car).length > 0; //true
This should solve your problem, if your curious about the utility function Object.entries you can look on mdn
I also know, that everything that has a value, is true
I wouldn't say that. All the examples given are values, even undefined and null are predefined values in JavaScript.
Shouldn't empty arrays and objects return false?
It is like that by specification. And that is really the answer to your question. It is a choice made by the designers of the language.
You could find some logic in it though. In JavaScript, values representing objects (and so also arrays) are references. These references are memory addresses/pointers, and although you cannot find out what exactly those addresses are, these are non-zero, even when an object has no properties.
Note that your example objects ({} and []) still have some non-enumerable properties, such a __proto__ and (for array) length, so they are not really as empty as you think.
The most empty object you can create, is: Object.create(null)
You can check wheather a object is empty or not in this simple way.
function objectLength( object ) {
return Object.keys(object).length;
}
if(objectLength(yourObject) == 0){
//object is empty
}else{
//object not empty
}
Checking if an object is empty:
Reflect.ownKeys(car).length
Returns an array with one element when a Symbol is used as the key:
let key = Symbol('vin')
let car = { [key]: 'honda' }
Reflect.ownKeys(car).length // => 1
Whereas Object.keys returns an array with zero elements in this case:
let key = Symbol('vin')
let car = { [key]: 'honda' }
Object.keys(car).length // => 0
I would always use typeof myvar !== 'undefined' and checks for content myvar !== ''
This would always would have a clear result.
There are concepts which are Truthy and Falsy values in JavaScript.
I highly recommend you to read MDN documents about this issue.
All values are truthy unless they are defined as falsy (i.e., except for false, 0, -0, 0n, "", null, undefined, and NaN).
Truthy values
Falsy values
No, they should not be false.
All objects are 'truthy', in that they return true when evaluated as a Boolean. In Javascript, all arrays are objects (try console.log(typeof [])), so they also return true, regardless of whether or not they are empty.
To check if any array is empty:
if (MYARRAY.length === 0) {
// console.log(true);
}
To check if an object is empty:
if (Object.keys(MYOBJECT).length === 0) {
// console.log(true);
}
You can use
if ($('#element').is(':empty')){
//do something
}
OR
function isEmpty( el ){
return !$.trim(el.html())
}
if (isEmpty($('#element'))) {
// do something
}
Here are some examples: http://api.jquery.com/is/
But if you need it in JavaScript:
if( typeof foo !== 'undefined' ) {
// foo could get resolved and it's defined
}
You can simply use typeof

Parsing JSON value fields is array or not. ( Javascript) [duplicate]

This question already has answers here:
How do I check if a variable is an array in JavaScript?
(24 answers)
Closed 1 year ago.
I'm trying to write a function that either accepts a list of strings, or a single string. If it's a string, then I want to convert it to an array with just the one item so I can loop over it without fear of an error.
So how do I check if the variable is an array?
The method given in the ECMAScript standard to find the class of Object is to use the toString method from Object.prototype.
if(Object.prototype.toString.call(someVar) === '[object Array]') {
alert('Array!');
}
Or you could use typeof to test if it is a string:
if(typeof someVar === 'string') {
someVar = [someVar];
}
Or if you're not concerned about performance, you could just do a concat to a new empty Array.
someVar = [].concat(someVar);
There's also the constructor which you can query directly:
if (somevar.constructor.name == "Array") {
// do something
}
Check out a thorough treatment from T.J. Crowder's blog, as posted in his comment below.
Check out this benchmark to get an idea which method performs better: http://jsben.ch/#/QgYAV
From #Bharath, convert a string to an array using ES6 for the question asked:
const convertStringToArray = (object) => {
return (typeof object === 'string') ? Array(object) : object
}
Suppose:
let m = 'bla'
let n = ['bla','Meow']
let y = convertStringToArray(m)
let z = convertStringToArray(n)
console.log('check y: '+JSON.stringify(y)) . // check y: ['bla']
console.log('check y: '+JSON.stringify(z)) . // check y: ['bla','Meow']
In modern browsers you can do:
Array.isArray(obj)
(Supported by Chrome 5, Firefox 4.0, Internet Explorer 9, Opera 10.5 and Safari 5)
For backward compatibility you can add the following:
// Only implement if no native implementation is available
if (typeof Array.isArray === 'undefined') {
Array.isArray = function(obj) {
return Object.prototype.toString.call(obj) === '[object Array]';
}
};
If you use jQuery you can use jQuery.isArray(obj) or $.isArray(obj). If you use Underscore.js you can use _.isArray(obj).
If you don't need to detect arrays created in different frames you can also just use instanceof:
obj instanceof Array
I would first check if your implementation supports isArray:
if (Array.isArray)
return Array.isArray(v);
You could also try using the instanceof operator
v instanceof Array
jQuery also offers an $.isArray() method:
var a = ["A", "AA", "AAA"];
if($.isArray(a)) {
alert("a is an array!");
} else {
alert("a is not an array!");
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
This is the fastest among all methods (all browsers supported):
function isArray(obj){
return !!obj && obj.constructor === Array;
}
Imagine you have this array below:
var arr = [1,2,3,4,5];
JavaScript (new and older browsers):
function isArray(arr) {
return arr.constructor.toString().indexOf("Array") > -1;
}
or
function isArray(arr) {
return arr instanceof Array;
}
or
function isArray(arr) {
return Object.prototype.toString.call(arr) === '[object Array]';
}
Then call it like this:
isArray(arr);
JavaScript (Internet Explorer 9+, Chrome 5+, Firefox 4+, Safari 5+, and Opera 10.5+)
Array.isArray(arr);
jQuery:
$.isArray(arr);
Angular:
angular.isArray(arr);
Underscore.js and Lodash:
_.isArray(arr);
Array.isArray works fast, but it isn't supported by all versions of browsers.
So you could make an exception for others and use a universal method:
Utils = {};
Utils.isArray = ('isArray' in Array) ?
Array.isArray :
function (value) {
return Object.prototype.toString.call(value) === '[object Array]';
}
A simple function to check this:
function isArray(object)
{
return object.constructor === Array;
}
You can use Array.isArray(). Here is a polyfill:
if (Array.isArray == null) {
Array.isArray = (arr) => Object.prototype.toString.call(arr) === "[object Array]"
}
As MDN says in here:
use Array.isArray or Object.prototype.toString.call to differentiate
regular objects from arrays
Like this:
Object.prototype.toString.call(arr) === '[object Array]', or
Array.isArray(arr)
There's just one line solution for this question
x instanceof Array
where x is the variable it will return true if x is an array and false if it is not.
I would make a function to test the type of object you are dealing with...
function whatAmI(me){ return Object.prototype.toString.call(me).split(/\W/)[2]; }
// tests
console.log(
whatAmI(["aiming","#"]),
whatAmI({living:4,breathing:4}),
whatAmI(function(ing){ return ing+" to the global window" }),
whatAmI("going to do with you?")
);
// output: Array Object Function String
then you can write a simple if statement...
if(whatAmI(myVar) === "Array"){
// do array stuff
} else { // could also check `if(whatAmI(myVar) === "String")` here to be sure
// do string stuff
}
You can check the type of your variable whether it is an array with;
var myArray=[];
if(myArray instanceof Array)
{
....
}
I do this in a very simple way. It works for me.
Array.prototype.isArray = true;
a=[]; b={};
a.isArray // true
b.isArray // (undefined -> false)
This is my attempt to improve on this answer taking into account the comments:
var isArray = myArray && myArray.constructor === Array;
It gets rid of the if/else, and accounts for the possibility of the array being null or undefined
I have updated the jsperf fiddle with two alternative methods as well as error checking.
It turns out that the method defining a constant value in the 'Object' and 'Array' prototypes is faster than any of the other methods. It is a somewhat surprising result.
/* Initialisation */
Object.prototype.isArray = function() {
return false;
};
Array.prototype.isArray = function() {
return true;
};
Object.prototype._isArray = false;
Array.prototype._isArray = true;
var arr = ["1", "2"];
var noarr = "1";
/* Method 1 (function) */
if (arr.isArray()) document.write("arr is an array according to function<br/>");
if (!noarr.isArray()) document.write("noarr is not an array according to function<br/>");
/* Method 2 (value) - **** FASTEST ***** */
if (arr._isArray) document.write("arr is an array according to member value<br/>");
if (!noarr._isArray) document.write("noarr is not an array according to member value<br/>");
These two methods do not work if the variable takes the undefined value, but they do work if you are certain that they have a value. With regards to checking with performance in mind if a value is an array or a single value, the second method looks like a valid fast method. It is slightly faster than 'instanceof' on Chrome, twice as fast as the second best method in Internet Explorer, Opera and Safari (on my machine).
I know, that people are looking for some kind of raw JavaScript approach. But if you want think less about it, take a look at Underscore.js' isArray:
_.isArray(object)
It returns true if object is an Array.
(function(){ return _.isArray(arguments); })();
=> false
_.isArray([1,2,3]);
=> true
The best practice is to compare it using constructor, something like this
if(some_variable.constructor === Array){
// do something
}
You can use other methods too, like typeOf, converting it to a string and then comparing, but comparing it with dataType is always a better approach.
The best solution I've seen is a cross-browser replacement for typeof. Check Angus Croll's solution.
The TL;DR version is below, but the article is a great discussion of the issue so you should read it if you have time.
Object.toType = function(obj) {
return ({}).toString.call(obj).match(/\s([a-z|A-Z]+)/)[1].toLowerCase();
}
// ... and usage:
Object.toType([1,2,3]); //"array" (all browsers)
// or to test...
var shouldBeAnArray = [1,2,3];
if(Object.toType(shouldBeAnArray) === 'array'){/* do stuff */};
If the only two kinds of values that could be passed to this function are a string or an array of strings, keep it simple and use a typeof check for the string possibility:
function someFunc(arg) {
var arr = (typeof arg == "string") ? [arg] : arg;
}
Here's my lazy approach:
if (Array.prototype.array_ === undefined) {
Array.prototype.array_ = true;
}
// ...
var test = [],
wat = {};
console.log(test.array_ === true); // true
console.log(wat.array_ === true); // false
I know it's sacrilege to "mess with" the prototype, but it appears to perform significantly better than the recommended toString method.
Note: A pitfall of this approach is that it wont work across iframe boundaries, but for my use case this is not an issue.
This function will turn almost anything into an array:
function arr(x) {
if(x === null || x === undefined) {
return [];
}
if(Array.isArray(x)) {
return x;
}
if(isString(x) || isNumber(x)) {
return [x];
}
if(x[Symbol.iterator] !== undefined || x.length !== undefined) {
return Array.from(x);
}
return [x];
}
function isString(x) {
return Object.prototype.toString.call(x) === "[object String]"
}
function isNumber(x) {
return Object.prototype.toString.call(x) === "[object Number]"
}
It uses some newer browser features so you may want to polyfill this for maximum support.
Examples:
> arr(null);
[]
> arr(undefined)
[]
> arr(3.14)
[ 3.14 ]
> arr(1/0)
[ Infinity ]
> gen = function*() { yield 1; yield 2; yield 3; }
[Function: gen]
> arr(gen())
[ 1, 2, 3 ]
> arr([4,5,6])
[ 4, 5, 6 ]
> arr("foo")
[ 'foo' ]
N.B. strings will be converted into an array with a single element instead of an array of chars. Delete the isString check if you would prefer it the other way around.
I've used Array.isArray here because it's the most robust and also simplest.
The following could be used if you know that your object doesn't have a concat method.
var arr = [];
if (typeof arr.concat === 'function') {
console.log("It's an array");
}
var a = [], b = {};
console.log(a.constructor.name == "Array");
console.log(b.constructor.name == "Object");
There is a nice example in Stoyan Stefanov's book JavaScript Patterns which is supposed to handle all possible problems as well as use the ECMAScript 5 method Array.isArray().
So here it is:
if (typeof Array.isArray === "undefined") {
Array.isArray = function (arg) {
return Object.prototype.toString.call(arg) === "[object Array]";
};
}
By the way, if you are using jQuery, you can use its method $.isArray().
You could use the isArray method, but I would prefer to check with:
Object.getPrototypeOf(yourvariable) === Array.prototype
function isArray(value) {
if (value) {
if (typeof value === 'object') {
return (Object.prototype.toString.call(value) == '[object Array]')
}
}
return false;
}
var ar = ["ff","tt"]
alert(isArray(ar))
A simple function for testing if an input value is an array is the following:
function isArray(value)
{
return Object.prototype.toString.call(value) === '[object Array]';
}
This works cross browser, and with older browsers. This is pulled from T.J. Crowders' blog post
You can try this:
var arr = []; (or) arr = new Array();
var obj = {}; (or) arr = new Object();
arr.constructor.prototype.hasOwnProperty('push') //true
obj.constructor.prototype.hasOwnProperty('push') // false
In your case you may use concat method of Array which can accept single objects as well as array (and even combined):
function myFunc(stringOrArray)
{
var arr = [].concat(stringOrArray);
console.log(arr);
arr.forEach(function(item, i)
{
console.log(i, "=", item);
})
}
myFunc("one string");
myFunc(["one string", "second", "third"]);
concat seems to be one of the oldest methods of Array (even IE 5.5 knows it well).

How to make a method that can affect any value type?

Warning: creating extensions to native object and/or properties is considered bad form, and is bound to cause problems. Do not use this if it is for code that you are not using solely for you, or if you don't know how to use it properly
I know you can use Object, String, Number, Boolean, etc. to define a method, something like this:
String.prototype.myFunction = function(){return this;} //only works on strings.
But what I need to be able to do is use that on any value, and access the value in the function.
I googled, and looked here, but couldn't find anything suitable.
2/18/15 Edit: Is there any workaround to having this be a property of any Object if I use Object.prototype?
Per Request, here is the current function that is used for isString()
function isString(ins) {
return typeof ins === "string";
}
Following on a few answers, I have come up with some code and errors caused by it.
Object.prototype.isString = function() {
return typeof this === "string";
}
"5".isString() //returns false
"".isString() //returns false
var str = "string"
str.isString() //returns false
A “dot operator function” is called a method. The cleanest way to create a method in JavaScript that can work on any data type is to create a wrapper. For example:
var Wrapper = defclass({
constructor: function (value) {
this.value = value;
},
isString: function () {
return typeof this.value === "string";
},
describe: function () {
if (this.isString()) {
alert('"' + this.value + '" is a string.');
} else {
alert(this.value + " is not a string.");
}
}
});
var n = new Wrapper(Math.PI);
var s = new Wrapper("Hello World!");
n.describe(); // 3.141592653589793 is not a string.
s.describe(); // "Hello World!" is a string.
function defclass(prototype) {
var constructor = prototype.constructor;
constructor.prototype = prototype;
return constructor;
}
By creating your own wrapper constructor you ensure that:
Your code doesn't mess with other peoples' code.
Other people's code doesn't mess with your code.
You keep the global scope and native prototypes clean.
Several popular JavaScript libraries like underscore and lodash create wrapper constructors for this very purpose.
First of all, why defining properties on Object (or other builtin types) is frowned upon - they show up in unexpected places. Here is some code that outputs the total number of feet some characters have:
var feetMap = {
jerry : 4,
donald : 2,
humpty: 0
}
function countFeet(feetMap) {
var allFeet = 0;
for (var character in feetMap) {
allFeet += feetMap[character];
}
return allFeet;
}
console.log('BEFORE DEFINITION', countFeet(feetMap));
Object.prototype.isString = function() {
return typeof this === "string";
};
console.log('AFTER DEFINITION', countFeet(feetMap));
Note how simply defining your isString function will influence the result of the countFeet function which now iterates over one unexpected property. Of course, this can be avoided if the iteration was protected with hasOwnProperty check, or if the property was defined as non-enumerable.
Another reason to avoid defining properties on builtin types it the possibility of collision. If everyone defined their own isNumber method that gave slightly different results depending on use cases - one could consider the string "42" a number and another could say it's not - subtile bugs would crop all over the place when people used multiple libraries.
The question is - why do you need a method that can affect any value type? A method should be something that is inherent to the class of objects it belongs to. Having an isString method makes no sense on a Number object - it simply doesn't have any relevance to Numbers.
What makes more sense is to have a function/method that can return the type of the value given to it as parameter:
var Util = Util || {};
Util.isString(value) {
return typeof value === "string";
}
Util.isString('test') // true
Util.isString(5) // false
The reason why your current code
Object.prototype.isString = function() {
return typeof this === "string";
}
"5".isString() //returns false
"".isString() //returns false
var str = "string"
str.isString() //returns false
isn't working is because when you access a property on a primitive value, JS creates a wrapper object of the apropriate types and resolves the property on that wrapper object (after which it throws it away). Here is an example that should elucidate it:
Object.prototype.getWrapper = function(){
return this;
}
console.log((5).getWrapper()); // Number [[PrimitiveValue]]:5
console.log("42".getWrapper()); // String [[PrimitiveValue]]:"42"
Note that the primitive value 5 and the object new Number(5) are different concepts.
You could alter your function to mostly work by returning the type of the primitive value. Also, don't forget to make it non-enumerable so it doesn't show up when you iterate over random Objects.
Object.defineProperty(Object.prototype, 'isString', {
value : function() {
return typeof this.valueOf() === "string";
},
enumerable : false
});
"5".isString() //returns true
"".isString() //returns true
var str = "string"
str.isString() //returns true
Object.prototype.isString = function() {
return typeof this === "string";
}
"5".isString() //returns false
"".isString() //returns false
var str = "string"
str.isString() //returns false
If anyone could explain a workaround for the function being a property of any object, and why the current method isn't working, I will provide 125 rep.
Answer:
Well in javascript, when you are calling a sub method/property of a object, like "myFunction" (object.myFunction or object["MyFunction"])
it will start to see if the object itself have it.
IF NOT: it will follow the prototype chain(like superclass in normal oop),
until it finds a "parent/superclass" with the method/property.
The last step in this prototype chain is Object.
If Object dosnt have the method, it will return "undefined".
When you extending the Object class itself it will alway look at
any object calling the method as a Object (In oop: All classes are also Object in addition the is own classtype)
This is like missing a "cast" in normal OOP.
So the reason why your function returns false is that its a "object" not a "string" in this context
Try making this function:
Object.prototype.typeString = function() {
return typeof this;
}
"5".typeString() //returns "object"
As everbody says it really bad idea to extend any of the native JS classes, but a workaround would start with something like this:
Object.prototype.objectTypeString = function(){
return Object.prototype.toString.call(this);
}
Here is a fiddle:
http://jsfiddle.net/fwLpty10/13/
Note that null dosnt have prototype and NaN (NotANumber) is condidered a Number!!!
This means that you will always need to check is a variable is null,
before calling this method!
Object.prototype.isString = function(){
return Object.prototype.toString.call(this) === "[object String]";
};
Final fiddle: http://jsfiddle.net/xwshjk4x/5/
The trick here is that this methods returns the result of the toString method, that are called with "this", which means that in the context of the toString method, the object you call it on, are its own class (not just any supertype in the prototype chain )
The code posted that extends the Object prototype will work, if corrected.
However, it makes an incorrect assumption about what this is inside the invoked method. With the posted code the following output is correct and to be expected (barring a few old implementation bugs);
"5".isString() //returns false
This is because JavaScript will "wrap" or "promote" the primitive value to the corresponding object type before it invokes the method - this is really a String object, not a string value. (JavaScript effectively fakes calling methods upon primitive values.)
Replace the function with:
Object.prototype.isString = function() {
return this instanceof String;
}
Then:
"5".isString() // => true (a string was "promoted" to a String)
(5).isString() // => false (`this` is a Number)
Another solution to this is also to use polymorphism; with the same "pitfalls"1 of modifying standard prototypes.
Object.prototype.isString = function () { return false; }
String.prototype.isString = function () { return true; }
1The concern of adding a new enumerable property to the global protoypes can be mitigated with using defineProperty which creates a "not enumerable" property by default.
Simply change
x.prototype.y = ..
to
Object.defineProperty(x.prototype, 'y', { value: .. })
(I am not defending the use of modifying the prototype; just explaining the original problematic output and pointing out a way to prevent the enumeration behavior.)
To show u some example:
String.prototype.myFunction = function() {
return this+"asd";
};
this function will add "asd" to each string when myFunction() is called.
var s = "123";
s = s.myFunction();
//s is now "123asd"
Before we start, few important statements to remember and be aware of (true for all string literal/primitive, String object, number literal/primitive, Number object etc.):
All objects in JavaScript are descended from Object and inherit methods and properties from Object.prototype – String, Number etc (much like Java).
JS has 6 primitive types – string, number, boolean, null, undefined and symbol
JS has their corresponding wrapper objects – String, Number, Boolean and Symbol
As you can see above, JS has string as a primitive as well an Object
Primitive is not of type Object.
String literal is a primitive and String object is of type Object.
The instanceof operator tests whether an object has in its prototype chain the prototype property of a constructor. (first condition to get TRUE here is that instanceof should be used against an Object or its subclass)
The typeof operator returns a string indicating the type of the unevaluated operand.
String as primitive:
String primitive or literal can be constructed in following ways:
var str1 = “Hello”;
var str2 = String(“Hello”);
typeof str1; //Output = "string"
typeof str2; //Output = "string"
str1 instanceof (String || Object) //Output = false because it is a primitive not object
str2 instanceof (String || Object) //Output = false because it is a primitive not object
String as Object:
String object can be constructed by calling its constructor from new object:
var str3 = new String(“Hello”);
typeof str3; //Output = "string"
str3 instanceof (String) //Output = true because it is a String object
str3 instanceof (Object) //Output = true because it is an Object
Above all may look little obvious but it was necessary to set the ground.
Now, let me talk about your case.
Object.prototype.isString = function() {
return typeof this === "string";
}
"5".isString() //returns false
"".isString() //returns false
var str = "string"
str.isString() //returns false
You are getting FALSE as o/p because of concept called as Auto-boxing. When you call any method on string literal then it gets converted to String object. Read this from MSDN - “Methods for String Literals”, to be sure in yourself.
So, in your prototype when you will check type using typeof then it will never be a literal (typeof == "string") because it is already converted into an object. That's the reason you were getting false, if you will check typeof for object then you will get true, which I am going to talk in detail below:
typeof will give information on what type of entity it is - an object or a primitive (string, number etc) or a function.
instanceof will give information on what type of JS Object it is - Object or String or Number or Boolean or Symbol
Now let me talk about solution which is provided to you. It says to do a instanceof check, which is 100% correct, but with a note that upon reaching your prototype it could be of object type or function type. So, the solution which I am providing below will give you a picture of the same.
My recommendation is to have a generic function which would return you the type of instance, and then you can do whatever you want based on if it is a Number or String etc. isString is good but then you have to write isNumber etc., so instead have a single function which will return you the type of instance and can even handle function type.
Below is my solution:
Object.prototype.getInstanceType = function() {
console.log(this.valueOf());
console.log(typeof this);
if(typeof this == "object"){
if(this instanceof String){
return "String";
} else if(this instanceof Boolean){
return "Boolean";
} else if(this instanceof Number){
return "Number";
} else if(this instanceof Symbol){
return "Symbol";
} else{
return "object or array"; //JSON type object (not Object) and array
}
} else if(typeof this == "function"){
return "Function";
} else{
//This should never happen, as per my knowledge, glad if folks would like to add...
return "Nothing at all";
}
}
Output:
new String("Hello").getInstanceType() //String
"Hello".getInstanceType() //String
(5).getInstanceType() //Number
(true).getInstanceType() //Boolean
Symbol().getInstanceType() //Symbol
var ddd = function(){}
var obj = {}
obj.getInstanceType() //object or array
var arr = []
arr.getInstanceType() //object or array
ddd.getInstanceType() //Function
($).getInstanceType() //Function, because without double quotes, $ will treated as a function
("$").getInstanceType() //String, since it came in double quotes, it became a String
To wrap up: Your 2 concerns as below
But what I need to be able to do is use that on any value, and access
the value in the function.
You can access the value in your function using this. In my solution you can see console.log(this.valueOf());
Is there any workaround to having this be a property of any Object if
I use Object.prototype?
You can achieve it from Object.prototype.getInstanceType as per above solution, and you can invoke it on any valid JS object and you will get the desired information.
Hope this helps!
From the MDN Description of Object:
All objects in JavaScript are descended from Object
So, you can add methods to Object.prototype, which can then be called on anything. For example:
Object.prototype.isString = function() {
return this.constructor.name === 'String';
}
console.log("hi".isString()); //logs true
console.log([].isString()); //logs false
console.log(5..isString()); //logs false
You could create this isX functions for each type of primitive there is, if you wanted. Either way, you can add methods to every type, since everything in JavaScript descends from an Object.
Hope that helps, and good luck :)
--edit--
I did want to point out that just because you can do this doesn't mean that you should. It's generally a bad practice to extend built-in functionality of JavaScript, even more so for a library that others will use. It depends on your use-case, though. Best of luck.
Discussions aside, that this is not good practice and not a common approach like the wrapper-constructor, you should achieve this with either asking for the constructor's name:
Object.defineProperty(Object.prototype, 'isString', {
value: function() { return this.constructor.name === "String"; }
});
or with the also already mentioned instanceof method:
Object.defineProperty(Object.prototype, 'isString', {
value: function() { return this instanceof String; }
});
Explanation why your method didn't work is taking care of in this post.
If you want your new defined property to be enumerable, configurable or writable, you should take a look at the docs for defineProperty.
As a few others have pointed out your code is almost correct expect for the typeof this === 'string' part which doesn't work due to JavaScript's quirky behavior when it comes to primitives vs. objects. One of the most robust ways to test if an object is a string is with Object.prototype.toString.call(this) === '[object String]' (check out this article). With that in mind you could simply write your implementation of isString like so:
Object.prototype.isString = function () {
return Object.prototype.toString.call(this) === '[object String]';
};
"abc".isString(); // ==> true
"".isString(); // ==> true
1..isString(); // ==> false
{}.isString(); // ==> false
This is because string literals are of native string type, not actually an instance of String object so, in fact, you cannot actually call any method from Object or String prototype.
What is happening is that when you try to call any method over a variable which type is string, Javascript is automatically coercing that value to a newly constructed String object.
So
"abc".isString();
Is the same as:
(new String("abc")).isString();
The side effect of that is that what you are receiving in your isString() method is an (variable of type) Object which, also, is an instance of the String object.
Maybe you could see it more clearly with a simplified example:
var a = "Hello";
console.log(typeof a); // string
var b = new String("Hello");
console.log(typeof b); // object
By the way, the best chance you have to detect string in your function, as many others said, is to check if it is an instance of the String object with:
foo instanceof String
If you want to also check over other possible types, you should do a double check like the following:
function someOtherFn(ins) {
var myType = typeOf ins;
if (myType == "object" && ins instanceof String) myType = "string";
// Do more stuf...
}

Deep comparison of objects/arrays [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
How do you determine equality for two JavaScript objects?
Object comparison in JavaScript
If I have two arrays or objects and want to compare them, such as
object1 = [
{ shoes:
[ 'loafer', 'penny' ]
},
{ beers:
[ 'budweiser', 'busch' ]
}
]
object2 = [
{ shoes:
[ 'loafer', 'penny' ]
},
{ beers:
[ 'budweiser', 'busch' ]
}
]
object1 == object2 // false
this can be annoying if you're getting a response from a server and trying to see if it's changed
Update:
In response to the comments and worries surrounding the original suggestion (comparing 2 JSON strings), you could use this function:
function compareObjects(o, p)
{
var i,
keysO = Object.keys(o).sort(),
keysP = Object.keys(p).sort();
if (keysO.length !== keysP.length)
return false;//not the same nr of keys
if (keysO.join('') !== keysP.join(''))
return false;//different keys
for (i=0;i<keysO.length;++i)
{
if (o[keysO[i]] instanceof Array)
{
if (!(p[keysO[i]] instanceof Array))
return false;
//if (compareObjects(o[keysO[i]], p[keysO[i]] === false) return false
//would work, too, and perhaps is a better fit, still, this is easy, too
if (p[keysO[i]].sort().join('') !== o[keysO[i]].sort().join(''))
return false;
}
else if (o[keysO[i]] instanceof Date)
{
if (!(p[keysO[i]] instanceof Date))
return false;
if ((''+o[keysO[i]]) !== (''+p[keysO[i]]))
return false;
}
else if (o[keysO[i]] instanceof Function)
{
if (!(p[keysO[i]] instanceof Function))
return false;
//ignore functions, or check them regardless?
}
else if (o[keysO[i]] instanceof Object)
{
if (!(p[keysO[i]] instanceof Object))
return false;
if (o[keysO[i]] === o)
{//self reference?
if (p[keysO[i]] !== p)
return false;
}
else if (compareObjects(o[keysO[i]], p[keysO[i]]) === false)
return false;//WARNING: does not deal with circular refs other than ^^
}
if (o[keysO[i]] !== p[keysO[i]])//change !== to != for loose comparison
return false;//not the same value
}
return true;
}
But in many cases, it needn't be that difficult IMO:
JSON.stringify(object1) === JSON.stringify(object2);
If the stringified objects are the same, their values are alike.
For completeness' sake: JSON simply ignores functions (well, removes them all together). It's meant to represent Data, not functionality.
Attempting to compare 2 objects that contain only functions will result in true:
JSON.stringify({foo: function(){return 1;}}) === JSON.stringify({foo: function(){ return -1;}});
//evaulutes to:
'{}' === '{}'
//is true, of course
For deep-comparison of objects/functions, you'll have to turn to libs or write your own function, and overcome the fact that JS objects are all references, so when comparing o1 === ob2 it'll only return true if both variables point to the same object...
As #a-j pointed out in the comment:
JSON.stringify({a: 1, b: 2}) === JSON.stringify({b: 2, a: 1});
is false, as both stringify calls yield "{"a":1,"b":2}" and "{"b":2,"a":1}" respectively. As to why this is, you need to understand the internals of chrome's V8 engine. I'm not an expert, and without going into too much detail, here's what it boils down to:
Each object that is created, and each time it is modified, V8 creates a new hidden C++ class (sort of). If object X has a property a, and another object has the same property, both these JS objects will reference a hidden class that inherits from a shared hidden class that defines this property a. If two objects all share the same basic properties, then they will all reference the same hidden classes, and JSON.stringify will work exactly the same on both objects. That's a given (More details on V8's internals here, if you're interested).
However, in the example pointed out by a-j, both objects are stringified differently. How come? Well, put simply, these objects never exist at the same time:
JSON.stringify({a: 1, b: 2})
This is a function call, an expression that needs to be resolved to the resulting value before it can be compared to the right-hand operand. The second object literal isn't on the table yet.
The object is stringified, and the exoression is resolved to a string constant. The object literal isn't being referenced anywhere and is flagged for garbage collection.
After this, the right hand operand (the JSON.stringify({b: 2, a: 1}) expression) gets the same treatment.
All fine and dandy, but what also needs to be taken into consideration is that JS engines now are far more sophisticated than they used to be. Again, I'm no V8 expert, but I think its plausible that a-j's snippet is being heavily optimized, in that the code is optimized to:
"{"b":2,"a":1}" === "{"a":1,"b":2}"
Essentially omitting the JSON.stringify calls all together, and just adding quotes in the right places. That is, after all, a lot more efficient.
As an underscore mixin:
in coffee-script:
_.mixin deepEquals: (ar1, ar2) ->
# typeofs should match
return false unless (_.isArray(ar1) and _.isArray(ar2)) or (_.isObject(ar1) and _.isObject(ar2))
#lengths should match
return false if ar1.length != ar2.length
still_matches = true
_fail = -> still_matches = false
_.each ar1, (prop1, n) =>
prop2 = ar2[n]
return if prop1 == prop2
_fail() unless _.deepEquals prop1, prop2
return still_matches
And in javascript:
_.mixin({
deepEquals: function(ar1, ar2) {
var still_matches, _fail,
_this = this;
if (!((_.isArray(ar1) && _.isArray(ar2)) || (_.isObject(ar1) && _.isObject(ar2)))) {
return false;
}
if (ar1.length !== ar2.length) {
return false;
}
still_matches = true;
_fail = function() {
still_matches = false;
};
_.each(ar1, function(prop1, n) {
var prop2;
prop2 = ar2[n];
if (prop1 !== prop2 && !_.deepEquals(prop1, prop2)) {
_fail();
}
});
return still_matches;
}
});

Determining if a Javascript object is a "complex" object or just a string

I want to be able to pass either a string literal,
'this is a string'
or a javascript object,
{one: 'this', two: 'is', three: 'a', four: 'string' }
as argument to a function, and take different actions depending on whether it's a string or an object. How do I determine which is true?
To be specific, I want to iterate over the properties of an object, and do some parsing if a property is a string, but nest recursively if the property is an object. I've figured out how to use $.each() to iterate over the properties of the object, but if I just do this with the string, it treates the string as an array of letters rather than as a single thing. Can I get around this some other way?
var data = {
foo: "I'm a string literal",
bar: {
content: "I'm within an object"
}
};
jQuery
$.each(data, function(i, element){
if($.isPlainObject(element){
// we got an object here
}
});
There are similar methods like $.isArray() or $.isFunction() within the jQuery lib.
Native Javascript
for(var element in data){
if(toString.call(element) === '[object Object]'){
// we got an object here
}
}
To use the hack'ish way with toString has the advantage, that you can identify whether it is really an object and an array. Both, objects and arrays would return object by using typeof element.
Long story short, you cannot rely on the typeof operator to distinguish true objects and arrays. For that you need the toString.call(). If you just need to know whether it is any object or not, typeof is just fine.
var a = 'this is a string';
console.log(typeof a); // Displays: "string"
var b = {one: 'this', two: 'is', three: 'a', four: 'string' };
console.log(typeof b); // Displays: "object"
Therefore:
if (typeof yourArgument === 'string') {
// Do the string parsing
}
else if (typeof yourArgument === 'object') {
// Do the property enumeration
}
else {
// Throw exception
}
UPDATE:
Some further considerations:
See #Andy E's comment below.
typeof null returns "object" as well. The same applies to any other object, including arrays.
Try this:
function some_function(argument) {
if (typeof(argument) == "string" || argument.constructor == String) {
// it's a string literal
} else if (argument && typeof(argument) == "object" && argument.constructor != Array) {
// it's an object and not null
} else {
// error
}
}
Thanks to Andy E for the tipp with argument.constructor.
Try the typeof operator. It will return object for objects and string for strings.
you can do something like this
function something(variableX){
if (typeof(variableX) === 'object'){
// Do something
}else if (typeof(variableX) === 'string'){
// Do something
}
}
I was having a similar problem and I think I figured out a solution. Here is my sample code for anyone who is interested.
var propToDotSyntax = function (obj) {
var parse = function (o, n) {
var a = [], t;
for (var p in o) {
if (o.hasOwnProperty(p)) {
t = o[p];
if (n !== undefined) tmp = n + '.' + p;
else tmp = p;
if (t && typeof(t) === 'object') a.push(arguments.callee(t, tmp));
else a.push(tmp + '=' + t);
}
}
return a;
};
return parse(obj).toString();
}
var i = { prop: 'string', obj: { subprop: 'substring', subobj: { subsubprop: 'subsubstring' } } };
propToDotSyntax(i);
This will go through all the properties of an object — even if the properties are objects themselves — and return a string with the following values in dot syntax.
"prop=string,obj.subprop=substring,obj.subobj.subsubprop=subsubstring"
I got the inspiration from DavidPirek.com — Thanks Mr. Pirek!

Categories

Resources