ES6 classes : what about instrospection?
Only if the constructor function was a global, which is poor practice.In ES5, we could wheck the existence of a class on the window object
Correct. (The same is true ofIn ES6, according to this article, globally-declared classes are globals, but not properties of the global object...
let
and const
declarations at global scope.) This is defined in §8.1.1.4: Global Environment Records:(My emphasis) So the things that used to go on the global object in ES5 and earlier still do (plus generators, because it would have been even more confusing if they didn't), but the new things (A global Environment Record is logically a single record but it is specified as a composite encapsulating an object Environment Record and a declarative Environment Record. The object Environment Record has as its base object the global object of the associated Realm. This global object is the value returned by the global Environment Record’s GetThisBinding concrete method. (E.g., the global object referenced by
window
on browsers — T.J.) The object Environment Record component of a global Environment Record contains the bindings for all built-in globals (clause 18) and all bindings introduced by a FunctionDeclaration, GeneratorDeclaration, or VariableStatement contained in global code. The bindings for all other ECMAScript declarations in global code are contained in the declarative Environment Record component of the global Environment Record.
let
, const
, and class
declarations) don't. They're globals, but not properties of the global object.Back to your question...
You could useSo if I can't use
if (window.MyClass)
, is there a way to do the same?
if (typeof MyClass === "function") {
...since typeof
on an unresolvable symbol doesn't throw a ReferenceError
. This also has the advantage of checking whether MyClass
is in scope for the code, even if it's not global.There's a gotcha there though: If that code is in the same scope where MyClass
is declared via class
(or let
or const
) but it's above MyClass
in that scope, even the typeof
check will throw a ReferenceError
, because you can't access the binding it creates at all (not even with typeof
) before the class
(or let
or const
).
E.g., this will throw:
if (typeof MyClass === "function") { // ReferenceError here
// Yup, it's defined
// ...
}
// ...
class MyClass {
}
The space from the beginning of the scope to the class
, let
, or const
line is called the temporal dead zone (TDZ) and you can't access the variable binding at all. Consequently, you have to catch the ReferenceError
:let exists = false;
try {
exists = typeof MyClass === "function";
} catch (e) {
}
Until JavaScript modules make it to broad browser support, there are a couple of ways:Actually is there a proper way to do this without using window object ?
Use an Asynchronous Module Definition library of some kind to handle loading your modules. Some examples: RequireJS, SystemJS, CommonJS
Have a single global variable that you'll use to refer to an object, and make your various application globals properties of that object. Here's a typical way to do that:
var MyApp = MyApp || {};
if (!MyApp.ThisModule) { // You can leave this `if` out
// if there's no chance of the file
// being loaded more than once
MyApp.ThisModule = function(module) {
module.MyClass = class MyClass {
// ...class definition here...
}
}({});
}
What is concept of reflection in JavaScript?
reflection is a part of metaprogramming.
so concept of reflection is that, just like we see our reflection in the mirror: we can see things we couldnt see without it, such as: our hair, our lips, tongue, etc.Metaprogramming is a programming technique in which computer programs have the ability to treat programs as their data. It means that a program can be designed to read, generate, analyse or transform other programs, and even modify itself while running.
in short, if a method or a class call this reflection stuff, it can see objects outside its knowledge, such as: instance variables, list of methods the class has, and other properties, what class called this method.
this is useful when we do metaprogramming. as method or class should be aware of things outside their (or even writer's) knowledge.
concrete example:
lets say water and a cup. if you want to program water physics to fit cup, there are many ways. lets say you work with 100 other developers and have no idea what kind of container they would come up with (and someone might end up with a lake or even river) and you choose metaprogramming style. you have class water, and class cup. your water class has to be aware of properties of cup such as: max volume, weight, curves, or even max/min temperature.
result: you wont have to insert those informations as parameters whenever someone call class water as it might be difficult to track if they are growing in number.
(im not sure if that is a good enough example and explanation, so please comment a better one if it happen to cross your mind)
Have private properties & methods in ES6 classes
Correct. TheIt seems like classes in ES6 doesn't explicitly provide anything to have private data or methods.
class
syntax is for normal classes with prototype methods. If you want private variables, you put them in the constructor as always:class Deferred {
constructor() {
// initialise private data
var isPending = true;
var handlers = {
resolve: [],
reject: [],
notify: []
};
// Private method
function trigger(event, params) {
...
}
// initialise public properties
this.promise = new Promise(this);
// and create privileged methods
this.resolve = trigger.bind(null, 'resolve');
this.reject = trigger.bind(null, 'reject');
this.notify = trigger.bind(null, 'notify');
this.on = function(event, handler) {
…
};
}
}
Get the class name of ES6 class instance
someClassInstance.constructor.name
is exactly the correct way to do this. Transpilers may not support this, but it is the standard way per the specification. (The name
property of functions declared via ClassDeclaration productions is set in 14.5.15, step 6.)
Get functions (methods) of a class
This function will get all functions. Inherited or not, enumerable or not. All functions are included.
function getAllFuncs(toCheck) {
const props = [];
let obj = toCheck;
do {
props.push(...Object.getOwnPropertyNames(obj));
} while (obj = Object.getPrototypeOf(obj));
return props.sort().filter((e, i, arr) => {
if (e!=arr[i+1] && typeof toCheck[e] == 'function') return true;
});
}
Do testgetAllFuncs([1,3]);
console output:
["constructor", "toString", "toLocaleString", "join", "pop", "push", "concat", "reverse", "shift", "unshift", "slice", "splice", "sort", "filter", "forEach", "some", "every", "map", "indexOf", "lastIndexOf", "reduce", "reduceRight", "entries", "keys", "constructor", "toString", "toLocaleString", "valueOf", "hasOwnProperty", "isPrototypeOf", "propertyIsEnumerable", "__defineGetter__", "__lookupGetter__", "__defineSetter__", "__lookupSetter__"]
NoteIt doesn't return functions defined via symbols;
Create instance of Class Using Reflection in JavaScript
JavaScript doesn't have classes. But if by "class" you mean you have a constructor function:
function MyClassName() {
// do constructor things here
}
But the name of that function is in a variable:var someclass = "MyClassName";
Then you can instantiate an instance like this:var obj = new window[someclass]();
The above only works if MyClassName
is in the global scope. What does the Reflect object do in JavaScript?
UPDATE 2015:
As pointed out by 7th's answer, now that ES6 (ECMAScript 2015) has been finalized, more appropriate documentation is now available:
- ES6 spec, Reflection
- MDN Reflect (including details and examples to all of its methods)
**Original answer (for (historic) understanding and extra examples)**:The
Reflection proposal
seems to have progressed to the Draft ECMAScript 6 Specification. This document currently outlines the Reflect
-object's methods and only states the following about the Reflect
-object itself:The Reflect object is a single ordinary object.However, there is a short explanation about it's purpose in ES Harmony:
The value of the [[Prototype]] internal slot of the Reflect object is the standard built-in Object prototype object (19.1.3).
The Reflect object is not a function object. It does not have a [[Construct]] internal method; it is not possible to use the Reflect object as a constructor with the new operator. The Reflect object also does not have a [[Call]] internal method; it is not possible to invoke the Reflect object as a function.
The “@reflect” module serves multiple purposes:
- Now that we have modules, a “@reflect” module is a more natural place for many of the reflection methods previously defined on Object.
For backwards-compatibility purposes, it is unlikely that the static methods on Object will disappear. However, new methods should likely be added to the “@reflect” module rather than to the Object constructor.- A natural home for proxies, avoiding the need for a global Proxy binding.
- Most methods in this module map one-to-one onto Proxy traps. Proxy handlers need these methods to conveniently forward operations, as shown below.
So, the
Reflect
object provides a number of utility functions, many of which appear to overlap with ES5 methods defined on the global Object.However, that doesn't really explain what existing problems this intends to solve or what functionality is added. I suspected this could be shimmed and indeed, the above harmony-spec links to a 'non-normative, approximate implementation of these methods'.
Examining that code could give (further) idea's about it's use, but thankfully there is also a wiki that outlines a number of reasons why the Reflect object is useful:
(I've copied (and formatted) the following text for future reference from that source as they are the only examples I could find. Besides that, they make sense, already have a good explanation and touch the question's apply
example.)
More useful return values
Many operations in Reflect
are similar to ES5 operations defined on Object
, such as Reflect.getOwnPropertyDescriptor
and Reflect.defineProperty
. However, whereas Object.defineProperty(obj, name, desc)
will either return obj
when the property was successfully defined, or throw a TypeError
otherwise, Reflect.defineProperty(obj, name, desc)
is specced to simply return a boolean that indicates whether or not the property was successfully defined. This allows you to refactor this code:
try {
Object.defineProperty(obj, name, desc);
// property defined successfully
} catch (e) {
// possible failure (and might accidentally catch the wrong exception)
}
To this:if (Reflect.defineProperty(obj, name, desc)) {
// success
} else {
// failure
}
Other methods that return such a boolean success status are Reflect.set
(to update a property), Reflect.deleteProperty
(to delete a property), Reflect.preventExtensions
(to make an object non-extensible) and Reflect.setPrototypeOf
(to update an object's prototype link).
First-class operations
In ES5, the way to detect whether an object obj
defines or inherits a certain property name is to write (name in obj)
. Similarly, to delete a property, one uses delete obj[name]
. While dedicated syntax is nice and short, it also means you must explicitly wrap these operations in functions when you want to pass the operation around as a first-class value.
With Reflect
, these operations are readily defined as first-class functions:Reflect.has(obj, name)
is the functional equivalent of (name in obj)
and Reflect.deleteProperty(obj, name)
is a function that does the same as delete obj[name].
More reliable function application
In ES5, when one wants to call a function f
with a variable number of arguments packed as an array args
and binding the this
value to obj
, one can write:
f.apply(obj, args)
However, f
could be an object that intentionally or unintentionally defines its own apply
method. When you really want to make sure that the built-in apply
function is called, one typically writes:Function.prototype.apply.call(f, obj, args)
Not only is this verbose, it quickly becomes hard to understand. With Reflect
, you can now make a reliable function call in a shorter and easier to understand way:Reflect.apply(f, obj, args)
Variable-argument constructors
Imagine you want to call a constructor function with a variable number of arguments. In ES6, thanks to the new spread syntax, it will be possible to write code like:
var obj = new F(...args)
In ES5, this is harder to write, because one can only use F.apply
or F.call
to call a function with a variable number of arguments, but there is no F.construct
function to new
the function with a variable number of arguments. With Reflect
, one can now write, in ES5:var obj = Reflect.construct(F, args)
Default forwarding behavior for Proxy traps
When using Proxy
objects to wrap existing objects, it is very common to intercept an operation, do something, and then to "do the default thing", which is typically to apply the intercepted operation to the wrapped object. For example, say I want to simply log all property accesses to an object obj
:
var loggedObj = new Proxy(obj, {
get: function(target, name) {
console.log("get", target, name);
// now do the default thing
}
});
The Reflect
and Proxy
APIs were designed in tandem, such that for each Proxy
trap, there exists a corresponding method on Reflect
that "does the default thing". Hence, whenever you find yourself wanting to "do the default" thing inside a Proxy handler, the correct thing to do is to always call the corresponding method in the Reflect
object:var loggedObj = new Proxy(obj, {
get: function(target, name) {
console.log("get", target, name);
return Reflect.get(target, name);
}
});
The return type of the Reflect
methods is guaranteed to be compatible with the return type of the Proxy
traps.
Control the this-binding of accessors
In ES5 it's fairly easy to do a generic property access or property update. For instance:
var name = ... // get property name as a string
obj[name] // generic property lookup
obj[name] = value // generic property update
The Reflect.get
and Reflect.set
methods allow you to do the same thing, but additionally accept as a last optional argument a receiver
parameter that allows you to explicitly set the this
-binding when the property that you get/set is an accessor:var name = ... // get property name as a string
Reflect.get(obj, name, wrapper) // if obj[name] is an accessor, it gets run with `this === wrapper`
Reflect.set(obj, name, value, wrapper)
This is occasionally useful when you're wrapping obj
and you want any self-sends within the accessor to get re-routed to your wrapper, e.g. if obj
is defined as:var obj = {
get foo() { return this.bar(); },
bar: function() { ... }
}
Calling Reflect.get(obj, "foo", wrapper)
will cause the this.bar()
call to get rerouted to wrapper
.
Avoid legacy __proto__
On some browsers, __proto__
is defined as a special property that gives access to an object's prototype. ES5 standardized a new method Object.getPrototypeOf(obj)
to query the prototype. Reflect.getPrototypeOf(obj)
does exactly the same, except that Reflect
also defines a corresponding Reflect.setPrototypeOf(obj, newProto)
to set the object's prototype. This is the new ES6-compliant way of updating an object's prototype.
Note that: setPrototypeOf
also exists on Object
(as correctly pointed out by Knu's comment)!
EDIT:
Side-note (addressing comments to the Q): There is a short and simple answer on 'Q: ES6 Modules vs. HTML Imports' that explains
Realms
and Loader
objects.Another explanation is offered by this link:
A realm object abstracts the notion of a distinct global environment,Worth mentioning though:
with its own global object, copy of the standard library, and
"intrinsics" (standard objects that are not bound to global variables,
like the initial value of Object.prototype).Extensible web: This is the dynamic equivalent of a same-origin
<iframe>
without DOM.
ES6: If class has method?
I think you're looking for
build (methodnames) {
for (const methodname of methodnames) {
if (typeof this[methodname] == "function") {
this[methodname]();
}
}
}
There's nothing special about classes - and in fact you should ignore them. If you want to call some method, the only thing that is important is that there is a function as a property value. It doesn't matter whether the method is an own property of the prototype object of the class that created the instance. Can I use in Google Apps Scripts a defined Class in a library with ES6 (V8)?
As written in the official documentation,
Only the following properties in the script are available to library users:
This would mean every property in the global
- enumerable global properties
- function declarations,
- variables created outside a function with var, and
- properties explicitly set on the global object.
this
object are available to library users. Before ES6, All declarations outside a function (and function declaration themselves) were properties of this global object. After ES6, There are two kinds of global records:
Those in the declarative record are not accessible from the global "object", though they are globals themselves. Thus, the class declaration in the library is not accessible to library users. You could simply add a variable assignment to the class to add a property to the global object(outside any function):
Object record- Same as ES5.
- Function declarations
- Function generators
- Variable assignments
Declarative record - New
- Everything else -
let
,const
,class
var Update = class Update{/*your code here*/}
References:
- Library official documentation
- Global environment records
- Related Answers:
- ES6- What about introspection
- Do let statements create properties on the global object
Related Topics
Javascript: Dynamically Creating Variables for Loops
Do Websockets Allow for P2P (Browser to Browser) Communication
Difference Between Obtrusive and Unobtrusive JavaScript
In JavaScript, Can You Extend the Dom
Clear JavaScript Console in Google Chrome
How to Upload Preview Image Before Upload Through JavaScript
JavaScript String and Number Conversion
Set Window to Fullscreen (Real Fullscreen; F11 Functionality) by JavaScript
JavaScript Regular Expression to Check for Ip Addresses
C# Web Method Is Not Calling in JavaScript
Adding a Slide Effect to Bootstrap Dropdown
How Does Setinterval and Settimeout Work
JSON Transfer of Bigint: 12000000000002539 Is Converted to 12000000000002540
If (Key in Object) or If(Object.Hasownproperty(Key)
JavaScript Remove "Disabled" Attribute from HTML Input
What Exactly Can Cause an "Hierarchy_Request_Err: Dom Exception 3"-Error