The core provides basic utility functions and properties that are used by the rest of the library.
These are the public properties available under the UsefulJS namespace:
The global context; may be one of window
or global
.
The name of the global context; may be one of "window"
or "global"
.
Regular expression object to test for whitespace. In most modern browsers this will be equivalent to /\s/
However, not all browsers correctly make \s Unicode-aware. RE_WS is Unicode-aware and may be used to correctly test for whitespace in all browsers:
UsefulJS.RE_WS.test("\u00a0"); // true
Portable regular expression object that matches whitespace at the start of a string.
Portable regular expression object that matches whitespace at the end of a string.
A map of detected features. This is intended primarily for internal use and currently exposes the following properties that your application code can test for:
Object.defineProperty
is available.
Object.create
is available.
"use strict";
has any effect.Additional modules (such as ClassList) may add additional properties.
The detected list separator (such as ',' or ';') in use on the system.
These are the public methods available under the UsefulJS namespace:
Tests to see whether its argument is defined, that is not null or undefined
UsefulJS.defined(obj)
// Optional boolean parameter defaults to true var f = function(strParam, boolParam) { if (!UsefulJS.defined(boolParam)) { boolParam = true; } ... };
Returns somewhat more reliable run-time type information for its argument than the built-in
typeof
operator.
UsefulJS._typeof(obj)
Poor RTTI is one of JavaScript's core weaknesses and makes generic programming painful and error prone. Almost everything is identified as an "object":
typeof("a") // "string"; OK typeof([]) // "array"; Good // Pre-allocate typeof(new Array(1000)) // "object"; Huh? typeof(null) // "object"; You're kidding, right? typeof(document) // "object"; A pattern emerges
_typeof uses introspection (not duck-typing, other than as a last resort) to identify the type of its argument:
_typeof(new Array(1000)) // "array" _typeof(null) // "null" _typeof(document) // "document"
A list of inputs and return values is shown below:
Input | Return value | Input | Return value |
---|---|---|---|
undefined | "undefined" | User-defined class | "object" |
null | "null" | Date | "date" |
Boolean | "boolean" | RegExp | "regexp" |
new Boolean() | "boolean" | ArrayBuffer | "arraybuffer" |
Number | "number" | Element (any) | "element" |
new Number() | "number" | Element attribute | "attr" |
String | "string" | Text node | "text" |
new String() | "string" | document | "document" |
Array | "array" | Event (any) | "event" |
new Array() | "array" | Error (any) | "error" |
Function | "function" | window | "window" |
new Function() | "function" | Math | "math" |
Object | "object" | JSON | "json" |
var addClass = function(elem, clName) { // Inputs must be an element and a string var _u = UsefulJS; if (!(_u._typeof(elem) === "element" && _u._typeof(clName) === "string")) { throw new TypeError("Bad arguments"); } ... };
Returns an object that is equal but not identical to its argument
UsefulJS.clone(obj)
JavaScript Array and Object variables are pointers. Not keeping this in mind can lead to hard-to-track-down bugs:
var a = [1, 2, 3, 4], b = a; ... Many lines later ... b[0] = 5; // Changed a; is this intended?
clone creates, in effect, a bitwise copy of its argument, resulting in an independent copy that can safely be modified without unexpected side-effects:
var a = [1, 2, 3, 4], b = UsefulJS.clone(a); ... Many lines later ... b[0] = 5; // a[0] is still 1
Only objects for which cloning makes sense are cloned; other types are returned as-is. Cloneable object types are:
Arrays and Objects are cloned recursively, that is any cloneable items that they contain are also cloned.
clone
keeps track of how many times it has been called recursively in a single clone
operation. If the recursion depth exceeds 100, it will raise an Error. This is
better than a browser crash. Basically, if your Objects contain circular references by design,
(this may be legitimate in a tree structure, for example) do not attempt to clone
them. If your Objects contain circular references by accident, give yourself a smack
on the head!
Object.create
, cloning an instance
of a user-defined class will cause the returned value to lose its identity: the properties
will be copied, but it will no longer be an instance of the class. You can test
UsefulJS.featureSupport.createObject
to see whether instances of a
user-defined class can be successfully cloned.
To clarify the results of a clone operation, examine the following snippet:
var a = { a : 1, b : [1] }, b = UsefulJS.clone(a); a.a === b.a; // scalar, true a.b === b.b; // array, false a.b[0] === b.b[0]; // true a === b; // false
var StaticList = function(arr) { // Hide the initial data in a closure this.data = (function() { var _data = UsefulJS.clone(arr); return { get : function() { // Don't give out private data return UsefulJS.clone(_data); } }; })(); }; var sl = new StaticList([1, 2, 3, 4]), arr = sl.data.get(); arr[0] = 2; var k = sl.data.get()[0]; // k = 1;
defined
, _typeof
and clone
are exported to the global namespace by
default. _typeof
is intended as a drop-in replacement for the built-in
typeof
operator. Apart from UsefulJS itself, these are the only additions to the global
namespace.
Pads a string to a specified length using a specified character; padding is either left or right
UsefulJS.pad(s, padTo, padWith, right)
s
StringpadTo
NumberpadWith
Stringright
BooleanReturns: String
// Turn a string into a series of \uxxxx sequences var uLit = Array.from("한국어").reduce(function(s, c) { return s + "\\u" + UsefulJS.pad(c.charCodeAt(0).toString(16), 4, '0'); }, "");
padLeft
and padRight
methods of String.prototype
Merges properties from one object into another.
UsefulJS.mix(o1, o2, prefer1)
o1
Objecto2
Objectprefer1
BooleanReturns: Object
Copies the properties that are in o2 into o1 and returns o1. o2 is unaffected.
To avoid inadvertent bugs with shared references, properties are cloned rather than copied.
If both o2 and o1 have identically named properties that are also Objects, the two values will be mixed recursively.
The prefer1 parameter controls how conflicts are handled. If o1 already contains a property and prefer1 is true, it will be left alone (unless it is an Object - see above). Otherwise it will be overwritten.
var a = { a : 1, b : { p1 : "a" }, d : null }, b = { a : 2, b : { p1 : "b", p2 : "c" }, c : 3, d : 4 }; UsefulJS.mix(a, b, true); // a is now // { // a : 1, // b : { // p1 : "a", // p2 : "c" // }, // c : 3, // d : null // }
mix
function is used when defining locale properties. Each locale definition contains
only the attributes that are different from another locale and these are mixed with the properties of the
parent locale.
Returns the property names (or keys) of an Object
UsefulJS.keys(obj)
obj
ObjectReturns: Array of property names. If the object has no enumerable properties, the array will be empty.
This will be the same function as Object.keys
if that function
is implemented. The return value only contains property names for which
hasOwnProperty
returns true.
Iterates over an object, calling a callback function for each enumerable property until either the keys are exhausted or the callback function returns false.
UsefulJS.every(obj, callback, ctx)
obj
Objectcallback
Functionf(value, key, obj)
ctx
Objectthis
context for the callbackReturns: Boolean true unless the callback returns false.
Throws: TypeError if the callback is not a function.
Iterates over an object, calling a callback function for each enumerable property which should return true for the properties that are to be copied into the return value.
UsefulJS.filter(obj, callback, ctx)
All iteration functions take the same parameters
Returns: Object A shallow copy of the input with a subset of the properties of the original.
Iterates over an object, calling a callback function for each enumerable property which should return true if the required value has been found.
UsefulJS.find(obj, callback, ctx)
All iteration functions take the same parameters
Returns: Object The item that satisfies the callback or undefined.
Iterates over an object, calling a callback function for each enumerable property which should return true if the required key has been found.
UsefulJS.findKey(obj, callback, ctx)
All iteration functions take the same parameters
Returns: Object The key that satisfies the callback or undefined.
Iterates over an object, calling a callback function for each enumerable property.
UsefulJS.forEach(obj, callback, ctx)
All iteration functions take the same parameters
Returns: undefined.
Iterates over an object, calling a callback function for each enumerable property which should return a value be set in the return value. The property name set will be the same one passed to the callback
UsefulJS.map(obj, callback, ctx)
All iteration functions take the same parameters
Returns: Object A shallow copy of the input with the same property names as the original but with values transformed by the mapping function.
Iterates over an object, calling a callback function for each enumerable property until either the keys are exhausted or the callback function returns true.
UsefulJS.some(obj, callback, ctx)
All iteration functions take the same parameters
Returns: Boolean false unless the callback returns true.
var _u = UsefulJS, obj = { ... }; // Does the object have any undefined values var isGood = _u.every(obj, function(item, key) { return _u.defined(item); }); // Filter out undefined values obj = isGood ? obj : _u.filter(obj, function(item, key) { return _u.defined(item); }); // Transform the values remaining obj = _u.map(obj, function(item, key) { return String(item).toLocaleUpperCase(); });
Many objects, such as strings and instances of Date or RegExp, have no enumerable properties.
The properties that will be enumerated over are frozen when you call an iterator. This means that you can
modify the input (it's passed as the obj
parameter to the callback) as it's iterated over. The
callback will not be called for properties that are no longer in the input.
You can pass Array objects to the iteration functions and the return value from filter and map will be arrays. However, since Array objects have their own iteration methods which, likely as not, will run at native speed, there is little point.
Array-like objects are better served with generic Array methods. For example, Array.prototype.forEach
will iterate over the characters in a string while UsefulJS.forEach will not.
filter creates a shallow copy of the input. Be careful with shared references. Depending on how values are transformed, the return value from map may have shared references as well.
If the system supports Object.create
, the returns from filter and
map will be the instances of the same class as the input. Otherwise they will be plain
objects.
Generates a UUID (universally unique identifier).
UsefulJS.uuid()
Generates an RFC 4122-compliant UUID. The version field is 4 (randomly generated).
Applies fixes provided by the various UsefulJS modules
UsefulJS.fix(opts)
Each UsefulJS module registers fix callbacks with the core on load. When you call UsefulJS.fix
,
these callbacks are called and the fixes are applied. You can control which fixes are applied via the
(optional) opts
parameter. If you are happy with the defaults, you don't need to specify
anything. If, for some reason, you don't want the defined
function exported into the global
namespace, you'd call fix
like this:
UsefulJS.fix({ _core : { defined : false } });
Rather than supplying Objects as the input options, you can specify "all"
or
"none"
. So if you didn't want anything exported into the global namespace you could call:
UsefulJS.fix({ _core : "none" });
The return value is an object indicating which fixes have been applied. The naming convention in the output properties is the same as that in the input properties so that if the defaults are used, the output properties might look like this:
{ _core : { defined : true, _typeof : true, clone : true }, _array : { ... } ... }
_array
property in the return value will be populated while on Internet Explorer 9, it
won't be.
Generally, fixes that fill in standard methods and properties that are absent in the runtime environment are applied by default and have to be explicitly disabled. Non-standard extensions to the standard classes have to be explicitly enabled.
Implementation of String.fromCodePoint
.
UsefulJS.fromCodePoint(codePoint1[, codePoint2, ...])
If String.fromCodePoint
is implemented in the browser, this will
be the same function. It constructs a String from one or more code points (numeric
values between 0 and 0x10ffff). Code points between 0x10000 and 0x10ffff are
resolved into surrogate pairs.
Implementation of String.prototype.codePointAt
.
UsefulJS.codePointAt.call(str, pos)
If String.prototype.codePointAt
is implemented in the browser, this will
be the same function. It behaves like charCodeAt
unless the character
at pos is one half of a surrogate pair, in which case it combines the character
code at this position and the next into a single value >= 0x10000.
Implementation of Object.is
.
UsefulJS.is(a, b)
Evaluates to the same boolean value as a === b
with two exceptions:
returns false if a is 0 and b is -0 (or vice versa); returns true if a and b are
both NaN.
The fixes for the core module are defined in the _core namespace in the input and output properties. All are applied by default.
Make UsefulJS.defined
available in the global namespace.
Make UsefulJS._typeof
available in the global namespace.
Make UsefulJS.clone
available in the global namespace.
Add navigator.language
property if not already present.
navigator.language
contains
a value that you can use. On Webkit-based browsers, the value is baked in at compile-time and is consequently
useless.
Adds a bind method to Function.prototype
if not already present.
Adds an "is" static method to Object
if not already present.