Currently i started working with JS ECMA6 for my personal web app,
but I am not sure about usage of Symbols
i.e. how can I make use of it?
I believe, they are tokens that serve as unique IDs. But I am not sure about its usage in web app development.
I am currently new to this standard, please provide your suggestions on it.
Symbols enable access control for object state. Symbols allow properties to be keyed by either string (as in ES5) or symbol. Symbols are a new primitive type. Optional description parameter used in debugging - but is not part of identity. Symbols are unique (like gensym), but not private since they are exposed via reflection features like Object.getOwnPropertySymbols.
var MyClass = (function() {
// module scoped symbol
var key = Symbol("key");
function MyClass(privateData) {
this[key] = privateData;
}
MyClass.prototype = {
doStuff: function() {
... this[key] ...
}
};
return MyClass;
})();
var c = new MyClass("hello")
c["key"] === undefined
It can be referred here.
Here are few more links with nicely explained examples.(As already mentioned in comments section.)
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol
http://www.2ality.com/2014/12/es6-symbols.html
Related
In Ruby I think you can call a method that hasn't been defined and yet capture the name of the method called and do processing of this method at runtime.
Can Javascript do the same kind of thing ?
method_missing does not fit well with JavaScript for the same reason it does not exist in Python: in both languages, methods are just attributes that happen to be functions; and objects often have public attributes that are not callable. Contrast with Ruby, where the public interface of an object is 100% methods.
What is needed in JavaScript is a hook to catch access to missing attributes, whether they are methods or not. Python has it: see the __getattr__ special method.
The __noSuchMethod__ proposal by Mozilla introduced yet another inconsistency in a language riddled with them.
The way forward for JavaScript is the Proxy mechanism (also in ECMAscript Harmony), which is closer to the Python protocol for customizing attribute access than to Ruby's method_missing.
The ruby feature that you are explaining is called "method_missing" http://rubylearning.com/satishtalim/ruby_method_missing.htm.
It's a brand new feature that is present only in some browsers like Firefox (in the spider monkey Javascript engine). In SpiderMonkey it's called "__noSuchMethod__" https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Object/NoSuchMethod
Please read this article from Yehuda Katz http://yehudakatz.com/2008/08/18/method_missing-in-javascript/ for more details about the upcoming implementation.
Not at the moment, no. There is a proposal for ECMAScript Harmony, called proxies, which implements a similar (actually, much more powerful) feature, but ECMAScript Harmony isn't out yet and probably won't be for a couple of years.
You can use the Proxy class.
var myObj = {
someAttr: 'foo'
};
var p = new Proxy(myObj, {
get: function (target, methodOrAttributeName) {
// target is the first argument passed into new Proxy, aka. target is myObj
// First give the target a chance to handle it
if (Object.keys(target).indexOf(methodOrAttributeName) !== -1) {
return target[methodOrAttributeName];
}
// If the target did not have the method/attribute return whatever we want
// Explicitly handle certain cases
if (methodOrAttributeName === 'specialPants') {
return 'trousers';
}
// return our generic method_missing function
return function () {
// Use the special "arguments" object to access a variable number arguments
return 'For show, myObj.someAttr="' + target.someAttr + '" and "'
+ methodOrAttributeName + '" called with: ['
+ Array.prototype.slice.call(arguments).join(',') + ']';
}
}
});
console.log(p.specialPants);
// outputs: trousers
console.log(p.unknownMethod('hi', 'bye', 'ok'));
// outputs:
// For show, myObj.someAttr="foo" and "unknownMethod" called with: [hi,bye,ok]
About
You would use p in place of myObj.
You should be careful with get because it intercepts all attribute requests of p. So, p.specialPants() would result in an error because specialPants returns a string and not a function.
What's really going on with unknownMethod is equivalent to the following:
var unk = p.unkownMethod;
unk('hi', 'bye', 'ok');
This works because functions are objects in javascript.
Bonus
If you know the number of arguments you expect, you can declare them as normal in the returned function.
eg:
...
get: function (target, name) {
return function(expectedArg1, expectedArg2) {
...
I've created a library for javascript that let you use method_missing in javascript: https://github.com/ramadis/unmiss
It uses ES6 Proxies to work. Here is an example using ES6 Class inheritance. However you can also use decorators to achieve the same results.
import { MethodMissingClass } from 'unmiss'
class Example extends MethodMissingClass {
methodMissing(name, ...args) {
console.log(`Method ${name} was called with arguments: ${args.join(' ')}`);
}
}
const instance = new Example;
instance.what('is', 'this');
> Method what was called with arguments: is this
No, there is no metaprogramming capability in javascript directly analogous to ruby's method_missing hook. The interpreter simply raises an Error which the calling code can catch but cannot be detected by the object being accessed. There are some answers here about defining functions at run time, but that's not the same thing. You can do lots of metaprogramming, changing specific instances of objects, defining functions, doing functional things like memoizing and decorators. But there's no dynamic metaprogramming of missing functions as there is in ruby or python.
I came to this question because I was looking for a way to fall through to another object if the method wasn't present on the first object. It's not quite as flexible as what your asking - for instance if a method is missing from both then it will fail.
I was thinking of doing this for a little library I've got that helps configure extjs objects in a way that also makes them more testable. I had seperate calls to actually get hold of the objects for interaction and thought this might be a nice way of sticking those calls together by effectively returning an augmented type
I can think of two ways of doing this:
Prototypes
You can do this using prototypes - as stuff falls through to the prototype if it isn't on the actual object. It seems like this wouldn't work if the set of functions you want drop through to use the this keyword - obviously your object wont know or care about stuff that the other one knows about.
If its all your own code and you aren't using this and constructors ... which is a good idea for lots of reasons then you can do it like this:
var makeHorse = function () {
var neigh = "neigh";
return {
doTheNoise: function () {
return neigh + " is all im saying"
},
setNeigh: function (newNoise) {
neigh = newNoise;
}
}
};
var createSomething = function (fallThrough) {
var constructor = function () {};
constructor.prototype = fallThrough;
var instance = new constructor();
instance.someMethod = function () {
console.log("aaaaa");
};
instance.callTheOther = function () {
var theNoise = instance.doTheNoise();
console.log(theNoise);
};
return instance;
};
var firstHorse = makeHorse();
var secondHorse = makeHorse();
secondHorse.setNeigh("mooo");
var firstWrapper = createSomething(firstHorse);
var secondWrapper = createSomething(secondHorse);
var nothingWrapper = createSomething();
firstWrapper.someMethod();
firstWrapper.callTheOther();
console.log(firstWrapper.doTheNoise());
secondWrapper.someMethod();
secondWrapper.callTheOther();
console.log(secondWrapper.doTheNoise());
nothingWrapper.someMethod();
//this call fails as we dont have this method on the fall through object (which is undefined)
console.log(nothingWrapper.doTheNoise());
This doesn't work for my use case as the extjs guys have not only mistakenly used 'this' they've also built a whole crazy classical inheritance type system on the principal of using prototypes and 'this'.
This is actually the first time I've used prototypes/constructors and I was slightly baffled that you can't just set the prototype - you also have to use a constructor. There is a magic field in objects (at least in firefox) call __proto which is basically the real prototype. it seems the actual prototype field is only used at construction time... how confusing!
Copying methods
This method is probably more expensive but seems more elegant to me and will also work on code that is using this (eg so you can use it to wrap library objects). It will also work on stuff written using the functional/closure style aswell - I've just illustrated it with this/constructors to show it works with stuff like that.
Here's the mods:
//this is now a constructor
var MakeHorse = function () {
this.neigh = "neigh";
};
MakeHorse.prototype.doTheNoise = function () {
return this.neigh + " is all im saying"
};
MakeHorse.prototype.setNeigh = function (newNoise) {
this.neigh = newNoise;
};
var createSomething = function (fallThrough) {
var instance = {
someMethod : function () {
console.log("aaaaa");
},
callTheOther : function () {
//note this has had to change to directly call the fallThrough object
var theNoise = fallThrough.doTheNoise();
console.log(theNoise);
}
};
//copy stuff over but not if it already exists
for (var propertyName in fallThrough)
if (!instance.hasOwnProperty(propertyName))
instance[propertyName] = fallThrough[propertyName];
return instance;
};
var firstHorse = new MakeHorse();
var secondHorse = new MakeHorse();
secondHorse.setNeigh("mooo");
var firstWrapper = createSomething(firstHorse);
var secondWrapper = createSomething(secondHorse);
var nothingWrapper = createSomething();
firstWrapper.someMethod();
firstWrapper.callTheOther();
console.log(firstWrapper.doTheNoise());
secondWrapper.someMethod();
secondWrapper.callTheOther();
console.log(secondWrapper.doTheNoise());
nothingWrapper.someMethod();
//this call fails as we dont have this method on the fall through object (which is undefined)
console.log(nothingWrapper.doTheNoise());
I was actually anticipating having to use bind in there somewhere but it appears not to be necessary.
Not to my knowledge, but you can simulate it by initializing the function to null at first and then replacing the implementation later.
var foo = null;
var bar = function() { alert(foo()); } // Appear to use foo before definition
// ...
foo = function() { return "ABC"; } /* Define the function */
bar(); /* Alert box pops up with "ABC" */
This trick is similar to a C# trick for implementing recursive lambdas, as described here.
The only downside is that if you do use foo before it's defined, you'll get an error for trying to call null as though it were a function, rather than a more descriptive error message. But you would expect to get some error message for using a function before it's defined.
I have been searching for discussions about how to specify a symbol as public or private in ECMAScript 6.
As I undertand it, a private symbol would be created using a pattern similar to the following:
var itemManager = (function() {
var items = new Symbol(/* possible string description? */);
return {
[items]: [ ],
getItems: function() {
return this[items].slice();
},
addItem: function(item) {
this[items].push(item);
}
};
})();
But how could I specify the items symbol as public? Will public symbols be possible in ES6, or will they only be private (not show up in Object.getOwnPropertyNames for example)? Additionally, will public symbols be enumerable by default (show up in Object.keys)?
Could anyone please link me to relevant information?
Neither non-private names and their semantics, nor the precise syntactic support for names in general is quite settled yet. So there is nothing to link you to just yet. The best you can get is digging for the relevant threads on es-discuss.
This question just got upvoted so can update question with what I did
I solved it by iterating over the window object (or user specified object root) and when I found the correct instance I backtracked and got the name from the index. The final solution can be found here
https://github.com/AndersMalmgren/Knockout.BindingConventions
Update end
I'm planning on writing a convention over configuration template source engine for KnockoutJS / MVC.
I'm started with a little client side POC and ran into a show stopper right away
My plan is use this syntax or something similar
MyApp.EditCustomersViewModel = function() {
ko.templates.loadView(this);
};
When doing this it will check the tamplate cache or fetch the templates from server using the object name as key.
The problem is I cant get the name of the prototype object, i tried this
Object.prototype.getName = function() {
var funcNameRegex = /function (.{1,})\(/;
var results = (funcNameRegex).exec((this).constructor.toString());
return (results && results.length > 1) ? results[1] : "";
};
If works for objects defined like this
function MyClass() {
}
If you add a prototype to the above object it will not work, or if you define it like this
MyApp = {};
MyApp.MyClass = function() {
};
Prototype and scoping is two musts so this is a showstopper, any ideas?
Fiddle: http://jsfiddle.net/aRWLA/
edit: The background for this is like this.
On the server you have structure like this
Templates\ [ViewName]\index.html
Templates\ [ViewName]\sub-model-template.html
on the client you will do
MyApp.EditCustomersViewModel = function() {
ko.templates.loadView(this);
};
which will generate a ajax request with the objects name as key, which will fetch all the templates for the view in question
Only hoisted functions (function someFunc() {) have a retrievable name.
Assigned functions do not, because you are not technically naming the function but creating an anonymous function and assigning a reference to it (in the memory) to a named variable.
So it's the var, not the function, that is named.
This makes the very idea of retrieving function names pretty much a none-starter, since in any vaguely mature pattern you'll be writing methods, not hoisted functions - and methods of course are assigned functions.
Named expressions (see other answers) are a partial workaround but these have other issues - not least lack of support in older IEs.
(Sidenote: I've long expected browser vendors to build around this such that the names of assigned functions became retrievable, but no joy yet AFAIK.)
I think you problem in improper replacing function prototype: if you replace function prototype object then you must preserve constructor member in prototype:
function Test1() {
}
Test1.prototype={
constructor: Test1
};
MyApp={};
MyApp.MyClass=function MyClass(){
};
MyApp.MyClass.prototype={
constructor: MyApp.MyClass
};
Your example: http://jsfiddle.net/aRWLA/1/
Modified example: http://jsfiddle.net/aRWLA/2/
You can make use of named function expressions:
MyApp.MyClass = function MyClass() { ... };
But note that (suprise) they don't work correctly in all versions of IE.
See: http://kangax.github.com/nfe/
THIS DOES NOT ANSWER THE QUESTION
However, the code might be useful to other people, so I'm leaving it here, just in case. I don't expect upvotes, but please don't abuse it for downvoting either. Thanks.
I don't know your use case, as such I think you've got a design issue - the problem you describe shouldn't happen in practice.
But let's say you do need to have this working. An easy way to do what you need would be something like:
function findNamed(obj, fn){
for(var p in obj)
if(obj[p] === fn)
return p;
return false;
}
var m = {};
m.MyClass = function() {};
console.log(findNamed(m, m.MyClass));
Of course, the solution could be made into a more appropriate OOP form, but this is just to give an idea.
To replicate your use case, it would look like:
m.MyClass = function() {
findNamed(this, arguments.callee);
};
So, the final code is:
Object.prototype.getNameOfCall = function(fn) {
for(var p in this)
if(this[p] === fn)
return p;
throw "Callback not in object.";
};
var m = {};
m.MyClass = function() {
console.log(this.getNameOfCall(arguments.callee)); // MyClass
};
m.MyClass(); // test it out
I'm making a google chrome extension and trying to get reference of a local variable within a closure scope.
// The script model of the target website
// I can't change any code of these
function Player(playerName){
this.name = playerName;
this.score = 0;
}
function Match(playerRed,playerBlue){
var player_red = new Player(playerRed);
var player_blue = new Player(playerBlue);
}
var tennis = new Match("Mike","John")
so what I'm trying to do in my content script is to inject a function into prototype of Match
just to get the variable player_red and player_blue:
function Match(playerRed,playerBlue){
var player_red = new Player(playerRed);
var player_blue = new Player(playerBlue);
//hoping to add this into Match.prototype
this.showMatchInfo = function(){
alert(player_red.name + " vs " + player_blue.name);
}
}
but this will not work because player_red and player_blue isn't defined under this.
I found this question through search. The solution is to "wrap the constructor in a new constructor and then set the prototypes equal". Unfortunately this doesn't work for me as I have no access to the original script of the website and probably because:
even by create new myMatch, the new myMatch doesn't not inherit the player_red and player_blue variable from their original Match instance.
Are there any possible workarounds? Thanks.
Notes on "partial solution":
Please note that the code snippets posted below only show "some alternatives which may or may not provide enough to get by". This is because they don't capture the values (Player objects) within the constructor, but only wrap the values going inside.
A "full solution" might also wrap the Player constructor and use a property or other mechanism to "remember" the objects created for different input values; alternatively, it could remember object creation order. This could then be used to wrap Match and then extract the created Players from the shared store after the Match constructor had run -- those details, however, are left as an exercise. The Player wrapping code can utilize the code presented below (assuming Player is a global/accessible property).
The exact request is not possible given the above context.
Variables (real variables, not properties) can only be accessed from the scope they are declared in or a nested scope as they are resolved through scope chains. This also includes usage of eval. While this may seem like a limitation, it also ensures that scope chains (and their variables) can't be externally mucked with unless exposed.
However, consider this fun approach, which utilizes the fact that an explicit object can be returned from a Constructor:
var oldMatch = Match
// note this form, else above would be pre-clobbered
Match = function Match (playerRed, playerBlue) {
var m = new oldMatch(playerRed, playerBlue)
// either "inject" method here, or save in object for later
m.myPlayerRed = playerRed
m.myPlayerBlue = playerBlue
return m
}
Of course, this will break things like new Match(...) instanceof Match.
Happy coding.
Update:
Here is a modification of the above to work with the "wrap the constructor in a new constructor and then set the prototypes equal" method as discussed in the link in the post. The trick is "stealing" the global properties name. I have also altered the code to keep oldMatch "private" to avoid pollution.
// note this form, else Match property would be pre-clobbered
Match = (function (oldMatch) {
function Match (playerRed, playerBlue) {
oldMatch.call(this, playerRed, playerBlue);
// either "inject" method here, or save in object for later
this.myPlayerRed = playerRed
this.myPlayerBlue = playerBlue
}
Match.prototype = oldMatch.prototype
return Match
})(Match)
Unlike the first code snippet, this should work with new Match(...) instanceof Match, but it may still break depending upon particular assumptions made within the Match object methods.
Example of how to invert ("extract") data from Player constructor:
// original -- remember this method will only work
// if Player is used as a property (and not itself a closure'd variable)
function Player (name) {
this.name = name
}
Player = (function (oldPlayer) {
function Player (name) {
oldPlayer.call(this, name)
var fn = arguments.callee
fn.recent = fn.recent || []
fn.recent.push([name, this])
}
Player.prototype = oldPlayer.prototype
return Player
})(Player)
var p1 = new Player("fred");
var p2 = new Player("barney");
alert("instanceof check? " + p1 instanceof Player)
alert("name check? " + ("barney" == p2.name))
alert(Player.recent.join(","))
Player.recent = [] // reset
This question already has answers here:
Are there constants in JavaScript?
(33 answers)
Closed 6 years ago.
I want to declare string constants in JavaScript.
Is there is a way to do that?
Many browsers' implementations (and Node) have constants, used with const.
const SOME_VALUE = "Your string";
This const means that you can't reassign it to any other value.
Check the compatibility notes to see if your targeted browsers are supported.
Alternatively, you could also modify the first example, using defineProperty() or its friends and make the writable property false. This will mean the variable's contents can not be changed, like a constant.
Are you using JQuery? Do you want to use the constants in multiple javascript files? Then read on. (This is my answer for a related JQuery question)
There is a handy jQuery method called 'getScript'. Make sure you use the same relative path that you would if accessing the file from your html/jsp/etc files (i.e. the path is NOT relative to where you place the getScript method, but instead relative to your domain path). For example, for an app at localhost:8080/myDomain:
$(document).ready(function() {
$.getScript('/myDomain/myScriptsDir/constants.js');
...
then, if you have this in a file called constants.js:
var jsEnum = { //not really an enum, just an object that serves a similar purpose
FOO : "foofoo",
BAR : "barbar",
}
You can now print out 'foofoo' with
jsEnum.FOO
There's no constants in JavaScript, but to declare a literal all you have to do is:
var myString = "Hello World";
I'm not sure what you mean by store them in a resource file; that's not a JavaScript concept.
Of course, this wasn't an option when the OP submitted the question, but ECMAScript 6 now also allows for constants by way of the "const" keyword:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/const
You can see ECMAScript 6 adoption here.
Standard freeze function of built-in Object can be used to freeze an object containing constants.
var obj = {
constant_1 : 'value_1'
};
Object.freeze(obj);
obj.constant_1 = 'value_2'; //Silently does nothing
obj.constant_2 = 'value_3'; //Silently does nothing
In strict mode, setting values on immutable object throws TypeError. For more details, see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/freeze
Well, you can do it like so:
(function() {
var localByaka;
Object.defineProperty(window, 'Byaka', {
get: function() {
return localByaka;
},
set: function(val) {
localByaka = window.Byaka || val;
}
});
}());
window.Byaka = "foo"; //set constant
window.Byaka = "bar"; // try resetting it for shits and giggles
window.Byaka; // will allways return foo!
If you do this as above in global scope this will be a true constant, because you cannot overwrite the window object.
I've created a library to create constants and immutable objects in javascript. Its still version 0.2 but it does the trick nicely. http://beckafly.github.io/insulatejs
Starting ECMAScript 2015 (a.k.a ES6), you can use const
const constantString = 'Hello';
But not all browsers/servers support this yet. In order to support this, use a polyfill library like Babel.
So many ways to skin this cat. You can do this in a closure. This code will give you a read-only , namespaced way to have constants. Just declare them in the Public area.
//Namespaced Constants
var MyAppName;
//MyAppName Namespace
(function (MyAppName) {
//MyAppName.Constants Namespace
(function (Constants) {
//Private
function createConstant(name, val) {
Object.defineProperty(MyAppName.Constants, name, {
value: val,
writable: false
});
}
//Public
Constants.FOO = createConstant("FOO", 1);
Constants.FOO2 = createConstant("FOO2", 1);
MyAppName.Constants = Constants;
})(MyAppName.Constants || (MyAppName.Constants = {}));
})(MyAppName || (MyAppName = {}));
Usage:
console.log(MyAppName.Constants.FOO); //prints 1
MyAppName.Constants.FOO = 2;
console.log(MyAppName.Constants.FOO); //does not change - still prints 1
You can use freeze method of Object to create a constant. For example:
var configObj ={timeOut :36000};
Object.freeze(configObj);
In this way you can not alter the configObj.
Use global namespace or global object like Constants.
var Constants = {};
And using defineObject write function which will add all properties to that object and assign value to it.
function createConstant (prop, value) {
Object.defineProperty(Constants , prop, {
value: value,
writable: false
});
};
Just declare variable outside of scope of any js function. Such variables will be global.