Shorthand for defining function in JavaScript object [duplicate] - javascript

This question already has answers here:
How does this object method definition work without the "function" keyword?
(2 answers)
Closed 6 years ago.
Accidentally I written a code like below,
var x = {hai:10,test(){ alert("I am alive")}};
x.test(); //alerting the value
It is working fine and I wonder how this code is working? since it was considered previously as an invalid grammar. And I know, In ECMAscript 6, there is a shorthand for assigning properties has been introduced.
Example:
var x = 5, y = {x}; // is as same as var x=5,y={x:x};
But I am not sure about the function definition. Can anyone explain about it with proof from documentation?

This is a Feature coming with ES2015. You can skip the function-keyword for method-definitions (not for plain functions).
So { doSth(){/*...*/ } } is simply a shorthand for { doSth: function(){/*...*/ } }
Reference: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Object_initializer#Method_definitions

MDN
Starting with ECMAScript 2015 (ES6), a shorter syntax for method
definitions on objects initializers is introduced. It is a shorthand
for a function assigned to the method's name.
Syntax
var obj = {
property( parameters… ) {},
*generator( parameters… ) {},
// also with computed keys:
[property]( parameters… ) {},
*[generator]( parameters… ) {},
// compare ES5 getter/setter syntax:
get property() {},
set property(value) {}
};
You are now able to shorten this to:
var obj = {
foo() {},
bar() {}
};
MDN Links to ECMA

Enhanced Object Literals
Object literals are extended to support setting the prototype at
construction, shorthand for foo: foo assignments, defining methods,
making super calls, and computing property names with expressions.
Together, these also bring object literals and class declarations
closer together, and let object-based design benefit from some of the
same conveniences.
var obj = {
// __proto__
__proto__: theProtoObj,
// Shorthand for ‘handler: handler’
handler,
// Methods
toString() {
// Super calls
return "d " + super.toString();
},
// Computed (dynamic) property names
[ 'prop_' + (() => 42)() ]: 42
};
Reference : https://github.com/lukehoban/es6features#enhanced-object-literals

Related

Console.log function property difference between object literal vs. dot notation [duplicate]

This question already has an answer here:
Definition of name property in assignment expression
(1 answer)
Closed 1 year ago.
I create objects using two different notations and then console.log them:
object = {key: 'value', func: function() {}};
console.log(object);
output: { key: 'value', func: [Function: func] }
object.key = 'value';
object.func = function() {};
console.log(object);
output: { key: 'value', func: [Function] }
Why there's a difference in the outputs? Does it matter?
This has nothing to do with dot notation and bracket notation.
In example (a) you are declaring a property name (func) and value (a function) in an object literal. In example (b) you are assigning a function to a property afterwards.
In the first case, func is used as a Binding Identifier which is used to give the function a name.
That isn't the case in the second example.
This isn't likely to make much difference, but function names can be useful when debugging. You can give a function expression a name explicitly:
object.func = function func () {};

Why put an object key in square brackets (not destructuring)? [duplicate]

This question already has answers here:
What do square brackets around a property name in an object literal mean?
(2 answers)
Closed 7 years ago.
Look at the example here:
https://github.com/rackt/redux/blob/master/examples/real-world/actions/index.js
return {
[CALL_API]: {
types: [ USER_REQUEST, USER_SUCCESS, USER_FAILURE ],
endpoint: `users/${login}`,
schema: Schemas.USER
}
}
CALL_API is in square brackets so I assumed maybe it was an array and this was a destructuring thing.
But CALL_API is defined as
export const CALL_API = Symbol('Call API')
So it's not an array or anything. I've also seen the use of square braces with non-symbols. So what's the difference between
CALL_API: {}
and
[CALL_API]: {}
This is a computed property - it's the equivalent of:
let result = {}
result[CALL_API] = { ... };
return result;
Combining this with Symbol lets the library author create a protocol that will not collide with other protocols (e. g. if the protocol was a string "call" then it could collide with other libraries that use someObject.call for their (unrelated) protocols - as well as colliding with Function.prototype.call.)
What this is doing is taking the value of the express [CALL_API] and using it as the key, thus setting the key dynamically.
Example:
var x = "hello";
var y = {
[x]: "world"
};
console.log(y); // Object {hello: "world"}
After some testing, I recommend being very careful with this. The following is perfectly valid:
var x = {"will": "this work?"};
var y = {[x]: "let's see"};
console.log(y); // Object {[object Object]: "let's see"}
console.log(y['[object Object]']); // "let's see"

Access internal Property Name to Compute New Property in ES6 [duplicate]

This question already has answers here:
Self-references in object literals / initializers
(30 answers)
Closed 7 years ago.
I have object. I want to add properties but I want to compute the suffix for all properties in my object during definition.
var myObject = {
foo: "bar",
[ "prop_" + "Access foo property: foo" ]: 42
};
Below is my expected output:
{
foo: "bar",
prop_bar: 42
}
It's not the case that i'm unable to achieve it. i can able to achieve by the below snippet and its working fine but i want this to be done during declaration.
let myObject = {
foo: "bar"
};
myObject[ "prop_" + myObject['foo'] ] = 'hello'
Note to Reviewers: I have already reviewed the below questions.
Is there a shorthand for this in ES6/ES7?
ES6 Object Literal Property Value Shorthand
How to use ES6 computed property names in node / iojs?
ES6 Computed (dynamic) property names
I feel that there will be better solution than above approach, below are my questions.
What is best approach for this scenario?
How many ways we can achieve this ?
Its not possible during declaration ?
You can create factory function to do this, e.g.:
const create = v => ({
foo: v,
["prop_" + v]: 42
});
let myObject = create("bar");
or inline:
let myObject = (v => ({
foo: v,
["prop_" + v]: 42
}))("bar");

What are __defineGetter__() and __defineSetter__() functions?

What are __defineGetter__() and __defineSetter__() functions in prototype of every Object?
See the MDN docs here for a description and example code:
A getter is a method that gets the value of a specific property. A setter is a method that sets the value of a specific property. You can define getters and setters on any predefined core object or user-defined object that supports the addition of new properties.
As noted in the docs (and by # cwallenpoole), __define[GS]etter__() functions are now deprecated. There's a lot more detail in this article. I believe the defineProperty() function is now the preferred syntax.
To answer your question __defineGetter__() and __defineSetter__() are the old/original way to create a getter and a setter for an object's property. They allow you use an object's property as a name/value pair while behind the scenes these name/value pairs are supported by functions.
For example, let's say you wanted to reference some random numbers in fixed ranges. You could express these as words with the maximum of the range and it would look like a property.
var random = {};
random.__defineGetter__('ten', function() {
return Math.floor(Math.random()*10); });
random.__defineGetter__('hundred', function() {
return Math.floor(Math.random()*100); });
Note that the while the above example answers the question you should not use this solution. Instead you should use the modern form of getters and setters since ES5:
var random = {
get ten() { return Math.floor(Math.random()*10); },
get hundred() { return Math.floor(Math.random()*100); }
};
Either of the above constructs would allow you to get a random number like this:
var myrand = random.ten;
// returns a result in the range 0 to 9
.__defineGetter__ it means when you refer to object.[param1] a function is executed.
.__defineSetter__ it means when you set object.[param1] a function is executed.
for example, like this:
const person = {
firstName: 'john',
lastName: 'doe',
};
person.__defineGetter__('fullName', () => `${person.firstName} ${person.lastName}`);
person.__defineSetter__('fullName', v => {
person.firstName = v.split(' ')[0];
person.lastName = v.split(' ')[1];
});
or if you want cls to clear the console,
this.__defineGetter__('cls', console.clear);

How to display all methods of an object?

I want to know how to list all methods available for an object like for example:
alert(show_all_methods(Math));
This should print:
abs, acos, asin, atan, atan2, ceil, cos, exp, floor, log, max, min, pow, random,round, sin, sqrt, tan, …
You can use Object.getOwnPropertyNames() to get all properties that belong to an object, whether enumerable or not. For example:
console.log(Object.getOwnPropertyNames(Math));
//-> ["E", "LN10", "LN2", "LOG2E", "LOG10E", "PI", ...etc ]
You can then use filter() to obtain only the methods:
console.log(Object.getOwnPropertyNames(Math).filter(function (p) {
return typeof Math[p] === 'function';
}));
//-> ["random", "abs", "acos", "asin", "atan", "ceil", "cos", "exp", ...etc ]
In ES3 browsers (IE 8 and lower), the properties of built-in objects aren't enumerable. Objects like window and document aren't built-in, they're defined by the browser and most likely enumerable by design.
From ECMA-262 Edition 3:
Global Object
There is a unique global
object (15.1), which is created before
control enters any execution context.
Initially the global object has the
following properties:
• Built-in
objects such as Math, String, Date,
parseInt, etc. These have attributes {
DontEnum }.
• Additional host defined
properties. This may include a
property whose value is the global
object itself; for example, in the
HTML document object model the window
property of the global object is the
global object itself.
As control
enters execution contexts, and as
ECMAScript code is executed,
additional properties may be added to
the global object and the initial
properties may be changed.
I should point out that this means those objects aren't enumerable properties of the Global object. If you look through the rest of the specification document, you will see most of the built-in properties and methods of these objects have the { DontEnum } attribute set on them.
Update: a fellow SO user, CMS, brought an IE bug regarding { DontEnum } to my attention.
Instead of checking the DontEnum attribute, [Microsoft] JScript will skip over any property in any object where there is a same-named property in the object's prototype chain that has the attribute DontEnum.
In short, beware when naming your object properties. If there is a built-in prototype property or method with the same name then IE will skip over it when using a for...in loop.
It's not possible with ES3 as the properties have an internal DontEnum attribute which prevents us from enumerating these properties. ES5, on the other hand, provides property descriptors for controlling the enumeration capabilities of properties so user-defined and native properties can use the same interface and enjoy the same capabilities, which includes being able to see non-enumerable properties programmatically.
The getOwnPropertyNames function can be used to enumerate over all properties of the passed in object, including those that are non-enumerable. Then a simple typeof check can be employed to filter out non-functions. Unfortunately, Chrome is the only browser that it works on currently.
​function getAllMethods(object) {
return Object.getOwnPropertyNames(object).filter(function(property) {
return typeof object[property] == 'function';
});
}
console.log(getAllMethods(Math));
logs ["cos", "pow", "log", "tan", "sqrt", "ceil", "asin", "abs", "max", "exp", "atan2", "random", "round", "floor", "acos", "atan", "min", "sin"] in no particular order.
var methods = [];
for (var m in obj) {
if (typeof obj[m] == "function") {
methods.push(m);
}
}
alert(methods.join(","));
This way, you will get all methods that you can call on obj. This includes the methods that it "inherits" from its prototype (like getMethods() in java). If you only want to see those methods defined directly by obj you can check with hasOwnProperty:
var methods = [];
for (var m in obj) {
if (typeof obj[m] == "function" && obj.hasOwnProperty(m)) {
methods.push(m);
}
}
alert(methods.join(","));
Most modern browser support console.dir(obj), which will return all the properties of an object that it inherited through its constructor. See Mozilla's documentation for more info and current browser support.
console.dir(Math)
=> MathConstructor
E: 2.718281828459045
LN2: 0.6931471805599453
...
tan: function tan() { [native code] }
__proto__: Object
The other answers here work for something like Math, which is a static object. But they don't work for an instance of an object, such as a date. I found the following to work:
function getMethods(o) {
return Object.getOwnPropertyNames(Object.getPrototypeOf(o))
.filter(m => 'function' === typeof o[m])
}
//example: getMethods(new Date()): [ 'getFullYear', 'setMonth', ... ]
https://jsfiddle.net/3xrsead0/
This won't work for something like the original question (Math), so pick your solution based on your needs. I'm posting this here because Google sent me to this question but I was wanting to know how to do this for instances of objects.
Approach that works nicely with ES6 classes and inheritance
This is likely what most newbie ES6 users like me mean when they are looking for "how to list object methods".
This has been adapted from: https://stackoverflow.com/a/47714550/895245
// Define getMethods.
const isGetter = (x, name) => (Object.getOwnPropertyDescriptor(x, name) || {}).get
const isFunction = (x, name) => typeof x[name] === "function";
const deepFunctions = x =>
x && x !== Object.prototype &&
Object.getOwnPropertyNames(x)
.filter(name => isGetter(x, name) || isFunction(x, name))
.concat(deepFunctions(Object.getPrototypeOf(x)) || []);
const distinctDeepFunctions = x => Array.from(new Set(deepFunctions(x)));
const getMethods = (obj) => distinctDeepFunctions(obj).filter(
name => name !== "constructor" && !~name.indexOf("__"));
// Example usage.
class BaseClass {
override() { }
baseMethod() { }
}
class DerivedClass extends BaseClass {
override() { }
get myGetter() { }
static myStatic() { }
}
const obj = new DerivedClass();
const methods = getMethods(obj)
methods.sort()
const assert = require('assert')
assert(methods[0] === 'baseMethod')
assert(methods[1] === 'myGetter')
assert(methods[2] === 'override')
console.log(getMethods(Math))
Note how it also includes methods of base classes as most users will want to see which methods they can call on the object.
It also appears to work with Math, it output:
[
'abs', 'acos', 'acosh', 'asin',
'asinh', 'atan', 'atanh', 'atan2',
'ceil', 'cbrt', 'expm1', 'clz32',
'cos', 'cosh', 'exp', 'floor',
'fround', 'hypot', 'imul', 'log',
'log1p', 'log2', 'log10', 'max',
'min', 'pow', 'random', 'round',
'sign', 'sin', 'sinh', 'sqrt',
'tan', 'tanh', 'trunc'
]
Tested on Node.js 14.17.0.
Math has static method where you can call directly like Math.abs() while Date has static method like Date.now() and also instance method where you need to create new instance first var time = new Date() to call time.getHours().
// The instance method of Date can be found on `Date.prototype` so you can just call:
var keys = Object.getOwnPropertyNames(Date.prototype);
// And for the static method
var keys = Object.getOwnPropertyNames(Date);
// But if the instance already created you need to
// pass its constructor
var time = new Date();
var staticKeys = Object.getOwnPropertyNames(time.constructor);
var instanceKeys = Object.getOwnPropertyNames(time.constructor.prototype);
Of course you will need to filter the obtained keys for the static method to get actual method names, because you can also get length, name that aren't a function on the list.
But how if we want to obtain all available method from class that extend another class?
Of course you will need to scan through the root of prototype like using __proto__. For saving your time you can use script below to get static method and deep method instance.
// var keys = new Set();
function getStaticMethods(keys, clas){
var keys2 = Object.getOwnPropertyNames(clas);
for(var i = 0; i < keys2.length; i++){
if(clas[keys2[i]].constructor === Function)
keys.add(keys2[i]);
}
}
function getPrototypeMethods(keys, clas){
if(clas.prototype === void 0)
return;
var keys2 = Object.getOwnPropertyNames(clas.prototype);
for (var i = keys2.length - 1; i >= 0; i--) {
if(keys2[i] !== 'constructor')
keys.add(keys2[i]);
}
var deep = Object.getPrototypeOf(clas);
if(deep.prototype !== void 0)
getPrototypeMethods(keys, deep);
}
// ====== Usage example ======
// To avoid duplicate on deeper prototype we use `Set`
var keys = new Set();
getStaticMethods(keys, Date);
getPrototypeMethods(keys, Date);
console.log(Array.from(keys));
If you want to obtain methods from created instance, don't forget to pass the constructor of it.
The short answer is you can't because Math and Date (off the top of my head, I'm sure there are others) are't normal objects. To see this, create a simple test script:
<html>
<body>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.1/jquery.min.js"></script>
<script type="text/javascript">
$(function() {
alert("Math: " + Math);
alert("Math: " + Math.sqrt);
alert("Date: " + Date);
alert("Array: " + Array);
alert("jQuery: " + jQuery);
alert("Document: " + document);
alert("Document: " + document.ready);
});
</script>
</body>
</html>
You see it presents as an object the same ways document does overall, but when you actually try and see in that object, you see that it's native code and something not exposed the same way for enumeration.
I believe there's a simple historical reason why you can't enumerate
over methods of built-in objects like Array for instance. Here's why:
Methods are properties of the prototype-object, say Object.prototype.
That means that all Object-instances will inherit those methods. That's
why you can use those methods on any object. Say .toString() for instance.
So IF methods were enumerable, and I would iterate over say {a:123}
with: "for (key in {a:123}) {...}" what would happen? How many times
would that loop be executed?
It would be iterated once for the single key 'a' in our example. BUT ALSO
once for every enumerable property of Object.prototype. So if
methods were enumerable (by default), then any loop over any object would loop
over all its inherited methods as well.
Inspired by the other answers, here's a recursive way of finding all methods:
// Find all methods of an object, up to the root prototype
function findAllMethods(obj, methods = []) {
if (!obj) {
return [...new Set(methods)];
}
const props = Object.getOwnPropertyNames(obj);
return findAllMethods(Object.getPrototypeOf(obj), [
...methods,
...props.filter(prop => typeof obj[prop] === 'function'),
]);
}
If you want all methods including inherited ones:
function getMethods(obj) {
const methods = [];
do {
for (const prop of Object.getOwnPropertyNames(obj)) {
if (obj[prop] instanceof Function) methods.push(prop);
}
obj = Object.getPrototypeOf(obj);
} while (obj !== null)
return methods;
}
console.log(getMethods(Math));

Categories

Resources