a pretty simple question, is there ever a case where using a primitive data-type is preferable in javascript, i am specifically bothered by primitive booleans, consider the following code
var bool = new Boolean(false);
if (bool){
alert(bool);
}
it will alert but you will get false, which is kinda confusing (false != falsy).
so is there ever a point in using primitive data-types and especially primitive booleans?
These are not primitives. Primitives are like 100, "foobar", false:
> typeof false
"boolean"
> typeof new Boolean(false)
"object"
new Boolean (or Number or String) is an object and follows objects', not primitives' rules for comparison, boolean conversion etc. These objects are indeed hardly useful for a JS programmer (as opposed to a JS engine which uses them internally).
Note that while it's rarely needed to use Boolean and friends to construct objects (as in x = new Boolean(...)), these functions are sometimes useful per se. For example, the following nice idiom removes all falsy values from an array:
ary = ary.filter(Boolean)
The primitive values are very useful (ex of primitive values: true, false, null, 1, 2, etc). What you are talking about in the question are the Object wrappers around them.
Object wrappers are useful because it allows you to add functions to be called on them. One more important thing is that when you call methods on the primitive values, Object wrappers are created over them and the methods are called on the Object wrappers*.
Example 1: String
String.prototype.sayHello = function() {
return this + ' says hello';
};
// calling a method on a string literal temporarily converts it to a String
console.log('John'.sayHello()); // 'John says hello'
Example 2: Boolean
var bool = new Boolean(false);
console.log(bool); // Boolean
console.log(bool.toString()); // 'false'
console.log(bool.valueOf()); // false
// How you can use it:
Boolean.prototype.toCaps = function() {
return this.valueOf().toString().toUpperCase();
};
console.log(bool.toCaps()); // 'FALSE'
// calling a method on a boolean literal temporarily converts it to a Boolean
console.log(true.toCaps()); // 'TRUE'
console.log((1 === 1).toCaps()); // 'TRUE'
DEMO: http://jsbin.com/apeGOve/1/edit
*) Different Object wrappers are created each time a method is called on a primitive value:
String.prototype.getWrapper = function() { return this; };
String.prototype.setTest = function() { this.test = 'test' };
String.prototype.getTest = function() { return this.test; };
var str = '123';
console.log('Different wrappers each time',str.getWrapper() === str.getWrapper());
var wrapper = str.getWrapper();
wrapper.setTest();
console.log(wrapper.getTest());
console.log(str.getTest());
Your example:
var bool = new Boolean(false);
if (bool){
alert(bool);
}
and you're wanting to know why it alerts false.
bool is the variable, you assigned it a value when you created it. So, when you say if(bool) JavaScript does some coercion and tests whether bool is falsy, it isn't, so the conditional block executes. Now you're at alert(bool) which will try to call the toString method of your object and display the result. The toString method of the boolean object returns the value of the boolean object as a string so, you get the word "false" alerted.
Go ahead, try
var bool = new Boolean(false);
bool.toString = function () {
return 'I need a banana';
}
if (bool){
alert(bool);
}
and you'll get completely different results.
This brings us to your other question of "why" you'd even use the boolean constructor: you can assign properties to the boolean object, you can not assign properties to true and false. You may want to inherit from the boolean object when building some logic handling library with chainable methods, for instance.
Related
In JavaScript is there any difference between using String() and new String()?
console.log(String('word')); // word
console.log(new String('word')); // word
Using the String() constructor without new gives you the string (primitive) value of the passed parameter. It's like boxing the parameter in a native object if necessary (like a Number or Boolean), and then calling .toString() on it. (Of course if you pass a plain object reference it just calls .toString() on that.)
Calling new String(something) makes a String instance object.
The results look the same via console.log() because it'll just extract the primitive string from the String instance you pass to it.
So: just plain String() returns a string primitive. new String(xyz) returns an object constructed by the String constructor.
It's rarely necessary to explicitly construct a String instance.
String() returns a string primitive and new String() returns a Object String. This has some real consequences for your code.
Using String() returns 'true' with other primitives both with == and === operator.
Using String() gives you a primitive so it cannot use the "instanceOf" method to check its type. You can check only value type with "typeof" operator
Using new String() with "instanceOf" method with String or Object prototypes - both assert to true.
Using new String() will return 'true' with string primitives only by calling valueOf() method. String() has also this method and returns true when compared to string of the same value.
Using new String() allows you to add some other properties and methods to the Object to allow more complex behaviour.
From my coding experience you should avoid using new String() if you have no need for adding special methods to your String Object.
var x = String('word');
console.log(typeof x); // "string"
var y = new String('word');
console.log(typeof y); // "object"
// compare two objects !!!
console.log(new String('') === new String('')) // false!!!
// compare with string primitive
console.log('' == String('')) // true
console.log('' === String('')) // true
//compare with string Object
console.log('' == new String('')) // true
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
console.log('' === new String('')) // false !!!!
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// instance of behavior
console.log(x instanceof String); // false
console.log(x instanceof Object); // false
// please note that only new String() is a instanceOf Object and String
console.log(y instanceof String); // true
console.log(y instanceof Object); // true
//valueOf behavior
console.log('word' == x.valueOf()); // true
console.log('word' === x.valueOf()); // true
console.log('word' == y.valueOf()); // true
console.log('word' === y.valueOf()); // true
//create smart string
var superString = new String('Voice')
superString.powerful = 'POWERFUL'
String.prototype.shout = function () {
return `${this.powerful} ${this.toUpperCase()}`
};
console.log(superString.shout()) //"POWERFUL VOICE"
Strings returned from String calls in a non-constructor context (i.e., without using the new keyword) are primitive strings.
Strings created with new String() (constructor mode) is an object and can store property in them.
Demonstrating the difference:
var strPrimitive = String('word');
strPrimitive.prop = "bar";
console.log(strPrimitive.prop); // undefined
var strObject = new String('word');
strObject.prop = "bar";
console.log(strObject.prop); // bar
Here is an example in addition to the good answers already provided:
var x = String('word');
console.log(typeof x); // "string"
var y = new String('word');
console.log(typeof y); // "object"
The exact answer to your question is here in the documentation.
String literals (denoted by double or single quotes) and strings
returned from String calls in a non-constructor context (i.e., without
using the new keyword) are primitive strings.
Generally it's not recommended to use constructor functions (i.e. using new keyword) because it can lead to unpredictable results.
For example:
if (new Number(0)) { //
console.log('It will be executed because object always treated as TRUE in logical contexts. If you want to treat 0 as falsy value then use Number(0)')
}
Also, as mentioned above, there is another potential problem:
typeof 0; // number
typeof Number(0) // number
typeof new Number(0) // object
I've recently stumbled on this function which determines if something is a plain object is JavaScript:
function isPlainObject (value){
if (typeof value !== 'object' || value === null) return false;
let proto = value;
while (Object.getPrototypeOf(proto) !== null) {
proto = Object.getPrototypeOf(proto);
}
return Object.getPrototypeOf(value) === proto;
};
Source: https://github.com/redux-utilities/redux-actions/blob/master/src/utils/isPlainObject.js
I would like to know:
If the following approach will do exactly the same stuff?
If so, can it be considered more effective?
function isPlainObj(value){
if (typeof value !== 'object' || value === null) return false;
let obj = {};
return Object.getPrototypeOf(value) === Object.getPrototypeOf(obj)
}
Checking if a value is a plain object:
/*
isPlainObject({}) // true
isPlainObject() // false
isPlainObject(null) // false
isPlainObject(true) // false
isPlainObject('1') // false
isPlainObject([]) // false
isPlainObject(new Function()) // false
isPlainObject(new Date()) // false
*/
const isPlainObject = value => value?.constructor === Object;
Excludes nulls, scalars, arrays, functions and any extended type other than Object.
No. The former walks through the whole prototype chain but returns true only if such chain is composed by 1 prototype (so, your first example is kinda pointless)
Yes and No. Yes, it's more effective, no need to loop everything just to check the prototype is the Object.prototype one. No, it performs a needless operation.
This is how I'd do it:
const isPlainObj = value => !!value &&
Object.getPrototypeOf(value) === Object.prototype;
No need to go too fancy, if all you want to know is that value prototype is Object.prototype 👋
P.S. There is one thing your initial example does that other examples, including mine, don't: it works with foreign objects, which are objects coming from different realms (i.e. iframes). I don't think this use case exists in 2021, but if your app/site passes objects between different windows/frames then the first function would return true for those objects too, while my suggestion, or yours, won't. Yet, there's no need to loop through the whole chain, you can simply do this instead:
function isPlainObj(value) {
// it's truthy
return !!value &&
// it has a prototype that's also truthy
!!(value = Object.getPrototypeOf(value)) &&
// which has `null` as parent prototype
!Object.getPrototypeOf(value);
}
This grabs the proto once or maximum twice ensuring its chain ends up with null, which is usually the common literal case.
Yet, I think foreign objects are non existent these days, so I'd stick with my suggested version.
ToolJS has a method under it's "Obj" module that checks if an object is infact a plain object literal.
Ref: ToolJS Object Module
Get the code on NPM or through its CDN and use as shown below
// export the methods in the "Obj" module
var $ = ToolJS.export("Obj");
var myObj = {name: "John Doe"};
var myArr = [1,2,3]; // note that arrays are of type object but are obviously not plain objects
var myEl = document.getElementById("elem"); // elements are also objects
$.isObj(myObj); // => true
$.isObj(myArr); // => false
$.isObj(myEl); // => false
You can check out it's full documentation here
Under the hood, the method checks the item type is not null or undefined but an object, then checks its constructor to see if its even an object, after which it makes sure that its not an array and finally converts it to string to see if its a plain object.
I am looking for a quick check to determine if a value is an object {} but not an array []. I have written this:
function isPlainObject(input) {
return !Array.isArray(input) && typeof input === 'object';
}
Is there a shorter check I can use to determine this?
Or are there other possible data structures that still checkout as typeof 'object'?
It is not quicker, but more precise, with a check for falsy values, like null, which is an object.
function isPlainObject(input) {
return input && !Array.isArray(input) && typeof input === 'object';
}
If you want to check if an object is a "plain" object, i.e. inherits directly from Object.prototype, then you should check for that.
E.g. the following first tests if value has Object anywhere on it's prototype chain (and hence will not throw an error for getPrototypeOf), then checks if its immediate [[prototype]] is Object.prototype:
function isPlainObject(value) {
return value instanceof Object &&
Object.getPrototypeOf(value) == Object.prototype;
}
// Some tests
[[1,2], // Array
{}, // Plain object
null, // null
document.createElement('div'), // host object
function(){}, // function object
console // host objet
].forEach(function(value) {
console.log(value + ': ' + isPlainObject(value));
});
Edit
If you want to test that the input is some extended object but not a Function, etc. that is much less efficient, e.g. test against some list of objects that you want to avoid:
function isJustObj(obj) {
var notThese = [Function, Array, Date];
if (obj instanceof Object) {
return !notThese.some(function(o) {
return obj instanceof o;
});
}
return false;
}
function Foo(){}
var tests = {'Array: ':[],
'Object: ' : {},
'Foo instance:' : new Foo(),
'Function: ' : function(){},
'Date: ' : new Date(),
'Host obj: ' : document.createElement('div')
};
Object.keys(tests).forEach(function(test) {
console.log(test + isJustObj(tests[test]));
})
Note that this strategy sees if the value is some kind of Object, then tests whether it's an instance of a particular set of constructors. This list of things to exclude can become very large since it's not possible in any reasonable way to rule out host objects which, by their very nature, can be indistinguishable from built-in objects based on some general test (see Is there an environment-agnostic way to detect Javascript Host Objects?).
E.g.
console.log instanceof Function // true
console instanceof Object // true
isPlainObject(console) // false
So you either check if Object.prototype is the immediate [[Prototype]] or create a long list of constructors to test against. That list will go out of date very quickly given the variety of host environments available and the freedom for implementors to extend it. Also, you need to test every member of the host object set before trying to use it as it may not exist for the particular host on which the code is running.
Javascript arrays are considered objects so typeof will always be object in case of array.
I have an object with some properties which are String objects:
var obj = {
foo: new String("bar")
};
I am using String objects because I am needing to store additional sub-properties on the object while still being able to get the string value:
obj.foo.baz = "baz";
"" + obj.foo; //-> "bar";
I feel dumb for asking, but how can I update the value of a String object? Seems like some Array splice magic might need to be applied.
EDIT: Just to be clear, I understand string primitives in JS and immutability therein. This is an object I'm talking about. Here is the test that needs to pass:
assert.equal("" + obj.foo, "foo"); //-> true
assert.equal(obj.foo.baz, "baz"); //-> true
extend(obj, { foo: "foooooo" });
assert.equal("" + obj.foo, "foooooo"); //-> true
assert.equal(obj.foo.baz, "baz"); //-> true
You can't. Strings are immutable, regardless of how you "construct" them (literal or object).
What you should be doing is simply use an actual object to hold your values and your string.
At the most basic level this would be:
var obj = {
foo: "bar"
};
// later...
obj.baz = "baz";
"" + obj.foo; //-> "bar";
You can also consider using a monadic type as an "amplifier" / decorator, but that seems way overkill for this use case.
As a side note, adding properties and "random" functions to a string object is not a good OOP choice. These are strictly not relevant to the value that is the string, and only make sense to a higher level object, which is where they should reside.
You'd need to create a new String object and extend any new properties and values to that String object. I've provided a simple example below. That said, this example can be modified to suit your purposes (you'd create a custom extend or setter function).
Example of a property setter function
var createNewString = function (oldStringObj, string) {
var _new = new String(string);
var keys = Object.keys(oldStringObj); // returns only custom properties (not part of prototype)
for (var i=0,n=keys.length; i<n; i++){
var key = keys[i];
if (Number.isInteger(+key)) {
continue; // skip property if it's a numbered key
}
_new[key] = oldStringObj[key]; // simple assignment (not a deep copy) -- room for improvement
}
return _new;
};
Original object
var obj = {
foo: new String("bar")
};
obj.foo.baz = "baz"; // new property
Update the object
obj.foo = createNewString( obj.foo, 'foot' );
//obj.foo=='foot' and obj.foo.baz=='baz'
I suggest that you use a custom type for this, instead of the default String type. The ES6 spec defines that the underlying value for a String object is stored in its "[[StringData]] internal slot". The only place this slot is assigned is via the new String constructor, so it is implicitly immutable. You can create a new type which has the same string-like behaviours that you require, while being mutable.
class MutableString {
constructor(value) {
this.value = value;
}
toString() {
return this.value;
}
}
var obj = {
foo: new MutableString('bar')
};
obj.foo.baz = "baz";
console.assert("" + obj.foo == "bar");
console.assert(obj.foo + "" == "bar");
console.assert(obj.foo.baz == "baz");
console.assert(Object.keys({[obj.foo]: 1})[0] == "bar");
obj.foo.value = "foooooo";
console.assert("" + obj.foo == "foooooo");
console.assert(obj.foo + "" == "foooooo");
console.assert(obj.foo.baz == "baz");
console.assert(Object.keys({[obj.foo]: 1})[0] == "foooooo");
Because this isn't really a string it won't support any string methods, so it may not be suitable for your use. But it's more flexible and a little clearer, so I suggest considering it if possible.
It may be necessary to define a valueOf() method like toString() to handle some other cases, but I haven't verified.
Recently I've learned that you can use the Boolean keyword to check whether a boolean value is false, e.g. this, where the arrayOfSheeps is simply an array of boolean values.
function countSheeps(arrayOfSheeps) {
return arrayOfSheeps.filter(Boolean).length;
}
As I've been unable to find anything about using 'Boolean' as a keyword, I was wondering if there are any other uses for the word, or even just any resources I can use to learn about it.
Boolean is not a keyword, it is a function, and functions are just objects, that you can pass around. It is the same as:
return arrayOfSheeps.filter(function(x){return Boolean(x)}).length;
Since function(x){return f(x)} === f then you can simplify:
return arrayOfSheeps.filter(Boolean).length;
Based on MDN Boolean,
Do not use a Boolean object to convert a non-boolean value to a
boolean value. To perform this task, instead, use Boolean as a
function
var x = Boolean(expression); // use this...
var x = !!(expression); // ...or this
var x = new Boolean(expression); // don't use this!
So the code is same as:
const b = v => !!v;
arrayOfSheeps.filter(b).length;
arrayOfSheeps.filter(v => !!v).length; // or inline