I want to use Proxy on a customized class called ObservableList which contains an Array. Since Proxy is available only after ES6, I wonder if there is any alternative implementation.
My requirement is to get updated (rather than get noticed) for observers once ObservableList changes, so that the observers are always consist with observable with some filtering or mapping method.
var activities = new ObservableList(['reading', 'swimming']);
var sAct = activities.filter(function(v) {
return v[0] === 's';
});
// expect sAct.list to be ['swimming']
var meAct = activities.map(function(v) {
return 'I am ' + v;
});
// expect meAct.list to be ['I am reading', 'I am swimming']
activities.list.push('smiling');
console.log(sAct.list, meAct.list);
// expect sAct.list to be ['swimming', 'smiling']
// expect meAct.list to be ['I am reading', 'I am swimming', 'I am smiling']
activities.list[1] = 'snoopying';
console.log(sAct.list, meAct.list);
// expect sAct.list to be ['swimming', 'snoopying']
// expect meAct.list to be ['I am reading', 'I am snoopying', 'I am smiling']
My implementation with Proxy is available at https://jsfiddle.net/ovilia/tLmbptr0/3/
used defineProperty.
not exactly with what you want. i just implemented a "reactive array". but i think it maybe works in your problems.
bad parts:
defined tons of getters/setters on the target.
accessing indexers not defined will be not reactive.
update() is to-be optimized.
good parts:
ES5 friendly.
if no indexers needed, use set(i, val)/get(i) will be reactive.
https://jsfiddle.net/jimnox/jrtq40p7/2/
As described in questions, I only need ObservableList to contain an Array, rather than to extend it, as Jim did in his complicated answer. And surprisingly enough, I found this could be easily achieved by wrapping the original Array operations.
One limitation is that index operation is not reactive in my implementation, in that I failed to find a proper way to capture index operations. If you have a better idea, feel welcomed to tell me! XD
Here's the full implementation.
export class ObservableList {
list: Array<any>;
private _observer: Array<ObserverList>;
constructor(list?: Array<any>) {
this.list = list || [];
this._initList();
this._initMethods();
this._observer = [];
}
notify(): void {
for (let o of this._observer) {
o.update();
}
}
private _initList(): void {
var that = this;
var operations = ['push', 'pop', 'shift', 'unshift', 'splice',
'sort', 'reverse'];
for (let operation of operations) {
this.list[operation] = function() {
var res = Array.prototype[operation].apply(that.list, arguments);
that.notify();
return res;
}
}
}
private _initMethods(): void {
var that = this;
var methods = ['filter', 'map'];
for (let method of methods) {
this[method] = (formatter: Function): ObserverList => {
var observer = new ObserverList(that, formatter, method);
this._observer.push(observer);
return observer;
}
}
}
}
export class ObserverList {
public list: Array<any>;
constructor(public observable: ObservableList,
public formatter: Function,
public method: string) {
this.list = [];
this.update();
}
update(): void {
var list = [];
var master = this.observable.list;
for (var i = 0, len = master.length; i < len; ++i) {
if (this.method === 'filter') {
if (this.formatter(master[i])) {
list.push(master[i]);
}
} else if (this.method === 'map') {
list.push(this.formatter(master[i]));
} else {
console.error('Illegal method ' + this.method + '.');
}
}
this.list = list;
}
}
Is using proxies a hard requirement? I wouldn't recommend proxies for
general programming tasks as you can end up with unpredictable and
hard-to-spot side effects.
If you keep to data and functions to transform it, avoiding mutable
state where possible, I think you'll end up with simpler code that's
easier to maintain.
var activities = ['reading', 'swimming'];
var sfilter = function(activities){
return activities.filter(function(v){
return v[0] === 's';
});
};
console.log(sfilter(activities));
var memap = function(activities){
return activities.map(function(v){
return 'I am ' + v;
});
};
console.log(memap(activities));
activities.push('smiling');
console.log(sfilter(activities));
console.log(memap(activities));
// Yes, I know this doesn't work in quite the same way,
// but you're asking for trouble here since in your
// code you're appending to one list, but overwriting
// an element in the other.
activities[1] = 'snoopying';
console.log(sfilter(activities));
console.log(memap(activities));
Stick to a Single Source of Truth and observe that. With each copy you are multiplying state complexity. That will make debugging, testing, and extending the code difficult.
Related
I'm just beginning to understand how the Observer Pattern works. But now I want to put it to use. I see lots of examples of the Observer Pattern, but most simply demonstrate the pattern and don't show it being implemented to complete a task.
I understand that an observer gets notified by a subject. But, how can I then get the observer to then do something as a result?
The code below is a common Observer Pattern program. I see that it executes a console.log (console.log("Observer " + number + " is notified!");) when an observer is notified. Is this where I could, instead, return other things: values, function calls, etc.?
I've seen visual examples with simple math that updates a calculation when an observer is notified (i.e., cost + tax = total). But I can't find an example that shows how the code is making this happening. 1. how/where is the new cost being returned and 2. so an observer (a function?) gets notified that the cost has changed; how/where does the function receive the updated cost?
I'm a novice and the pattern, itself, is a bit baffling on its own. I'd love to see a super basic example program.
var Subject = function() {
let observers = [];
return {
subscribeObserver: function(observer) {
observers.push(observer);
},
unsubscribeObserver: function(observer) {
var index = observers.indexOf(observer);
if(index > -1) {
observers.splice(index, 1);
}
},
notifyObserver: function(observer) {
var index = observers.indexOf(observer);
if(index > -1) {
observers[index].notify(index);
}
},
notifyAllObservers: function() {
for(var i = 0; i < observers.length; i++){
observers[i].notify(i);
};
}
};
};
var Observer = function(number) {
return {
notify: function() {
console.log("Observer " + number + " is notified!");
}
}
}
var subject = new Subject();
var observer1 = new Observer(1);
var observer2 = new Observer(2);
subject.subscribeObserver(observer1);
subject.subscribeObserver(observer2);
subject.notifyObserver(observer2);
subject.unsubscribeObserver(observer2);
subject.notifyAllObservers();
In the simplest form, an Observer is nothing but a function that is invoked by the Subject. More "complex" Observers would be objects with a "notify" or similar function, an error handler and maybe a "done" notification, depending on the Subject.
So here's a very basic example to demonstrate this:
var Subject = function() {
let observers = [];
return {
subscribe: function(observer) {
observers.push(observer);
},
unsubscribe: function(observer) {
var index = observers.indexOf(observer);
if(index > -1) {
observers.splice(index, 1);
}
},
nextValue: function(value) {
// call every registered observer
for(var i = 0; i < observers.length; i++){
observers[i](value);
}
}
};
};
// now simply pass an observer function to the subject
const subject = new Subject();
subject.subscribe(value => {
// do whatever you want with the value, call functions etc.
console.log(value);
});
subject.nextValue('hello world!');
Just use the RxJs library.
https://www.learnrxjs.io/
const { Subject } = rxjs;
const subject$ = new Subject();
subject$.subscribe(val => { console.log(val); });
subject$.next('Hello');
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/6.5.1/rxjs.umd.min.js"></script>
The code below is a common Observer Pattern program. I see that it executes a console.log (console.log("Observer " + number + " is notified!");) when an observer is notified. Is this where I could, instead, return other things: values, function calls, etc.?
Yes when the subject calls notify it can pass data instead of an index or pass itself to the observer. In this way the observer can inspect Subject's state and do something with it. The method notifyObserver becomes:
notifyObserver: function(observer) {
var index = observers.indexOf(observer);
if(index > -1) {
observers[index].notify(this);
}
},
And the observer is something like:
var Observer = function(number) {
return {
notify: function(subject) {
// do something with subject
...
}
}
}
I need to do some experiment and I need to know some kind of unique identifier for objects in javascript, so I can see if they are the same. I don't want to use equality operators, I need something like the id() function in python.
Does something like this exist ?
Update My original answer below was written 6 years ago in a style befitting the times and my understanding. In response to some conversation in the comments, a more modern approach to this is as follows:
(function() {
if ( typeof Object.id != "undefined" ) return;
var id = 0;
Object.id = function(o) {
if ( typeof o.__uniqueid != "undefined" ) {
return o.__uniqueid;
}
Object.defineProperty(o, "__uniqueid", {
value: ++id,
enumerable: false,
// This could go either way, depending on your
// interpretation of what an "id" is
writable: false
});
return o.__uniqueid;
};
})();
var obj = { a: 1, b: 1 };
console.log(Object.id(obj));
console.log(Object.id([]));
console.log(Object.id({}));
console.log(Object.id(/./));
console.log(Object.id(function() {}));
for (var k in obj) {
if (obj.hasOwnProperty(k)) {
console.log(k);
}
}
// Logged keys are `a` and `b`
If you have archaic browser requirements, check here for browser compatibility for Object.defineProperty.
The original answer is kept below (instead of just in the change history) because I think the comparison is valuable.
You can give the following a spin. This also gives you the option to explicitly set an object's ID in its constructor or elsewhere.
(function() {
if ( typeof Object.prototype.uniqueId == "undefined" ) {
var id = 0;
Object.prototype.uniqueId = function() {
if ( typeof this.__uniqueid == "undefined" ) {
this.__uniqueid = ++id;
}
return this.__uniqueid;
};
}
})();
var obj1 = {};
var obj2 = new Object();
console.log(obj1.uniqueId());
console.log(obj2.uniqueId());
console.log([].uniqueId());
console.log({}.uniqueId());
console.log(/./.uniqueId());
console.log((function() {}).uniqueId());
Take care to make sure that whatever member you use to internally store the unique ID doesn't collide with another automatically created member name.
So far as my observation goes, any answer posted here can have unexpected side effects.
In ES2015-compatible enviroment, you can avoid any side effects by using WeakMap.
const id = (() => {
let currentId = 0;
const map = new WeakMap();
return (object) => {
if (!map.has(object)) {
map.set(object, ++currentId);
}
return map.get(object);
};
})();
id({}); //=> 1
Latest browsers provide a cleaner method for extending Object.prototype. This code will make the property hidden from property enumeration (for p in o)
For the browsers that implement defineProperty, you can implement uniqueId property like this:
(function() {
var id_counter = 1;
Object.defineProperty(Object.prototype, "__uniqueId", {
writable: true
});
Object.defineProperty(Object.prototype, "uniqueId", {
get: function() {
if (this.__uniqueId == undefined)
this.__uniqueId = id_counter++;
return this.__uniqueId;
}
});
}());
For details, see https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Object/defineProperty
Actually, you don't need to modify the object prototype and add a function there. The following should work well for your purpose.
var __next_objid=1;
function objectId(obj) {
if (obj==null) return null;
if (obj.__obj_id==null) obj.__obj_id=__next_objid++;
return obj.__obj_id;
}
For browsers implementing the Object.defineProperty() method, the code below generates and returns a function that you can bind to any object you own.
This approach has the advantage of not extending Object.prototype.
The code works by checking if the given object has a __objectID__ property, and by defining it as a hidden (non-enumerable) read-only property if not.
So it is safe against any attempt to change or redefine the read-only obj.__objectID__ property after it has been defined, and consistently throws a nice error instead of silently fail.
Finally, in the quite extreme case where some other code would already have defined __objectID__ on a given object, this value would simply be returned.
var getObjectID = (function () {
var id = 0; // Private ID counter
return function (obj) {
if(obj.hasOwnProperty("__objectID__")) {
return obj.__objectID__;
} else {
++id;
Object.defineProperty(obj, "__objectID__", {
/*
* Explicitly sets these two attribute values to false,
* although they are false by default.
*/
"configurable" : false,
"enumerable" : false,
/*
* This closure guarantees that different objects
* will not share the same id variable.
*/
"get" : (function (__objectID__) {
return function () { return __objectID__; };
})(id),
"set" : function () {
throw new Error("Sorry, but 'obj.__objectID__' is read-only!");
}
});
return obj.__objectID__;
}
};
})();
Typescript version of #justin answer, ES6 compatible, using Symbols to prevent any key collision and added into the global Object.id for convenience. Just copy paste the code below, or put it into an ObjecId.ts file you will import.
(enableObjectID)();
declare global {
interface ObjectConstructor {
id: (object: any) => number;
}
}
const uniqueId: symbol = Symbol('The unique id of an object');
export function enableObjectID(): void {
if (typeof Object['id'] !== 'undefined') {
return;
}
let id: number = 0;
Object['id'] = (object: any) => {
const hasUniqueId: boolean = !!object[uniqueId];
if (!hasUniqueId) {
object[uniqueId] = ++id;
}
return object[uniqueId];
};
}
Example of usage:
console.log(Object.id(myObject));
jQuery code uses it's own data() method as such id.
var id = $.data(object);
At the backstage method data creates a very special field in object called "jQuery" + now() put there next id of a stream of unique ids like
id = elem[ expando ] = ++uuid;
I'd suggest you use the same method as John Resig obviously knows all there is about JavaScript and his method is based on all that knowledge.
For the purpose of comparing two objects, the simplest way to do this would be to add a unique property to one of the objects at the time you need to compare the objects, check if the property exists in the other and then remove it again. This saves overriding prototypes.
function isSameObject(objectA, objectB) {
unique_ref = "unique_id_" + performance.now();
objectA[unique_ref] = true;
isSame = objectB.hasOwnProperty(unique_ref);
delete objectA[unique_ref];
return isSame;
}
object1 = {something:true};
object2 = {something:true};
object3 = object1;
console.log(isSameObject(object1, object2)); //false
console.log(isSameObject(object1, object3)); //true
I faced the same problem and here's the solution I implemented with ES6
code
let id = 0; // This is a kind of global variable accessible for every instance
class Animal {
constructor(name){
this.name = name;
this.id = id++;
}
foo(){}
// Executes some cool stuff
}
cat = new Animal("Catty");
console.log(cat.id) // 1
I've used code like this, which will cause Objects to stringify with unique strings:
Object.prototype.__defineGetter__('__id__', function () {
var gid = 0;
return function(){
var id = gid++;
this.__proto__ = {
__proto__: this.__proto__,
get __id__(){ return id }
};
return id;
}
}.call() );
Object.prototype.toString = function () {
return '[Object ' + this.__id__ + ']';
};
the __proto__ bits are to keep the __id__ getter from showing up in the object. this has been only tested in firefox.
Notwithstanding the advice not to modify Object.prototype, this can still be really useful for testing, within a limited scope. The author of the accepted answer changed it, but is still setting Object.id, which doesn't make sense to me. Here's a snippet that does the job:
// Generates a unique, read-only id for an object.
// The _uid is generated for the object the first time it's accessed.
(function() {
var id = 0;
Object.defineProperty(Object.prototype, '_uid', {
// The prototype getter sets up a property on the instance. Because
// the new instance-prop masks this one, we know this will only ever
// be called at most once for any given object.
get: function () {
Object.defineProperty(this, '_uid', {
value: id++,
writable: false,
enumerable: false,
});
return this._uid;
},
enumerable: false,
});
})();
function assert(p) { if (!p) throw Error('Not!'); }
var obj = {};
assert(obj._uid == 0);
assert({}._uid == 1);
assert([]._uid == 2);
assert(obj._uid == 0); // still
This one will calculate a HashCode for each object, optimized for string, number and virtually anything that has a getHashCode function. For the rest it assigns a new reference number.
(function() {
var __gRefID = 0;
window.getHashCode = function(ref)
{
if (ref == null) { throw Error("Unable to calculate HashCode on a null reference"); }
// already cached reference id
if (ref.hasOwnProperty("__refID")) { return ref["__refID"]; }
// numbers are already hashcodes
if (typeof ref === "number") { return ref; }
// strings are immutable, so we need to calculate this every time
if (typeof ref === "string")
{
var hash = 0, i, chr;
for (i = 0; i < ref.length; i++) {
chr = ref.charCodeAt(i);
hash = ((hash << 5) - hash) + chr;
hash |= 0;
}
return hash;
}
// virtual call
if (typeof ref.getHashCode === "function") { return ref.getHashCode(); }
// generate and return a new reference id
return (ref["__refID"] = "ref" + __gRefID++);
}
})();
If you came here because you deal with class instances like me you can use static vars/methods to reference instances by a custom unique id:
class Person {
constructor( name ) {
this.name = name;
this.id = Person.ix++;
Person.stack[ this.id ] = this;
}
}
Person.ix = 0;
Person.stack = {};
Person.byId = id => Person.stack[ id ];
let store = {};
store[ new Person( "joe" ).id ] = true;
store[ new Person( "tim" ).id ] = true;
for( let id in store ) {
console.log( Person.byId( id ).name );
}
Here's a variant of Justin Johnson's answer that provides a scalability benefit when you are creating billions of objects for which you want the ID.
Specifically, rather than solely using a 1-up counter (that might overflow the representational limits of Number, and can't be cycled without risking reusing an ID), we register the object and its newly generated ID with a FinalizationRegistry, such that, at some point after the object is garbage collected, the ID is returned to a freelist for reuse by a newly created object (Python's id function can also return the same ID for multiple objects, so long as the existence of the two objects does not overlap in time).
Limitations:
It only works on objects, not JS primitives (this is somewhat reasonable; unlike Python, where everything is an object, JS primitives typically aren't, and the id function logically only works on objects, since primitives need not "exist" in any reasonably identifiable way).
If the code creates (without discarding) billions of objects, asks for their IDs, then releases them all at once and never asks for an ID again, the recovered IDs in the freelist constitute a memory leak of sorts. Hopefully the JS optimizer stores them efficiently, so the cost remains a small fraction of what the objects themselves cost, but it's still a cost. In cases where objects with IDs are regularly created and destroyed, the wasted memory is roughly tied to the maximum number of such ID-ed objects in existence at any given point in time.
If those limitations aren't a problem though, this works fairly well. I modified the testing code a bit to hand control back to the event loop (and hopefully the garbage collector) now and again while creating 10M garbage objects to ID, and on my browser, nearly half the object IDs get reclaimed for reuse; the final loop making five objects and IDing them produces IDs just above 1M, when over 2M objects had IDs generated at some point. In a realistic scenario with meaningful code executing and real async usage I'd expect better results simply because there would be more opportunities for the finalization registry to perform cleanup.
async function sleep(ms) {
await _sleep(ms);
}
function _sleep(ms) {
return new Promise((resolve) => setTimeout(resolve, ms));
}
(function() {
if ( typeof Object.id != "undefined" ) return;
var freelist = []; // Stores previously used IDs for reuse when an object with
// an ID is garbage collected, so creating and dropping billions
// of objects doesn't consume all available IDs
const registry = new FinalizationRegistry((freeid) => {
freelist.push(freeid);
});
var id = 0;
Object.id = function(o) {
if ( typeof o.__uniqueid != "undefined" ) {
return o.__uniqueid;
}
Object.defineProperty(o, "__uniqueid", {
value: freelist.length ? freelist.pop() : ++id,
enumerable: false,
// This could go either way, depending on your
// interpretation of what an "id" is
writable: false
});
registry.register(o, o.__uniqueid); // Sometime after o is collected, its ID
// will be reclaimed for use by a new object
return o.__uniqueid;
};
})();
var obj = { a: 1, b: 1 };
console.log(Object.id(obj));
console.log(Object.id([]));
console.log(Object.id({}));
console.log(Object.id(/./));
var idsum = 0; // So we do something real to prevent optimizing out code
// Make a ton of temporary objects with IDs, handing control back to the event loop
// every once in a while to (hopefully) see some IDs returned to the pool
for (var i = 0; i < 1000000; ++i) {
idsum += Object.id({c: i});
}
sleep(10).then(() => {
console.log(Object.id(function() { console.log("Hey"); }));
for (var i = 1000000; i < 2000000; ++i) {
idsum += Object.id({c: i});
}
console.log(Object.id(function() { console.log("There"); }));
sleep(10).then(() => {
for (var i = 0; i < 5; ++i) {
console.log(Object.id([i]));
}
console.log(idsum);
});
});
for (var k in obj) {
if (obj.hasOwnProperty(k)) {
console.log(k);
}
}
// Logged keys are `a` and `b`
This is a strange one, but I'm exploring it to see if it's possible.
Let's say that I have a .NET application where I am using PubSub. I want a way to define the topic string using chained objects (not functions). The goal is to allow me a way of defining strings that lets me to take advantage of Visual Studio's IntelliSense and reduce the likelihood of spelling errors.
Here's an example:
/* Manual way */
var topic = "App.Navigation.CurrentItem"
/* Desired Solution */
// ... define the objects here ...
var topic = App.Navigation.CurrentItem;
console.log(topic); // "App.Navigation.CurrentItem"
var topic2 = App.Footer.CurrentItem;
console.log(topic2); // "App.Footer.CurrentItem"
I'd like each object to be responsible for outputing it's own value, and have the chaining process responsible for joining itself to the previous chained object via a predefined separator (in my case, a period [.]).
I've been playing with JavaScript getter syntax, but I'm curious if there's a better way.
Has anyone done something like this before, and if so, how did you solve it?
You're requirements aren't totally clear to me, but are you looking for something like this?
function namespace(ns) { this._ns = ns; }
namespace.prototype.toString = function() {return this._ns};
namespace.prototype.extend = function(suffix) {
return new namespace(this._ns + "." + suffix)
};
Usage:
App = new namespace('App');
App.Navigation = App.extend('Navigation');
App.Navigation.CurrentItem = App.Navigation.extend('CurrentItem');
console.log(App.Navigation.CurrentItem.toString()); // "App.Navigation.CurrentItem"
This is what I ended up with after reviewing StriplingWarrior's answer:
function Namespace(name, config) {
if (typeof name === "object") {
config = name;
name = null;
}
config = config || {};
this._ns = name;
this.define(config);
}
Namespace.prototype.toString = function() { return this._ns };
Namespace.prototype.define = function(config, base) {
base = base || this;
for (key in config) {
var name = (base._ns) ? base._ns + "." + key : key;
base[key] = new Namespace(name);
base.define(config[key], base[key]);
}
return base;
};
Usage:
var App = new Namespace("App", {
Navigation: {
Items: {
Current: {}
}
},
Content: {},
Footer: {
Items: {
Current: {}
}
}
});
console.log(App.toString()); // App
console.log(App.Navigation.Items.Current.toString()); // App.Navigation.Items.Current
console.log(App.Footer.toString()); // App.Footer
I also wrote a convenience method to reduce the toString():
function NS(namespace) {
return namespace.toString();
}
console.log(NS(App.Navigation.Items.Current));
Thanks again to StriplingWarrior for the the help!
For a personal challenge, I'm implementing LINQ in JavaScript (well, a set of functions with LINQ-like functionality). However, as of right now, the functions are processing the data immediately; that's correct behavior for some functions (such as Sum or Aggregate), but incorrect for others (such as Select or While).
I'm curious if there's a construct in JavaScript that could get me the same behavior as in .Net, where no real processing happens until the collection is enumerated or a function with immediate execution is used.
Note: I believe this task (implementing LINQ in JS) has already been done. That's not the point. This is a challenge to myself from myself, which is likely to help me increase my understanding of LINQ (and, coincidentally, JS). Beyond personal edification, I'm going to be using LINQ for my job soon, may use JS for my job depending on the needs of individual projects, and I use JS for some things outside of work.
Edit: It seems I've attracted people unfamiliar with LINQ, so I suppose I should give some explanation on that front. LINQ is Language-INtegrated Query, something from .Net. LINQ allows for SQL-like queries on many data sources (including actual SQL relational databases), such as LINQ to Objects, which is what I'm trying to achieve.
One of the features of LINQ is deferred execution on many of the methods. If I have a collection customers and call var query = customers.Where(c => c.Age > 40); (or what it would end up being in JS, var query = customers.Where(function (c) { return c.Age > 40; });), the return value is an interface type, and the actual processing of the collection (returning the subset of the collection containing only customers older than 40) hasn't happened yet. When I use one of the methods without deferred execution (eg, query.First() or query.ToArray()), then all of the deferred processing happens. This could be a chain, such as customers.Where(...).Skip(5).Select(...).OrderBy(...) (each "..." being a function).
The upshot is that code like this:
var collection = [1, 2, 3, 4, 5];
var query = collection.Where(function (n) { return n % 2 == 0; });
collection.push(6);
alert(query.Max());
Would result in "6".
As an addendum, I'm currently implementing this project by prototyping my methods onto both Object and Array, iterating over the elements of this, and skipping any elements which are functions. Something like making an Enumerable class may be superior (and in fact may be required for my deferred execution plan, if something like returning a function or an anonymous object is required), but that's what I've currently got. My functions generally appear as something along these lines:
Object.prototype.Distinct = Array.prototype.Distinct = function (comparer) {
comparer = comparer || function (a, b) { return a == b; };
var result = [];
for (var idx in this) {
var item = this[idx];
if (typeof item == "function") continue;
if (!result.Contains(item, comparer)) result.push(item);
}
return result;
};
Fundamentally what you need to do is return objects from your functions rather than performing operations. The objects you return will contain the code necessary to perform the operations in the future. Consider an example use case:
var myCollection = [];
for(var i = 0; i < 100; i++) { myCollection.push(i); }
var query = Iter(myCollection).Where(function(v) { return v % 2 === 0; })
.Skip(5).Select(function(v) { return v*2; });
var v;
while(v = query.Next()) {
console.log(v);
}
We expect as output:
20
24
28
...
188
192
196
In order to do that we define the methods .Where(), .Skip(), and .Select() to return instances of classes with overridden versions of the .Next() method. Working code that supports this functionality: ( set trace to true to observe that the execution order is lazy)
var trace = false;
function extend(target, src) {
for(var k in src) {
target[k] = src[k];
}
return target;
}
function Iter(wrapThis) {
if(wrapThis.Next) {
return wrapThis;
} else {
return new ArrayIter(wrapThis);
}
}
Iter.prototype = {
constructor: Iter,
Where: function(fn) { return new WhereIter(this, fn); },
Skip: function(count) { return new SkipIter(this, count); },
Select: function(fn) { return new SelectIter(this, fn); }
};
function ArrayIter(arr) {
this.arr = arr.slice();
this.idx = 0;
}
ArrayIter.prototype = extend(Object.create(Iter.prototype),
{
constructor: ArrayIter,
Next: function() {
if(this.idx >= this.arr.length) {
return null;
} else {
return this.arr[this.idx++];
}
}
});
function WhereIter(src, filter) {
this.src = src; this.filter = filter;
}
WhereIter.prototype = extend(Object.create(Iter.prototype), {
constructor: WhereIter,
Next: function() {
var v;
while(true) {
v = this.src.Next();
trace && console.log('Where processing: ' + v);
if(v === null || this.filter.call(this, v)) { break; }
}
return v;
}
});
function SkipIter(src, count) {
this.src = src; this.count = count;
this.skipped = 0;
}
SkipIter.prototype = extend(Object.create(Iter.prototype), {
constructor: SkipIter,
Next: function() {
var v;
while(this.count > this.skipped++) {
v = this.src.Next();
trace && console.log('Skip processing: ' + v);
if(v === null) { return v; }
}
return this.src.Next();
}
});
function SelectIter(src, fn) {
this.src = src; this.fn = fn;
}
SelectIter.prototype = extend(Object.create(Iter.prototype), {
constructor: SelectIter,
Next: function() {
var v = this.src.Next();
trace && console.log('Select processing: ' + v);
if(v === null) { return null; }
return this.fn.call(this, v);
}
});
var myCollection = [];
for(var i = 0; i < 100; i++) {
myCollection.push(i);
}
var query = Iter(myCollection).Where(function(v) { return v % 2 === 0; })
.Skip(5).Select(function(v) { return v*2; });
var v;
while(v = query.Next()) {
console.log(v);
}
You also may want to look into "string lambdas" to make your queries much more readable. That would allow you to say "v*2" instead of function(v) { return v*2; }
I am not entirely clear on what exactly you wish to do, but I think what you should look into is the defineProperty method. What you would probably wish to do is then to redefine the .length property and execute the code only once it's read. Or if you want to do it only once the property itself is read do it at that point. Not sure how LINQ works or even what it is, so that's why I am a bit vague. Either way, with defineProperty you can do something like
Object.defineProperty(o, "a", { get : function(){return 1;});
Allowing you to do actions only once the property is accessed (and you can do a lot more than that as well).
I need to do some experiment and I need to know some kind of unique identifier for objects in javascript, so I can see if they are the same. I don't want to use equality operators, I need something like the id() function in python.
Does something like this exist ?
Update My original answer below was written 6 years ago in a style befitting the times and my understanding. In response to some conversation in the comments, a more modern approach to this is as follows:
(function() {
if ( typeof Object.id != "undefined" ) return;
var id = 0;
Object.id = function(o) {
if ( typeof o.__uniqueid != "undefined" ) {
return o.__uniqueid;
}
Object.defineProperty(o, "__uniqueid", {
value: ++id,
enumerable: false,
// This could go either way, depending on your
// interpretation of what an "id" is
writable: false
});
return o.__uniqueid;
};
})();
var obj = { a: 1, b: 1 };
console.log(Object.id(obj));
console.log(Object.id([]));
console.log(Object.id({}));
console.log(Object.id(/./));
console.log(Object.id(function() {}));
for (var k in obj) {
if (obj.hasOwnProperty(k)) {
console.log(k);
}
}
// Logged keys are `a` and `b`
If you have archaic browser requirements, check here for browser compatibility for Object.defineProperty.
The original answer is kept below (instead of just in the change history) because I think the comparison is valuable.
You can give the following a spin. This also gives you the option to explicitly set an object's ID in its constructor or elsewhere.
(function() {
if ( typeof Object.prototype.uniqueId == "undefined" ) {
var id = 0;
Object.prototype.uniqueId = function() {
if ( typeof this.__uniqueid == "undefined" ) {
this.__uniqueid = ++id;
}
return this.__uniqueid;
};
}
})();
var obj1 = {};
var obj2 = new Object();
console.log(obj1.uniqueId());
console.log(obj2.uniqueId());
console.log([].uniqueId());
console.log({}.uniqueId());
console.log(/./.uniqueId());
console.log((function() {}).uniqueId());
Take care to make sure that whatever member you use to internally store the unique ID doesn't collide with another automatically created member name.
So far as my observation goes, any answer posted here can have unexpected side effects.
In ES2015-compatible enviroment, you can avoid any side effects by using WeakMap.
const id = (() => {
let currentId = 0;
const map = new WeakMap();
return (object) => {
if (!map.has(object)) {
map.set(object, ++currentId);
}
return map.get(object);
};
})();
id({}); //=> 1
Latest browsers provide a cleaner method for extending Object.prototype. This code will make the property hidden from property enumeration (for p in o)
For the browsers that implement defineProperty, you can implement uniqueId property like this:
(function() {
var id_counter = 1;
Object.defineProperty(Object.prototype, "__uniqueId", {
writable: true
});
Object.defineProperty(Object.prototype, "uniqueId", {
get: function() {
if (this.__uniqueId == undefined)
this.__uniqueId = id_counter++;
return this.__uniqueId;
}
});
}());
For details, see https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Object/defineProperty
Actually, you don't need to modify the object prototype and add a function there. The following should work well for your purpose.
var __next_objid=1;
function objectId(obj) {
if (obj==null) return null;
if (obj.__obj_id==null) obj.__obj_id=__next_objid++;
return obj.__obj_id;
}
For browsers implementing the Object.defineProperty() method, the code below generates and returns a function that you can bind to any object you own.
This approach has the advantage of not extending Object.prototype.
The code works by checking if the given object has a __objectID__ property, and by defining it as a hidden (non-enumerable) read-only property if not.
So it is safe against any attempt to change or redefine the read-only obj.__objectID__ property after it has been defined, and consistently throws a nice error instead of silently fail.
Finally, in the quite extreme case where some other code would already have defined __objectID__ on a given object, this value would simply be returned.
var getObjectID = (function () {
var id = 0; // Private ID counter
return function (obj) {
if(obj.hasOwnProperty("__objectID__")) {
return obj.__objectID__;
} else {
++id;
Object.defineProperty(obj, "__objectID__", {
/*
* Explicitly sets these two attribute values to false,
* although they are false by default.
*/
"configurable" : false,
"enumerable" : false,
/*
* This closure guarantees that different objects
* will not share the same id variable.
*/
"get" : (function (__objectID__) {
return function () { return __objectID__; };
})(id),
"set" : function () {
throw new Error("Sorry, but 'obj.__objectID__' is read-only!");
}
});
return obj.__objectID__;
}
};
})();
Typescript version of #justin answer, ES6 compatible, using Symbols to prevent any key collision and added into the global Object.id for convenience. Just copy paste the code below, or put it into an ObjecId.ts file you will import.
(enableObjectID)();
declare global {
interface ObjectConstructor {
id: (object: any) => number;
}
}
const uniqueId: symbol = Symbol('The unique id of an object');
export function enableObjectID(): void {
if (typeof Object['id'] !== 'undefined') {
return;
}
let id: number = 0;
Object['id'] = (object: any) => {
const hasUniqueId: boolean = !!object[uniqueId];
if (!hasUniqueId) {
object[uniqueId] = ++id;
}
return object[uniqueId];
};
}
Example of usage:
console.log(Object.id(myObject));
jQuery code uses it's own data() method as such id.
var id = $.data(object);
At the backstage method data creates a very special field in object called "jQuery" + now() put there next id of a stream of unique ids like
id = elem[ expando ] = ++uuid;
I'd suggest you use the same method as John Resig obviously knows all there is about JavaScript and his method is based on all that knowledge.
For the purpose of comparing two objects, the simplest way to do this would be to add a unique property to one of the objects at the time you need to compare the objects, check if the property exists in the other and then remove it again. This saves overriding prototypes.
function isSameObject(objectA, objectB) {
unique_ref = "unique_id_" + performance.now();
objectA[unique_ref] = true;
isSame = objectB.hasOwnProperty(unique_ref);
delete objectA[unique_ref];
return isSame;
}
object1 = {something:true};
object2 = {something:true};
object3 = object1;
console.log(isSameObject(object1, object2)); //false
console.log(isSameObject(object1, object3)); //true
I faced the same problem and here's the solution I implemented with ES6
code
let id = 0; // This is a kind of global variable accessible for every instance
class Animal {
constructor(name){
this.name = name;
this.id = id++;
}
foo(){}
// Executes some cool stuff
}
cat = new Animal("Catty");
console.log(cat.id) // 1
I've used code like this, which will cause Objects to stringify with unique strings:
Object.prototype.__defineGetter__('__id__', function () {
var gid = 0;
return function(){
var id = gid++;
this.__proto__ = {
__proto__: this.__proto__,
get __id__(){ return id }
};
return id;
}
}.call() );
Object.prototype.toString = function () {
return '[Object ' + this.__id__ + ']';
};
the __proto__ bits are to keep the __id__ getter from showing up in the object. this has been only tested in firefox.
Notwithstanding the advice not to modify Object.prototype, this can still be really useful for testing, within a limited scope. The author of the accepted answer changed it, but is still setting Object.id, which doesn't make sense to me. Here's a snippet that does the job:
// Generates a unique, read-only id for an object.
// The _uid is generated for the object the first time it's accessed.
(function() {
var id = 0;
Object.defineProperty(Object.prototype, '_uid', {
// The prototype getter sets up a property on the instance. Because
// the new instance-prop masks this one, we know this will only ever
// be called at most once for any given object.
get: function () {
Object.defineProperty(this, '_uid', {
value: id++,
writable: false,
enumerable: false,
});
return this._uid;
},
enumerable: false,
});
})();
function assert(p) { if (!p) throw Error('Not!'); }
var obj = {};
assert(obj._uid == 0);
assert({}._uid == 1);
assert([]._uid == 2);
assert(obj._uid == 0); // still
This one will calculate a HashCode for each object, optimized for string, number and virtually anything that has a getHashCode function. For the rest it assigns a new reference number.
(function() {
var __gRefID = 0;
window.getHashCode = function(ref)
{
if (ref == null) { throw Error("Unable to calculate HashCode on a null reference"); }
// already cached reference id
if (ref.hasOwnProperty("__refID")) { return ref["__refID"]; }
// numbers are already hashcodes
if (typeof ref === "number") { return ref; }
// strings are immutable, so we need to calculate this every time
if (typeof ref === "string")
{
var hash = 0, i, chr;
for (i = 0; i < ref.length; i++) {
chr = ref.charCodeAt(i);
hash = ((hash << 5) - hash) + chr;
hash |= 0;
}
return hash;
}
// virtual call
if (typeof ref.getHashCode === "function") { return ref.getHashCode(); }
// generate and return a new reference id
return (ref["__refID"] = "ref" + __gRefID++);
}
})();
If you came here because you deal with class instances like me you can use static vars/methods to reference instances by a custom unique id:
class Person {
constructor( name ) {
this.name = name;
this.id = Person.ix++;
Person.stack[ this.id ] = this;
}
}
Person.ix = 0;
Person.stack = {};
Person.byId = id => Person.stack[ id ];
let store = {};
store[ new Person( "joe" ).id ] = true;
store[ new Person( "tim" ).id ] = true;
for( let id in store ) {
console.log( Person.byId( id ).name );
}
Here's a variant of Justin Johnson's answer that provides a scalability benefit when you are creating billions of objects for which you want the ID.
Specifically, rather than solely using a 1-up counter (that might overflow the representational limits of Number, and can't be cycled without risking reusing an ID), we register the object and its newly generated ID with a FinalizationRegistry, such that, at some point after the object is garbage collected, the ID is returned to a freelist for reuse by a newly created object (Python's id function can also return the same ID for multiple objects, so long as the existence of the two objects does not overlap in time).
Limitations:
It only works on objects, not JS primitives (this is somewhat reasonable; unlike Python, where everything is an object, JS primitives typically aren't, and the id function logically only works on objects, since primitives need not "exist" in any reasonably identifiable way).
If the code creates (without discarding) billions of objects, asks for their IDs, then releases them all at once and never asks for an ID again, the recovered IDs in the freelist constitute a memory leak of sorts. Hopefully the JS optimizer stores them efficiently, so the cost remains a small fraction of what the objects themselves cost, but it's still a cost. In cases where objects with IDs are regularly created and destroyed, the wasted memory is roughly tied to the maximum number of such ID-ed objects in existence at any given point in time.
If those limitations aren't a problem though, this works fairly well. I modified the testing code a bit to hand control back to the event loop (and hopefully the garbage collector) now and again while creating 10M garbage objects to ID, and on my browser, nearly half the object IDs get reclaimed for reuse; the final loop making five objects and IDing them produces IDs just above 1M, when over 2M objects had IDs generated at some point. In a realistic scenario with meaningful code executing and real async usage I'd expect better results simply because there would be more opportunities for the finalization registry to perform cleanup.
async function sleep(ms) {
await _sleep(ms);
}
function _sleep(ms) {
return new Promise((resolve) => setTimeout(resolve, ms));
}
(function() {
if ( typeof Object.id != "undefined" ) return;
var freelist = []; // Stores previously used IDs for reuse when an object with
// an ID is garbage collected, so creating and dropping billions
// of objects doesn't consume all available IDs
const registry = new FinalizationRegistry((freeid) => {
freelist.push(freeid);
});
var id = 0;
Object.id = function(o) {
if ( typeof o.__uniqueid != "undefined" ) {
return o.__uniqueid;
}
Object.defineProperty(o, "__uniqueid", {
value: freelist.length ? freelist.pop() : ++id,
enumerable: false,
// This could go either way, depending on your
// interpretation of what an "id" is
writable: false
});
registry.register(o, o.__uniqueid); // Sometime after o is collected, its ID
// will be reclaimed for use by a new object
return o.__uniqueid;
};
})();
var obj = { a: 1, b: 1 };
console.log(Object.id(obj));
console.log(Object.id([]));
console.log(Object.id({}));
console.log(Object.id(/./));
var idsum = 0; // So we do something real to prevent optimizing out code
// Make a ton of temporary objects with IDs, handing control back to the event loop
// every once in a while to (hopefully) see some IDs returned to the pool
for (var i = 0; i < 1000000; ++i) {
idsum += Object.id({c: i});
}
sleep(10).then(() => {
console.log(Object.id(function() { console.log("Hey"); }));
for (var i = 1000000; i < 2000000; ++i) {
idsum += Object.id({c: i});
}
console.log(Object.id(function() { console.log("There"); }));
sleep(10).then(() => {
for (var i = 0; i < 5; ++i) {
console.log(Object.id([i]));
}
console.log(idsum);
});
});
for (var k in obj) {
if (obj.hasOwnProperty(k)) {
console.log(k);
}
}
// Logged keys are `a` and `b`