How to get rid of instanseof in javascript - javascript

I have a class, it has two methods: get(), set().
function A() {
var value = '';
this.get = function () {
return value;
};
this.set = function (v) {
value = v;
};
}
And I have a function f():
/**
*
* #param { String | Number } b
*/
function f(b){
var value;
if(b instanceof A){
value = b.get();
}else{
value = b;
}
}
I could create an object:
var test = new A();
test.set('Hello');
f(test); //Hello
f(10); //10
The instanceof operator tests whether an object has in its prototype chain the prototype property of a constructor.
I heard it is a bad practice use this operator.
The question is: Is it imposible to get rid of instanceof operator from my code?
Maybe I should use force type conversion or use another getter, setter?
<--UPDATE-->>
I found simple solution, I could coerce b.get to boolean type and check it. It works, but maybe it has incidental effect.
value = (!!b.get) ? b.get(): b;
<--UPDATE 2-->>
Another way: value = (b.constructor = A) ? b.get(): b;

It's not the instanceof operator itself which is the problem, it's what you're using it for. Your function is expecting values of two different types: either an instance of A which needs to be handled a certain way or anything else which can be used as is.
The problem with this is a) why is your function allowing two different types to begin with and couldn't you harmonise that into just one type, and b) if it's accepting "anything" or "A", why A specifically and not something more general?
Assuming that you cannot reasonably change point a), you can at least make b) better:
if (typeof b.get == 'function') {
value = b.get();
}
You've just made your function a little more flexible and adaptable to future change by testing for the actual thing you're interested in: a get method. That b is an instanceof A is sort of irrelevant for the task at hand and may limit you in the future.

Related

Comparable custom types which can be sorted as array items without defining an additional compare function inside sort()

Languages such as Python and Java have special methods for sorting custom classes. In JavaScript, toString() can be overridden, but this does not work easily for numeric values.
As a workaround, I added a method called compareTo() to the class, although this still requires a function to call it.
class NumericSortable {
constructor(newVal) {
this.val = newVal
}
compareTo(other) {
return this.val - other.val
}
}
const objectList = [
new NumericSortable(3),
new NumericSortable(1),
new NumericSortable(20),
]
objectList.sort(
function(a, b) { return a.compareTo(b) })
console.log(objectList)
Is there a way to modify the class so it can be sorted without requiring a function to be defined inside sort()?
Perhaps there is a good way to override toString() that will work for numeric values. However, solutions such as localeCompare() or a collator require two arguments, and they would not be passed to the overridden toString() method at the same time.
You can add a static method to your NumericSortable class, and pass that into the sort call. This idea can be extended to any custom class that need to define how two instances are to be compared for sorting.
class NumericSortable {
constructor(value) {
this.value = value;
}
static compare(a,b) {
return a.value - b.value;
}
}
const arr = [
new NumericSortable(3),
new NumericSortable(1),
new NumericSortable(20),
];
arr.sort(NumericSortable.compare);
console.log(arr);
This makes things more explicit, and easier for anyone else reading the code to reason about how the array is being sorted.
I like to make a function that returns a sort function for these cases.
function by(prop){
return function(a,b){return a[prop]-b[prop];};
}
this let's you specify the object's to-be-sorted property at call-time, letting one generic function do a lot of heavy lifting.
objectList.sort(by("val"))
This avoids the need for a custom callback each sort, though with fat arrows that's not the burden it used to be anyway...
If no comparator is provided, each time two items in the array are compared, they'll be coerced to strings, and then those strings will be compared lexiographically to determine which object will come before the other in the sorted array. So, if you don't want to pass a comparator, adding a toString method to implement the desired sorting logic is the only other approach.
Unfortunately, for your situation, lexiographic comparison alone based on the .vals won't cut it; 1 will come before 20, and 20 will come before 3. If the numbers involved won't get so high as to have es in their string version, you could .padStart the returned string so that each compared numeric string will have the same number of characters (thereby allowing lexiographic comparison to work).
class NumericSortable {
constructor(newVal) {
this.val = newVal
}
// Unused now
compareTo(other) {
return this.val - other.val
}
toString() {
return String(this.val).padStart(15, '0');
}
}
const objectList = [
new NumericSortable(3),
new NumericSortable(1),
new NumericSortable(20),
]
objectList.sort()
console.log(objectList)
You may wish to account for negative numbers too.
Still, this whole approach is a bit smelly. When possible, I'd prefer a comparator instead of having to fiddle with the strings to get them to compare properly.
From my above comment ...
"The OP needs to wrap the build-in sort method into an own/custom implementation of Array.prototype.sort. But why should one do it? Just for the sake of not writing a comparing sort-callback?"
Having said the above, I herby nevertheless provide an implementation of the above mentioned approach just in order to prove to the OP that it's manageable (after all it is exactly what the OP did ask for), but also to show to the audience that the effort (even though it's a one time effort) of doing so is much greater than other already provided suggestions / solutions.
class NumericSortable {
constructor(newVal) {
this.val = newVal;
}
compareTo(other) {
return this.val - other.val;
}
}
const objectList = [
new NumericSortable(3),
new NumericSortable(1),
new NumericSortable(20),
];
objectList
// - sorting by overwritten custom `sort` function with
// an already build-in `compareTo` based custom compare
// function and no additionally passed compare function.
.sort();
console.log({ objectList });
objectList
// - reverse sorting by overwritten custom `sort` function
// with an additionally passed compare function.
.sort((a, b) => (-1 * a.compareTo(b)));
console.log({ objectList });
console.log(
'... simple sort-implementation defaul-test ...\n[1,4,9,0,6,3].sort() ...',
[1,4,9,0,6,3].sort()
);
console.log(
'... simple sort-implementation defaul-test ...\n["foo", "biz", "baz", "bar"].sort() ...',
["foo", "biz", "baz", "bar"].sort()
);
.as-console-wrapper { min-height: 100%!important; top: 0; }
<script>
(function (arrProto) {
// save the native `sort` reference.
const coreApiSort = arrProto.sort;
// type detection helper.
function isFunction(value) {
return (
'function' === typeof value &&
'function' === typeof value.call &&
'function' === typeof value.apply
);
}
// different comparison helper functionality.
function defaultCompare(a, b) {
return (a < b && -1) || (a > b && 1) || 0;
}
function localeCompare(a, b) {
return a?.localeCompare?.(b) ?? defaultCompare(a, b);
}
function customDefaultCompare(a, b) {
const isCustomComparableA = isFunction(a.compareTo);
const isCustomComparableB = isFunction(b.compareTo);
return (isCustomComparableA && isCustomComparableB)
? a.compareTo(b)
: localeCompare(a, b);
}
// the new `sort` functionality.
function customSort(customCompare) {
return coreApiSort
// - (kind of "super") delegation to the
// before saved native `sort` reference ...
.call(this, (
// ... by using a cascade of different
// comparison functionality.
isFunction(customCompare)
&& customCompare
|| customDefaultCompare
));
}
Object
// - overwrite the Array prototype's native `sort`
// method with the newly implemented custom `sort`.
.defineProperty(arrProto, 'sort', {
value: customSort,
});
}(Array.prototype));
</script>

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...
}

Performing assignment operations on an object

Example JSFiddle so you can get a better idea of what is going on http://jsfiddle.net/brsXL/3/ (open your console and view the logged vars object).
I am building a parser and computer for a specific subset of maths in JavaScript, it takes an expression as a string from the user and allows them to use variables. To keep my computational logic simple but allow for the use of variables I have created an object that acts like a number but has the bonus of being passed by reference.
var Variable = function(value) {
this.value = value || null;
}
Variable.prototype.valueOf = function() {
return this.value;
}
This works so that:
var a = new Variable(10);
console.log(a + 2); // = 12
console.log(a / 2); // = 5
However as soon as I wish to perform any form of assignment operation such as += the object is lost and gets replaced by the result of the operation against the object's value property. e.g.
var a = new Variable(10);
console.log(a += 2); // = 12
console.log(a); // = 12
The reason I need it to work like this is because I want to use the same function to handle both numbers and variables. I could add code to each assignment operation but this feels sub-optimal to me, e.g.
var ops = {
"+=" : function(a, b) {
if (a instanceof Variable) {
a.value += b;
} else {
a += b;
}
return a;
},
...
}
But I'd much rather write:
var ops = {
"+=" : function(a, b) {
return a += b;
},
...
}
Can this be done?
I'd much rather write:
function(a, b) {
return a += b;
}
Can this be done?
No. It's impossible to pass a Reference value as a single variable. You always will need to use object properties. a is always local-scoped in your function, so changing it won't affect the outer world. And I'd discourage you from trying to make your operators functions that operate on higher-scope variables…
I think in your case it's quite fine to use an explicit test for variables, because the assignment operator has to do that actually. You cannot assign to literals or other values, only to variables. It might even be
var ops = {
"=" : function(a, b) {
if (a instanceof Variable) {
a.value = +b; // cast b to a number (from whatever it is)
return a;
} else {
throw new Error("Invalid assignment to non-variable "+a);
}
},
...
}
Also, to avoid code duplication you might not write out all the compound assignment operators. Define them in a generic way:
["+", "-", "*", "/"].forEach(function(op) {
ops[op+"="] = function(a, b) {
return ops["="].call(this, a, ops[op].call(this, a, b));
};
});
(Updated jsfiddle demo)

How best to inherit from native JavaScript object? (Especially String)

I'm a long-time browser but a first time participator. If I'm missing any etiquette details, please just let me know!
Also, I've searched high and low, including this site, but I haven't found a clear and succinct explanation of exactly what I'm looking to do. If I just missed it, please point me in the right direction!
Alright, I want to extend some native JavaScript objects, such as Array and String. However, I do not want to actually extend them, but create new objects that inherit from them, then modify those.
For Array, this works:
var myArray = function (n){
this.push(n);
this.a = function (){
alert(this[0]);
};
}
myArray.prototype = Array.prototype;
var x = new myArray("foo");
x.a();
However, for String, the same doesn't work:
var myString = function (n){
this = n;
this.a = function (){
alert(this);
};
}
myString.prototype = String.prototype;
var x = new myString("foo");
x.a();
I've also tried:
myString.prototype = new String();
Now, in trying to research this, I've found that this does work:
var myString = function (n){
var s = new String(n);
s.a = function (){
alert(this);
};
return s;
}
var x = myString("foo");
x.a();
However, this almost feels like 'cheating' to me. Like, I should be using the "real" inheritance model, and not this shortcut.
So, my questions:
1) Can you tell me what I'm doing wrong as regards inheriting from String? (Preferably with a working example...)
2) Between the "real" inheritance example and the "shortcut" example, can you name any clear benefits or detriments to one way over the other? Or perhaps just some differences in how one would operate over the other functionally? (Because they look ultimately the same to me...)
Thanks All!
EDIT:
Thank you to everyone who commented/answered. I think #CMS's information is the best because:
1) He answered my String inheritance issue by pointing out that by partially redefining a String in my own string object I could make it work. (e.g. overriding toString and toValue)
2) That creating a new object that inherits from Array has limitations of its own that weren't immediately visible and can't be worked around, even by partially redefining Array.
From the above 2 things, I conclude that JavaScript's claim of inheritablity extends only to objects you create yourself, and that when it comes to native objects the whole model breaks down. (Which is probably why 90% of the examples you find are Pet->Dog or Human->Student, and not String->SuperString). Which could be explained by #chjj's answer that these objects are really meant to be primitive values, even though everything in JS seems to be an object, and should therefore be 100% inheritable.
If that conclusion is totally off, please correct me. And if it's accurate, then I'm sure this isn't news to anyone but myself - but thank you all again for commenting. I suppose I now have a choice to make:
Either go forward with parasitic inheritance (my second example that I now know the name for) and try to reduce its memory-usage impact if possible, or do something like #davin, #Jeff or #chjj suggested and either psudo-redefine or totally redefine these objects for myself (which seems a waste).
#CMS - compile your information into an answer and I'll choose it.
The painfully simple but flawed way of doing this would be:
var MyString = function() {};
MyString.prototype = new String();
What you're asking for is strange though because normally in JS, you aren't treating them as string objects, you're treating them as "string" types, as primitive values. Also, strings are not mutable at all. You can have any object act as though it were a string by specifying a .toString method:
var obj = {};
obj.toString = function() {
return this.value;
};
obj.value = 'hello';
console.log(obj + ' world!');
But obviously it wouldn't have any string methods. You can do inheritence a few ways. One of them is the "original" method javascript was supposed to use, and which you and I posted above, or:
var MyString = function() {};
var fn = function() {};
fn.prototype = String.prototype;
MyString.prototype = new fn();
This allows adding to a prototype chain without invoking a constructor.
The ES5 way would be:
MyString.prototype = Object.create(String.prototype, {
constructor: { value: MyString }
});
The non-standard, but most convenient way is:
MyString.prototype.__proto__ = String.prototype;
So, finally, what you could do is this:
var MyString = function(str) {
this._value = str;
};
// non-standard, this is just an example
MyString.prototype.__proto__ = String.prototype;
MyString.prototype.toString = function() {
return this._value;
};
The inherited string methods might work using that method, I'm not sure. I think they might because there's a toString method. It depends on how they're implemented internally by whatever particular JS engine. But they might not. You would have to simply define your own. Once again, what you're asking for is very strange.
You could also try invoking the parent constructor directly:
var MyString = function(str) {
String.call(this, str);
};
MyString.prototype.__proto__ = String.prototype;
But this is also slightly sketchy.
Whatever you're trying to do with this probably isn't worth it. I'm betting there's a better way of going about whatever you're trying to use this for.
If you want an absolutely reliable way of doing it:
// warning, not backwardly compatible with non-ES5 engines
var MyString = function(str) {
this._value = str;
};
Object.getOwnPropertyNames(String.prototype).forEach(function(key) {
var func = String.prototype[key];
MyString.prototype[key] = function() {
return func.apply(this._value, arguments);
};
});
That will curry on this._value to every String method. It will be interesting because your string will be mutable, unlike real javascript strings.
You could do this:
return this._value = func.apply(this._value, arguments);
Which would add an interesting dynamic. If you want it to return one of your strings instead of a native string:
return new MyString(func.apply(this._value, arguments));
Or simply:
this._value = func.apply(this._value, arguments);
return this;
There's a few ways to tackle it depending on the behavior you want.
Also, your string wont have length or indexes like javascript strings do, a way do solve this would be to put in the constructor:
var MyString = function(str) {
this._value = str;
this.length = str.length;
// very rough to instantiate
for (var i = 0, l = str.length; i < l; i++) {
this[i] = str[i];
}
};
Very hacky. Depending on implementation, you might just be able to invoke the constructor there to add indexes and length. You could also use a getter for the length if you want to use ES5.
Once again though, what you want to do here is not ideal by any means. It will be slow and unnecessary.
This line is not valid:
this = n;
this is not a valid lvalue. Meaning, you cannot assign to the value referenced by this. Ever. It's just not valid javascript. Your example will work if you do:
var myString = function (n){
this.prop = n;
this.a = function (){
alert(this.prop);
};
}
myString.prototype = new String; // or String.prototype;
var x = new myString("foo");
x.a();
Regarding your workaround, you should realise that all you're doing is making a String object, augmenting a function property, and then calling it. There is no inheritance taking place.
For example, if you execute x instanceof myString in my example above it evaluates to true, but in your example it isn't, because the function myString isn't a type, it's just a regular function.
You can't assign the this in a constructor
this=n is an error
Your myarray is just an alias for the native Array- any changes you make to myarray.prototype are changes to Array.prototype.
I would look into creating a new object, using the native object as a backing field and manually recreating the functions for the native objects. For some very rough, untested sample code...
var myString = {
_value = ''
,substring:_value.substring
,indexOf:_value.indexOf
}
Now, I'm sure this wont work as intended. But I think with some tweaking, it could resemble on object inherited from String.
The ECMAScript6 standard allows to inherit directly from the constructor functions of a native object.
class ExtendedNumber extends Number
{
constructor(value)
{
super(value);
}
add(argument)
{
return this + argument;
}
}
var number = new ExtendedNumber(2);
console.log(number instanceof Number); // true
console.log(number + 1); // 4
console.log(number.add(3)); // 5
console.log(Number(1)); // 1
In ECMAScript5 it is possible to inherit like this:
function ExtendedNumber(value)
{
if(!(this instanceof arguments.callee)) { return Number(value); }
var self = new Number(value);
self.add = function(argument)
{
return self + argument;
};
return self;
}
However, the generated objects are not primitive:
console.log(number); // ExtendedNumber {[[PrimitiveValue]]: 2}
But you can extend a primitiv type by extending his actual prototype that is used:
var str = "some text";
var proto = Object.getPrototypeOf(str);
proto.replaceAll = function(substring, newstring)
{
return this.replace(new RegExp(substring, 'g'), newstring);
}
console.log(str.replaceAll('e', 'E')); // somE tExt
A cast to a class-oriented notation is a bit tricky:
function ExtendedString(value)
{
if(this instanceof arguments.callee) { throw new Error("Calling " + arguments.callee.name + " as a constructor function is not allowed."); }
if(this.constructor != String) { value = value == undefined || value == null || value.constructor != String ? "" : value; arguments.callee.bind(Object.getPrototypeOf(value))(); return value; }
this.replaceAll = function(substring, newstring)
{
return this.replace(new RegExp(substring, 'g'), newstring);
}
}
console.log(!!ExtendedString("str").replaceAll); // true

Hidden Features of JavaScript? [closed]

As it currently stands, this question is not a good fit for our Q&A format. We expect answers to be supported by facts, references, or expertise, but this question will likely solicit debate, arguments, polling, or extended discussion. If you feel that this question can be improved and possibly reopened, visit the help center for guidance.
Closed 11 years ago.
Locked. This question and its answers are locked because the question is off-topic but has historical significance. It is not currently accepting new answers or interactions.
What "Hidden Features" of JavaScript do you think every programmer should know?
After having seen the excellent quality of the answers to the following questions I thought it was time to ask it for JavaScript.
Hidden Features of HTML
Hidden Features of CSS
Hidden Features of PHP
Hidden Features of ASP.NET
Hidden Features of C#
Hidden Features of Java
Hidden Features of Python
Even though JavaScript is arguably the most important Client Side language right now (just ask Google) it's surprising how little most web developers appreciate how powerful it really is.
You don't need to define any parameters for a function. You can just use the function's arguments array-like object.
function sum() {
var retval = 0;
for (var i = 0, len = arguments.length; i < len; ++i) {
retval += arguments[i];
}
return retval;
}
sum(1, 2, 3) // returns 6
I could quote most of Douglas Crockford's excellent book
JavaScript: The Good Parts.
But I'll take just one for you, always use === and !== instead of == and !=
alert('' == '0'); //false
alert(0 == ''); // true
alert(0 =='0'); // true
== is not transitive. If you use === it would give false for
all of these statements as expected.
Functions are first class citizens in JavaScript:
var passFunAndApply = function (fn,x,y,z) { return fn(x,y,z); };
var sum = function(x,y,z) {
return x+y+z;
};
alert( passFunAndApply(sum,3,4,5) ); // 12
Functional programming techniques can be used to write elegant javascript.
Particularly, functions can be passed as parameters, e.g. Array.filter() accepts a callback:
[1, 2, -1].filter(function(element, index, array) { return element > 0 });
// -> [1,2]
You can also declare a "private" function that only exists within the scope of a specific function:
function PrintName() {
var privateFunction = function() { return "Steve"; };
return privateFunction();
}
You can use the in operator to check if a key exists in an object:
var x = 1;
var y = 3;
var list = {0:0, 1:0, 2:0};
x in list; //true
y in list; //false
1 in list; //true
y in {3:0, 4:0, 5:0}; //true
If you find the object literals too ugly you can combine it with the parameterless function tip:
function list()
{ var x = {};
for(var i=0; i < arguments.length; ++i) x[arguments[i]] = 0;
return x
}
5 in list(1,2,3,4,5) //true
Assigning default values to variables
You can use the logical or operator || in an assignment expression to provide a default value:
var a = b || c;
The a variable will get the value of c only if b is falsy (if is null, false, undefined, 0, empty string, or NaN), otherwise a will get the value of b.
This is often useful in functions, when you want to give a default value to an argument in case isn't supplied:
function example(arg1) {
arg1 || (arg1 = 'default value');
}
Example IE fallback in event handlers:
function onClick(e) {
e || (e = window.event);
}
The following language features have been with us for a long time, all JavaScript implementations support them, but they weren't part of the specification until ECMAScript 5th Edition:
The debugger statement
Described in: § 12.15 The debugger statement
This statement allows you to put breakpoints programmatically in your code just by:
// ...
debugger;
// ...
If a debugger is present or active, it will cause it to break immediately, right on that line.
Otherwise, if the debugger is not present or active this statement has no observable effect.
Multiline String literals
Described in: § 7.8.4 String Literals
var str = "This is a \
really, really \
long line!";
You have to be careful because the character next to the \ must be a line terminator, if you have a space after the \ for example, the code will look exactly the same, but it will raise a SyntaxError.
JavaScript does not have block scope (but it has closure so let's call it even?).
var x = 1;
{
var x = 2;
}
alert(x); // outputs 2
You can access object properties with [] instead of .
This allows you look up a property matching a variable.
obj = {a:"test"};
var propname = "a";
var b = obj[propname]; // "test"
You can also use this to get/set object properties whose name is not a legal identifier.
obj["class"] = "test"; // class is a reserved word; obj.class would be illegal.
obj["two words"] = "test2"; // using dot operator not possible with the space.
Some people don't know this and end up using eval() like this, which is a really bad idea:
var propname = "a";
var a = eval("obj." + propname);
This is harder to read, harder to find errors in (can't use jslint), slower to execute, and can lead to XSS exploits.
If you're Googling for a decent JavaScript reference on a given topic, include the "mdc" keyword in your query and your first results will be from the Mozilla Developer Center. I don't carry any offline references or books with me. I always use the "mdc" keyword trick to directly get to what I'm looking for. For example:
Google: javascript array sort mdc
(in most cases you may omit "javascript")
Update: Mozilla Developer Center has been renamed to Mozilla Developer Network. The "mdc" keyword trick still works, but soon enough we may have to start using "mdn" instead.
Maybe a little obvious to some...
Install Firebug and use console.log("hello"). So much better than using random alert();'s which I remember doing a lot a few years ago.
Private Methods
An object can have private methods.
function Person(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
// A private method only visible from within this constructor
function calcFullName() {
return firstName + " " + lastName;
}
// A public method available to everyone
this.sayHello = function () {
alert(calcFullName());
}
}
//Usage:
var person1 = new Person("Bob", "Loblaw");
person1.sayHello();
// This fails since the method is not visible from this scope
alert(person1.calcFullName());
Also mentioned in Crockford's "Javascript: The Good Parts":
parseInt() is dangerous. If you pass it a string without informing it of the proper base it may return unexpected numbers. For example parseInt('010') returns 8, not 10. Passing a base to parseInt makes it work correctly:
parseInt('010') // returns 8! (in FF3)
parseInt('010', 10); // returns 10 because we've informed it which base to work with.
Functions are objects and therefore can have properties.
fn = function(x) {
// ...
}
fn.foo = 1;
fn.next = function(y) {
//
}
I'd have to say self-executing functions.
(function() { alert("hi there");})();
Because Javascript doesn't have block scope, you can use a self-executing function if you want to define local variables:
(function() {
var myvar = 2;
alert(myvar);
})();
Here, myvar is does not interfere with or pollute the global scope, and disappears when the function terminates.
Know how many parameters are expected by a function
function add_nums(num1, num2, num3 ){
return num1 + num2 + num3;
}
add_nums.length // 3 is the number of parameters expected.
Know how many parameters are received by the function
function add_many_nums(){
return arguments.length;
}
add_many_nums(2,1,122,12,21,89); //returns 6
Here are some interesting things:
Comparing NaN with anything (even NaN) is always false, that includes ==, < and >.
NaN Stands for Not a Number but if you ask for the type it actually returns a number.
Array.sort can take a comparator function and is called by a quicksort-like driver (depends on implementation).
Regular expression "constants" can maintain state, like the last thing they matched.
Some versions of JavaScript allow you to access $0, $1, $2 members on a regex.
null is unlike anything else. It is neither an object, a boolean, a number, a string, nor undefined. It's a bit like an "alternate" undefined. (Note: typeof null == "object")
In the outermost context, this yields the otherwise unnameable [Global] object.
Declaring a variable with var, instead of just relying on automatic declaration of the variable gives the runtime a real chance of optimizing access to that variable
The with construct will destroy such optimzations
Variable names can contain Unicode characters.
JavaScript regular expressions are not actually regular. They are based on Perl's regexs, and it is possible to construct expressions with lookaheads that take a very, very long time to evaluate.
Blocks can be labeled and used as the targets of break. Loops can be labeled and used as the target of continue.
Arrays are not sparse. Setting the 1000th element of an otherwise empty array should fill it with undefined. (depends on implementation)
if (new Boolean(false)) {...} will execute the {...} block
Javascript's regular expression engine's are implementation specific: e.g. it is possible to write "non-portable" regular expressions.
[updated a little in response to good comments; please see comments]
I know I'm late to the party, but I just can't believe the + operator's usefulness hasn't been mentioned beyond "convert anything to a number". Maybe that's how well hidden a feature it is?
// Quick hex to dec conversion:
+"0xFF"; // -> 255
// Get a timestamp for now, the equivalent of `new Date().getTime()`:
+new Date();
// Safer parsing than parseFloat()/parseInt()
parseInt("1,000"); // -> 1, not 1000
+"1,000"; // -> NaN, much better for testing user input
parseInt("010"); // -> 8, because of the octal literal prefix
+"010"; // -> 10, `Number()` doesn't parse octal literals
// A use case for this would be rare, but still useful in cases
// for shortening something like if (someVar === null) someVar = 0;
+null; // -> 0;
// Boolean to integer
+true; // -> 1;
+false; // -> 0;
// Other useful tidbits:
+"1e10"; // -> 10000000000
+"1e-4"; // -> 0.0001
+"-12"; // -> -12
Of course, you can do all this using Number() instead, but the + operator is so much prettier!
You can also define a numeric return value for an object by overriding the prototype's valueOf() method. Any number conversion performed on that object will not result in NaN, but the return value of the valueOf() method:
var rnd = {
"valueOf": function () { return Math.floor(Math.random()*1000); }
};
+rnd; // -> 442;
+rnd; // -> 727;
+rnd; // -> 718;
"Extension methods in JavaScript" via the prototype property.
Array.prototype.contains = function(value) {
for (var i = 0; i < this.length; i++) {
if (this[i] == value) return true;
}
return false;
}
This will add a contains method to all Array objects. You can call this method using this syntax
var stringArray = ["foo", "bar", "foobar"];
stringArray.contains("foobar");
To properly remove a property from an object, you should delete the property instead of just setting it to undefined:
var obj = { prop1: 42, prop2: 43 };
obj.prop2 = undefined;
for (var key in obj) {
...
The property prop2 will still be part of the iteration. If you want to completely get rid of prop2, you should instead do:
delete obj.prop2;
The property prop2 will no longer will make an appearance when you're iterating through the properties.
with.
It's rarely used, and frankly, rarely useful... But, in limited circumstances, it does have its uses.
For instance: object literals are quite handy for quickly setting up properties on a new object. But what if you need to change half of the properties on an existing object?
var user =
{
fname: 'Rocket',
mname: 'Aloysus',
lname: 'Squirrel',
city: 'Fresno',
state: 'California'
};
// ...
with (user)
{
mname = 'J';
city = 'Frostbite Falls';
state = 'Minnesota';
}
Alan Storm points out that this can be somewhat dangerous: if the object used as context doesn't have one of the properties being assigned to, it will be resolved in the outer scope, possibly creating or overwriting a global variable. This is especially dangerous if you're used to writing code to work with objects where properties with default or empty values are left undefined:
var user =
{
fname: "John",
// mname definition skipped - no middle name
lname: "Doe"
};
with (user)
{
mname = "Q"; // creates / modifies global variable "mname"
}
Therefore, it is probably a good idea to avoid the use of the with statement for such assignment.
See also: Are there legitimate uses for JavaScript’s “with” statement?
Methods (or functions) can be called on object that are not of the type they were designed to work with. This is great to call native (fast) methods on custom objects.
var listNodes = document.getElementsByTagName('a');
listNodes.sort(function(a, b){ ... });
This code crashes because listNodes is not an Array
Array.prototype.sort.apply(listNodes, [function(a, b){ ... }]);
This code works because listNodes defines enough array-like properties (length, [] operator) to be used by sort().
Prototypal inheritance (popularized by Douglas Crockford) completely revolutionizes the way you think about loads of things in Javascript.
Object.beget = (function(Function){
return function(Object){
Function.prototype = Object;
return new Function;
}
})(function(){});
It's a killer! Pity how almost no one uses it.
It allows you to "beget" new instances of any object, extend them, while maintaining a (live) prototypical inheritance link to their other properties. Example:
var A = {
foo : 'greetings'
};
var B = Object.beget(A);
alert(B.foo); // 'greetings'
// changes and additionns to A are reflected in B
A.foo = 'hello';
alert(B.foo); // 'hello'
A.bar = 'world';
alert(B.bar); // 'world'
// ...but not the other way around
B.foo = 'wazzap';
alert(A.foo); // 'hello'
B.bar = 'universe';
alert(A.bar); // 'world'
Some would call this a matter of taste, but:
aWizz = wizz || "default";
// same as: if (wizz) { aWizz = wizz; } else { aWizz = "default"; }
The trinary operator can be chained to act like Scheme's (cond ...):
(cond (predicate (action ...))
(predicate2 (action2 ...))
(#t default ))
can be written as...
predicate ? action( ... ) :
predicate2 ? action2( ... ) :
default;
This is very "functional", as it branches your code without side effects. So instead of:
if (predicate) {
foo = "one";
} else if (predicate2) {
foo = "two";
} else {
foo = "default";
}
You can write:
foo = predicate ? "one" :
predicate2 ? "two" :
"default";
Works nice with recursion, too :)
Numbers are also objects. So you can do cool stuff like:
// convert to base 2
(5).toString(2) // returns "101"
// provide built in iteration
Number.prototype.times = function(funct){
if(typeof funct === 'function') {
for(var i = 0;i < Math.floor(this);i++) {
funct(i);
}
}
return this;
}
(5).times(function(i){
string += i+" ";
});
// string now equals "0 1 2 3 4 "
var x = 1000;
x.times(function(i){
document.body.innerHTML += '<p>paragraph #'+i+'</p>';
});
// adds 1000 parapraphs to the document
How about closures in JavaScript (similar to anonymous methods in C# v2.0+). You can create a function that creates a function or "expression".
Example of closures:
//Takes a function that filters numbers and calls the function on
//it to build up a list of numbers that satisfy the function.
function filter(filterFunction, numbers)
{
var filteredNumbers = [];
for (var index = 0; index < numbers.length; index++)
{
if (filterFunction(numbers[index]) == true)
{
filteredNumbers.push(numbers[index]);
}
}
return filteredNumbers;
}
//Creates a function (closure) that will remember the value "lowerBound"
//that gets passed in and keep a copy of it.
function buildGreaterThanFunction(lowerBound)
{
return function (numberToCheck) {
return (numberToCheck > lowerBound) ? true : false;
};
}
var numbers = [1, 15, 20, 4, 11, 9, 77, 102, 6];
var greaterThan7 = buildGreaterThanFunction(7);
var greaterThan15 = buildGreaterThanFunction(15);
numbers = filter(greaterThan7, numbers);
alert('Greater Than 7: ' + numbers);
numbers = filter(greaterThan15, numbers);
alert('Greater Than 15: ' + numbers);
You can also extend (inherit) classes and override properties/methods using the prototype chain spoon16 alluded to.
In the following example we create a class Pet and define some properties. We also override the .toString() method inherited from Object.
After this we create a Dog class which extends Pet and overrides the .toString() method again changing it's behavior (polymorphism). In addition we add some other properties to the child class.
After this we check the inheritance chain to show off that Dog is still of type Dog, of type Pet, and of type Object.
// Defines a Pet class constructor
function Pet(name)
{
this.getName = function() { return name; };
this.setName = function(newName) { name = newName; };
}
// Adds the Pet.toString() function for all Pet objects
Pet.prototype.toString = function()
{
return 'This pets name is: ' + this.getName();
};
// end of class Pet
// Define Dog class constructor (Dog : Pet)
function Dog(name, breed)
{
// think Dog : base(name)
Pet.call(this, name);
this.getBreed = function() { return breed; };
}
// this makes Dog.prototype inherit from Pet.prototype
Dog.prototype = new Pet();
// Currently Pet.prototype.constructor
// points to Pet. We want our Dog instances'
// constructor to point to Dog.
Dog.prototype.constructor = Dog;
// Now we override Pet.prototype.toString
Dog.prototype.toString = function()
{
return 'This dogs name is: ' + this.getName() +
', and its breed is: ' + this.getBreed();
};
// end of class Dog
var parrotty = new Pet('Parrotty the Parrot');
var dog = new Dog('Buddy', 'Great Dane');
// test the new toString()
alert(parrotty);
alert(dog);
// Testing instanceof (similar to the `is` operator)
alert('Is dog instance of Dog? ' + (dog instanceof Dog)); //true
alert('Is dog instance of Pet? ' + (dog instanceof Pet)); //true
alert('Is dog instance of Object? ' + (dog instanceof Object)); //true
Both answers to this question were codes modified from a great MSDN article by Ray Djajadinata.
You may catch exceptions depending on their type. Quoted from MDC:
try {
myroutine(); // may throw three exceptions
} catch (e if e instanceof TypeError) {
// statements to handle TypeError exceptions
} catch (e if e instanceof RangeError) {
// statements to handle RangeError exceptions
} catch (e if e instanceof EvalError) {
// statements to handle EvalError exceptions
} catch (e) {
// statements to handle any unspecified exceptions
logMyErrors(e); // pass exception object to error handler
}
NOTE: Conditional catch clauses are a Netscape (and hence Mozilla/Firefox) extension that is not part of the ECMAScript specification and hence cannot be relied upon except on particular browsers.
Off the top of my head...
Functions
arguments.callee refers to the function that hosts the "arguments" variable, so it can be used to recurse anonymous functions:
var recurse = function() {
if (condition) arguments.callee(); //calls recurse() again
}
That's useful if you want to do something like this:
//do something to all array items within an array recursively
myArray.forEach(function(item) {
if (item instanceof Array) item.forEach(arguments.callee)
else {/*...*/}
})
Objects
An interesting thing about object members: they can have any string as their names:
//these are normal object members
var obj = {
a : function() {},
b : function() {}
}
//but we can do this too
var rules = {
".layout .widget" : function(element) {},
"a[href]" : function(element) {}
}
/*
this snippet searches the page for elements that
match the CSS selectors and applies the respective function to them:
*/
for (var item in rules) {
var elements = document.querySelectorAll(rules[item]);
for (var e, i = 0; e = elements[i++];) rules[item](e);
}
Strings
String.split can take regular expressions as parameters:
"hello world with spaces".split(/\s+/g);
//returns an array: ["hello", "world", "with", "spaces"]
String.replace can take a regular expression as a search parameter and a function as a replacement parameter:
var i = 1;
"foo bar baz ".replace(/\s+/g, function() {return i++});
//returns "foo1bar2baz3"
You can use objects instead of switches most of the time.
function getInnerText(o){
return o === null? null : {
string: o,
array: o.map(getInnerText).join(""),
object:getInnerText(o["childNodes"])
}[typeis(o)];
}
Update: if you're concerned about the cases evaluating in advance being inefficient (why are you worried about efficiency this early on in the design of the program??) then you can do something like this:
function getInnerText(o){
return o === null? null : {
string: function() { return o;},
array: function() { return o.map(getInnerText).join(""); },
object: function () { return getInnerText(o["childNodes"]; ) }
}[typeis(o)]();
}
This is more onerous to type (or read) than either a switch or an object, but it preserves the benefits of using an object instead of a switch, detailed in the comments section below. This style also makes it more straightforward to spin this out into a proper "class" once it grows up enough.
update2: with proposed syntax extensions for ES.next, this becomes
let getInnerText = o -> ({
string: o -> o,
array: o -> o.map(getInnerText).join(""),
object: o -> getInnerText(o["childNodes"])
}[ typeis o ] || (->null) )(o);
Be sure to use the hasOwnProperty method when iterating through an object's properties:
for (p in anObject) {
if (anObject.hasOwnProperty(p)) {
//Do stuff with p here
}
}
This is done so that you will only access the direct properties of anObject, and not use the properties that are down the prototype chain.
Private variables with a Public Interface
It uses a neat little trick with a self-calling function definition.
Everything inside the object which is returned is available in the public interface, while everything else is private.
var test = function () {
//private members
var x = 1;
var y = function () {
return x * 2;
};
//public interface
return {
setx : function (newx) {
x = newx;
},
gety : function () {
return y();
}
}
}();
assert(undefined == test.x);
assert(undefined == test.y);
assert(2 == test.gety());
test.setx(5);
assert(10 == test.gety());

Categories

Resources