...or are there better ways to implement a Memoization?
Function.memoize = function(callableAsString)
{
var r = false, callable, code;
try
{
callable = eval(callableAsString);
if (typeof callable == "function" && typeof(Function.memoize.cache[callableAsString]) == "undefined")
{
code = callableAsString + " = function()" +
"{" +
"var cache = Function.memoize.cache['" + callableAsString + "'];" +
"var k = Json.stringify([this].concat(arguments));" +
"return cache.r[k] || (cache.r[k] = cache.c.apply(this, arguments));" +
"};" +
"true;";
if (r = eval(code))
{
Function.memoize.cache[callableAsString] = {c: callable, r: {}};
}
}
}
catch (e) {}
return r;
};
Function.memoize.cache = {};
Function.memoize("String.prototype.camelize");
Update based on the suggestions by Felix Kling
Function.memoize = function(callable)
{
var r = false;
if (typeof callable == "function")
{
var hash = callable.toString().hashCode();
r = function()
{
var cache = Function.memoize.cache[hash];
var key = Json.stringify([this].concat(arguments));
return cache.r[key] || (cache.r[key] = cache.c.apply(this, arguments));
}
if (!Function.memoize.cache)
{
Function.memoize.cache = {};
}
r.memoize = callable;
Function.memoize.cache[hash] = {c: callable, r: {}};
}
return r;
};
Function.unmemoize = function(callable)
{
if (callable.memoize && typeof callable.memoize == "function")
{
return callable.memoize;
}
else
{
return false;
}
};
String.prototype.camelize = Function.memoize(String.prototype.camelize);
String.prototype.camelize = Function.unmemoize(String.prototype.camelize);
I don't see the need for eval... consider this implementation
function memoize(f, cache)
{
if (!cache) cache = {};
return function()
{
var key = JSON.stringify(arguments);
return (cache[key] || (cache[key] = [f.apply(this, arguments)]))[0];
}
}
Note that I deliberately ignored this in the key. The reason is that this may not be serializable by stringify (e.g. because of loops) and this is more the rule than the exception for example when this == window i.e. in the global context.
What is IMO useful is the ability to explictly pass the cache, so that you can for example create a separate cache for each instance or one shared cache for all instances by doing something like:
function MyObj(...)
{
// every instance has its own cache
this.foo = memoize(function(...) { ... });
// there is one shared cache for all instances
this.bar = memoize(function(...) { ... }, MyObj.memoize_cache);
}
MyObj.memoize_cache = {};
Related
I am building the customer manual on frontend using Madcam Flare 11 HTML5 output and referring the below js file but getting the error Uncaught Error: Mismatched anonymous define() module: function(C)
<script src="scripts/helpDoc/WHP/Default.js"></script>
After i load the Madcap library and runtime i am getting the below error. This error comes at very first time when i invoke the madcap flare methods.
require.min.js:13 Uncaught Error: Mismatched anonymous define() module: function () { 'use strict';
var commonjsGlobal = typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
function commonjsRequire () {
throw new Error('Dynamic requires are not currently supported by rollup-plugin-commonjs');
}
function unwrapExports (x) {
return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
}
function createCommonjsModule(fn, module) {
return module = { exports: {} }, fn(module, module.exports), module.exports;
}
var es6Promise = createCommonjsModule(function (module, exports) {
/*!
* #overview es6-promise - a tiny implementation of Promises/A+.
* #copyright Copyright (c) 2014 Yehuda Katz, Tom Dale, Stefan Penner and contributors (Conversion to ES6 API by Jake Archibald)
* #license Licensed under MIT license
* See https://raw.githubusercontent.com/stefanpenner/es6-promise/master/LICENSE
* #version v4.2.5+7f2b526d
*/
(function (global, factory) {
module.exports = factory();
}(commonjsGlobal, (function () { function objectOrFunction(x) {
var type = typeof x;
return x !== null && (type === 'object' || type === 'function');
}
function isFunction(x) {
return typeof x === 'function';
}
var _isArray = void 0;
if (Array.isArray) {
_isArray = Array.isArray;
} else {
_isArray = function (x) {
return Object.prototype.toString.call(x) === '[object Array]';
};
}
var isArray = _isArray;
var len = 0;
var vertxNext = void 0;
var customSchedulerFn = void 0;
var asap = function asap(callback, arg) {
queue[len] = callback;
queue[len + 1] = arg;
len += 2;
if (len === 2) {
// If len is 2, that means that we need to schedule an async flush.
// If additional callbacks are queued before the queue is flushed, they
// will be processed by this flush that we are scheduling.
if (customSchedulerFn) {
customSchedulerFn(flush);
} else {
scheduleFlush();
}
}
};
function setScheduler(scheduleFn) {
customSchedulerFn = scheduleFn;
}
function setAsap(asapFn) {
asap = asapFn;
}
var browserWindow = typeof window !== 'undefined' ? window : undefined;
var browserGlobal = browserWindow || {};
var BrowserMutationObserver = browserGlobal.MutationObserver || browserGlobal.WebKitMutationObserver;
var isNode = typeof self === 'undefined' && typeof process !== 'undefined' && {}.toString.call(process) === '[object process]';
// test for web worker but not in IE10
var isWorker = typeof Uint8ClampedArray !== 'undefined' && typeof importScripts !== 'undefined' && typeof MessageChannel !== 'undefined';
// node
function useNextTick() {
// node version 0.10.x displays a deprecation warning when nextTick is used recursively
// see https://github.com/cujojs/when/issues/410 for details
return function () {
return process.nextTick(flush);
};
}
// vertx
function useVertxTimer() {
if (typeof vertxNext !== 'undefined') {
return function () {
vertxNext(flush);
};
}
return useSetTimeout();
}
function useMutationObserver() {
var iterations = 0;
var observer = new BrowserMutationObserver(flush);
var node = document.createTextNode('');
observer.observe(node, { characterData: true });
return function () {
node.data = iterations = ++iterations % 2;
};
}
// web worker
function useMessageChannel() {
var channel = new MessageChannel();
channel.port1.onmessage = flush;
return function () {
return channel.port2.postMessage(0);
};
}
function useSetTimeout() {
// Store setTimeout reference so es6-promise will be unaffected by
// other code modifying setTimeout (like sinon.useFakeTimers())
var globalSetTimeout = setTimeout;
return function () {
return globalSetTimeout(flush, 1);
};
}
var queue = new Array(1000);
function flush() {
for (var i = 0; i < len; i += 2) {
var callback = queue[i];
var arg = queue[i + 1];
callback(arg);
queue[i] = undefined;
queue[i + 1] = undefined;
}
len = 0;
}
function attemptVertx() {
try {
var vertx = Function('return this')().require('vertx');
vertxNext = vertx.runOnLoop || vertx.runOnContext;
return useVertxTimer();
} catch (e) {
return useSetTimeout();
}
}
var scheduleFlush = void 0;
// Decide what async method to use to triggering processing of queued callbacks:
if (isNode) {
scheduleFlush = useNextTick();
} else if (BrowserMutationObserver) {
scheduleFlush = useMutationObserver();
} else if (isWorker) {
scheduleFlush = useMessageChannel();
} else if (browserWindow === undefined && typeof commonjsRequire === 'function') {
scheduleFlush = attemptVertx();
} else {
scheduleFlush = useSetTimeout();
}
function then(onFulfillment, onRejection) {
var parent = trequire.min.js:13)
at L (require.min.js:41)
at Object.g [as require] (require.min.js:104)
at requirejs (require.min.js:126)
at MadCap.WebHelp.HelpSystem.LoadLanguage (Default.js:269)
at Default.js:269
at MadCap.WebHelp.HelpSystem.LoadBreakpoints (Default.js:269)
at MadCap.WebHelp.HelpSystem.<anonymous> (Default.js:269)
at XMLHttpRequest.OnreadystatechangeRemote (Default.js:241)
I have an object called status where I want to keep track of any status of a class.
Beside setting various statuses I also want to keep track of how long these have been active. Now instead of defining a second property for every status to track the time, this sounded like a job for getter / setter.
That's where I'm stuck. How do I make them dynamic so they trigger for each property of status?
var Person = function(options) {
this.name = options.name;
var _statusChanged = {};
var _status = {};
// How to make this dynamic?
var expr = "isOnfire";
this.status = {
get [expr]() {
console.log(_statusChanged);
return _status[expr];
},
set [expr](val) {
_status[expr] = val;
_statusChanged[expr] = new Date();
return _status[expr];
}
};
};
var John = new Person({
name: "John"
});
John.status.isOnfire = true;
John.status.hasPinkShirt = true;
console.log(John, John.status.isOnfire, John.status.hasPinkShirt);
If you have a list of these, just create the getters/setters in a loop, e.g.:
this.status = {};
["isOnFire", "hasPinkShirt"].forEach((name) => {
Object.defineProperty(status, name {
get() {
console.log(_statusChanged);
return _status[name];
},
set(val) {
_status[name] = val;
_statusChanged[name] = new Date();
return _status[name];
}
});
});
If they could be anything, then you'll want to use a Proxy object. With a proxy, you can capture all gets/sets without knowing property names in advance:
this.status = new Proxy(_status, {
get(target, propKey, receiver) {
// handle get
return _status[propKey];
},
set(target, propKey, value, receiver) {
// handle set
_status[propKey] = value;
_statusChanged[propKey] = new Date();
return true; // Tells the proxy the assignment worked
}
});
(Or you might use Reflect.get and Reflect.set, but even Firefox doesn't have them yet.)
Here's an article going into proxies in more detail.
Here's an example, but you'll need to run it in a recent version of Firefox because support or Proxy in the wild is still really thin on the ground, and by their nature, you can't shim/polyfill proxies.
(function() {
"use strict";
var _status = {};
var _statusChanged = {};
var status = new Proxy(_status, {
get(target, propKey, receiver) {
snippet.log(propKey + " requested");
return _status[propKey];
},
set(target, propKey, value, receiver) {
snippet.log(propKey + " set to " + value);
_status[propKey] = value;
_statusChanged[propKey] = new Date();
return true; // Tells the proxy the assignment worked
}
});
status.foo = "bar";
snippet.log("foo = " + status.foo);
})();
<!-- Script provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 -->
<script src="http://tjcrowder.github.io/simple-snippets-console/snippet.js"></script>
Until you can use them, you'll need to make setting a status a method call, not an assignment.
You need an object called an ECMAScript 6 Proxy. In Firefox, they're on by default. At one point they were implemented in Chrome under "experimental JavaScript" but they seem to have been removed temporarily; see this ES6 compatibility table.
This code works in Firefox:
var output = function(text) {
var line = document.createElement('div');
line.innerHTML = text;
document.getElementById('output').appendChild(line);
}
var Person = function(options) {
this.name = options.name;
var _status = {};
var _statusChanged = {};
this.status = new Proxy(_status,{
get: function(target,property) {
return target[property];
},
set: function(target,property,value) {
_statusChanged[property] = new Date();
output("set " + property + " to " + value + " at " + _statusChanged[property]);
_status[property] = value;
}
});
this.show = function(property) {
output("Property " + property + " is " + _status[property] + " since " + _statusChanged[property]);
}
};
var John = new Person({
name: "John"
});
John.status.isOnfire = true;
John.status.hasPinkShirt = true;
John.show("isOnfire");
John.show("hasPinkShirt");
<div id="output"></div>
Maybe that would work for you
http://jsfiddle.net/oksbLyqf/16/
var Person = function (options) {
this.name = options.name;
var _statusChanged = {};
var _status = {};
var expr = '';
var addStatusProperty = function (prop) {
expr = prop;
Object.defineProperty(otherStatus, expr, {
get: function () {
console.log(_statusChanged);
return _status[expr];
},
set: function (val) {
_status[expr] = val;
_statusChanged[expr] = new Date();
return _status[expr];
}
});
};
var setStatusProperty = function (prop, val) {
expr = prop;
if (_status[expr]) {
otherStatus[expr] = val;
return _status[expr];
} else {
addStatusProperty(expr);
otherStatus[expr] = val;
return _status[expr];
}
};
var getStatusProperty = function (prop) {
expr = prop;
return _status[expr]
};
this.status = {
addProperty: addStatusProperty,
setProperty: setStatusProperty,
getProperty: getStatusProperty
};
var otherStatus = this.status;
};
var John = new Person({
name: "John"
});
John.status.setProperty('isOnfire', true);
John.status.setProperty('hasPinkShirt', true);
console.log(John, John.status.getProperty('isOnfire'), John.status.getProperty('hasPinkShirt'));
I lately was experimenting with the object serialization in JavaScript. I have already been looking through some of the questions concerning the serialization and deserialization of predefined object in Javascript, but I am looking for a more general solution. An example of this would be:
function anObject(){
var x = 1;
this.test = function(){return x;};
this.add = function(a){x+a;};
}
var x = new anObject();
x.add(2);
console.log(x.test());
>>> 3
var y = deserialize(serialize(x));
console.log(y.test());
>>> 3
Is there a way to serialize this object and deserialize it, such that the deserialized object still have access to the local variable x without the use of the prototype of that object (like in this solution)?
I have already tried by just storing the function as a string and evaluating it again, but then the state of an object can not be saved.
What you are trying to do is not possible without code introspection and code re-writing which I think is not a good idea. However, what about something like this?
function AnObject() {
var x = 1;
this.x = function () { return x; };
this.addToX = function (num) { x += num; };
this.memento = function () {
return { x: x };
};
this.restoreState = function (memento) {
x = memento.x;
};
}
var o = new AnObject();
o.addToX(2);
o.x(); //3
var serializedState = JSON.stringify(o.memento()),
o = new AnObject();
o.restoreState(JSON.parse(serializedState));
o.x(); //3
However, please note that having priviledged members comes at a great cost because you lose the benefits of using prototypes. For that reason I prefer not enforcing true privacy and rely on naming conventions such as this._myPrivateVariable instead (unless you are hiding members of a module).
Thanks for the responses. While the answer from plalx works perfectly for specific objects, I wanted to have something more general which just works for any object you throw at it.
Another solution one can use is something like this:
function construct(constructor, args, vars) {
function Obj() {
var variables = vars
return constructor.apply(this, args);
}
Obj.prototype = constructor.prototype;
return new Obj();
}
function addFunction(anObject, aFunction, variables) {
var objectSource = anObject.toString();
var functionSource = aFunction.toString();
objectSource = objectSource.substring(0,objectSource.length-1);
var functionName = functionSource.substring(9, functionSource.indexOf('('));
var functionArgs = functionSource.substring(functionSource.indexOf('('), functionSource.indexOf('{')+1);
var functionBody = functionSource.substring(functionSource.indexOf('{')+1, functionSource.length);
return objectSource + "this." + functionName + " = function" +
functionArgs + "var variables = " + variables + ";\n" + functionBody + "}";
}
function makeSerializable(anObject) {
var obj = JSON.stringify(anObject, function(key, val) {
return ((typeof val === "function") ? val+'' : val);
});
var variables = [];
while(obj.indexOf("var") > -1) {
var subString = obj.substring(obj.indexOf("var")+3, obj.length-1);
while (subString[0] == " ")
subString = subString.replace(" ", "");
var varEnd = Math.min(subString.indexOf(" "), subString.indexOf(";"));
var varName = subString.substring(0, varEnd);
variables.push(varName);
obj = obj.replace("var","");
}
var anObjectSource = addFunction(anObject,
function serialize(){
var vars = [];
console.log("hidden variables:" + variables);
variables.forEach(function(variable) {
console.log(variable + ": " + eval(variable));
vars += JSON.stringify([variable, eval(variable)]);
});
var serialized = [];
serialized.push(vars);
for (var func in this){
if (func != "serialize")
serialized.push([func, this[func].toString()]);
}
return JSON.stringify(serialized);
},
JSON.stringify(variables));
anObject = Function("return " + anObjectSource)();
var params = Array.prototype.slice.call(arguments);
params.shift();
return construct(anObject, params, variables);
}
This allows you to serialize all elements of any object, including the hidden variables. The serialize() function can then be replaced by a custom string representation for the hidden variables, which can be used when deserializing the string representation to the object.
usage:
function anObject(){
var x = 1;
var y = [1,2];
var z = {"name": "test"};
this.test = function(){return x;};
this.add = function(a){x+a;};
}
var test = makeSerializable(anObject)
test.serialize()
>>>["[\"x\",1][\"y\",[1,2]][\"z\",{\"name\":\"test\"}]",["test","function (){return x;}"],["add","function (a){x+a;}"]]
I am trying to simulate a namespace feature in Javascript.
var com = {};
com.domain = {};
com.domain.system = {};
com.domain.net = {};
com.domain.net.ip = {};
com.domain.net.ip.tcp = {};
com.domain.net.ip.udp = {};
com.domain.net.ip.ssl = {};
com.domain.util = {};
com.domain.util.timer = {};
com.domain.plugins = {};
com.domain.session = {};
com.domain.io = {};
com.domain.algorithm = {};
com.domain.debug = {};
This is the namespaces declaration. Later I will add functions to these namespaces.
This is my selector function:
For a convenient way to use namespaces, I add a function named $. This function will walk all namespaces in com. If the selected name exists, return the object.
function $ (selector) {
function digger (namespace, selector) {
for (var prop in namespace) {
if (typeof namespace[prop] == "array" || typeof namespace[prop] == "object") {
if (prop == selector) {
return namespace[prop];
}
var dig = digger(namespace[prop], selector);
if (dig != null) {
return dig;
}
} else {
if (prop == selector) {
return namespace[prop];
}
}
}
}
return digger (com, selector);
}
After that, I add a timer to namespace com.doamin.util.
com.domain.util.timer = function () {
this._handle = new InnerObj.SystemTimer(io);
return this;
};
com.domain.util.timer.prototype.expiresFromNow = function (seconds, cbHandler) {
this._handle.ExpiresFromNow (seconds, cbHandler);
};
com.domain.util.timer.prototype.wait = function (seconds, cbHandler) {
this._handle.Wait (seconds, cbHandler);
};
com.domain.util.timer.prototype.expiresAt = function (seconds, cbHandler) {
this._handle.Wait (seconds, cbHandler);
};
com.domain.util.timer.prototype.cancel = function () {
this._handle.Cancel ();
};
Usage:
1. var timer = new com.domain.util.timer (); OK
timer.expiresAt (1, {}); OK
2. var func = $("timer"); OK
var timer = new func (); OK
timer.expiresAt (1, {}); OK
But but but but but
var timer = new $("timer") (); NG
Can anyone tell me why the last new function is not working?
Try var timer = new ($("timer"))();.
Your question is not clear but I guess since $("timer") returns a function, you want a new instance of the result of $("timer") and not a new instance of $().
This is a question for the guru of JavaScript. I'm trying to do work with JavaScript prototype model more elegant. Here is my utility code (it provides real chain of prototypes and correct work with instanceof operator):
function Class(conf) {
var init = conf.init || function () {};
delete conf.init;
var parent = conf.parent || function () {};
delete conf.parent;
var F = function () {};
F.prototype = parent.prototype;
var f = new F();
for (var fn in conf) f[fn] = conf[fn];
init.prototype = f;
return init;
};
It allows me to do such thigns:
var Class_1 = new Class({
init: function (msg) { // constructor
this.msg = msg;
},
method_1: function () {
alert(this.msg + ' in Class_1::method_1');
},
method_2: function () {
alert(this.msg + ' in Class_1::method_2');
}
});
var Class_2 = new Class({
parent: Class_1,
init: function (msg) { // constructor
this.msg = msg;
},
// method_1 will be taken from Class_1
method_2: function () { // this method will overwrite the original one
alert(this.msg + ' in Class_2::method_2');
},
method_3: function () { // just new method
alert(this.msg + ' in Class_2::method_3');
}
});
var c1 = new Class_1('msg');
c1.method_1(); // msg in Class_1::method_1
c1.method_2(); // msg in Class_1::method_2
var c2 = new Class_2('msg');
c2.method_1(); // msg in Class_1::method_1
c2.method_2(); // msg in Class_2::method_2
c2.method_3(); // msg in Class_2::method_3
alert('c1 < Class_1 - ' + (c1 instanceof Class_1 ? 'true' : 'false')); // true
alert('c1 < Class_2 - ' + (c1 instanceof Class_2 ? 'true' : 'false')); // false
alert('c2 < Class_1 - ' + (c2 instanceof Class_1 ? 'true' : 'false')); // true
alert('c2 < Class_2 - ' + (c2 instanceof Class_2 ? 'true' : 'false')); // true
My question is: Is there more simple way to do this?
Yes, there is a better way to do this.
var call = Function.prototype.call;
var classes = createStorage(),
namespaces = createStorage(),
instances = createStorage(createStorage);
function createStorage(creator){
var storage = new WeakMap;
creator = typeof creator === 'function' ? creator : Object.create.bind(null, null, {});
return function store(o, v){
if (v) {
storage.set(o, v);
} else {
v = storage.get(o);
if (!v) {
storage.set(o, v = creator(o));
}
}
return v;
};
}
function Type(){
var self = function(){}
self.__proto__ = Type.prototype;
return self;
}
Type.prototype = Object.create(Function, {
constructor: { value: Type,
writable: true,
configurable: true },
subclass: { value: function subclass(scope){ return new Class(this, scope) },
configurable: true,
writable: true }
});
function Class(Super, scope){
if (!scope) {
scope = Super;
Super = new Type;
}
if (typeof Super !== 'function') {
throw new TypeError('Superconstructor must be a function');
} else if (typeof scope !== 'function') {
throw new TypeError('A scope function was not provided');
}
this.super = Super;
this.scope = scope;
return this.instantiate();
}
Class.unwrap = function unwrap(Ctor){
return classes(Ctor);
};
Class.prototype.instantiate = function instantiate(){
function super_(){
var name = super_.caller === Ctor ? 'constructor' : super_.caller.name;
var method = Super.prototype[name];
if (typeof method !== 'function') {
throw new Error('Attempted to call non-existent supermethod');
}
return call.apply(method, arguments);
}
var Super = this.super,
namespace = namespaces(Super),
private = instances(namespace)
var Ctor = this.scope.call(namespace, private, super_);
Ctor.__proto__ = Super;
Ctor.prototype.__proto__ = Super.prototype;
namespaces(Ctor, namespace);
classes(Ctor, this);
return Ctor;
}
example usage:
var Primary = new Class(function(_, super_){
var namespace = this;
namespace.instances = 0;
function Primary(name, secret){
this.name = name;
_(this).secret = secret;
namespace.instances++;
}
Primary.prototype.logSecret = function logSecret(label){
label = label || 'secret';
console.log(label + ': ' + _(this).secret);
}
return Primary;
});
var Derived = Primary.subclass(function(_, super_){
function Derived(name, secret, size){
super_(this, name, secret);
this.size = size;
}
Derived.prototype.logSecret = function logSecret(){
super_(this, 'derived secret');
}
Derived.prototype.exposeSecret = function exposeSecret(){
return _(this).secret;
}
return Derived;
});
var Bob = new Derived('Bob', 'is dumb', 20);
Bob.logSecret();
console.log(Bob);
console.log(Bob.exposeSecret());
After some research I've concluded there is no more simple way to do this.