This question already has answers here:
How does this object method definition work without the "function" keyword?
(2 answers)
Closed 6 years ago.
I'm curious about the following two methods of declaring functions within a variable in Javascript. What's the difference between the two function declarations below? Both seem to work. Are there any drawbacks to using one over the other? They seem to be constructed slightly differently when looking at the debugger.
In addition, I'm fairly certain the first method is called 'object literal notation'. Is there a formal name for the second method?
var myVar = {
testProperty: 'testProperty',
// Object literal notation?
testFunc: function()
{
console.log('testFunc called');
},
// What's this called? 'Named function declaration'?
testFunc2()
{
console.log('testFunc2 called');
}
}
// Both work...
myVar.testFunc();
myVar.testFunc2();
There are multiple ways to define properties (PropertyDefinition) in an object initializer (ObjectLiteral):
A "simple" PropertyDefinition
PropertyName[?Yield] : AssignmentExpression[In, ?Yield]
For example:
var obj = {a: 1};
obj.a; // 1
Method definitions
This includes getters and setters, added by ECMAScript 5
get PropertyName[?Yield] ( ) { FunctionBody }
set PropertyName[?Yield] ( PropertySetParameterList ) { FunctionBody }
For example:
var obj = {n: 0, get a() { return ++obj.n; }};
obj.a; // 1
obj.a; // 2
And also methods and generator methods, added by ECMAScript 6
PropertyName[?Yield] ( StrictFormalParameters ) { FunctionBody }
* PropertyName[?Yield] ( StrictFormalParameters[?Yield] ) { GeneratorBody }
For example:
var obj = {a(n) { return 2*n; }};
obj.a(1); // 2
obj.a(2); // 4
PropertyDefinition using computed property names, added by ECMAScript 6
[ AssignmentExpression[In, ?Yield] ] : AssignmentExpression[In, ?Yield]
For example:
var prop = "a",
obj = {[prop]: 1};
obj.a; // 1
"Shorthand" PropertyDefinition, added by ES6
IdentifierReference
For example:
var a = 1,
obj = {a};
obj.a; // 1
They have different syntax and provide different functionalities, but the result is always the creation of a property in the resulting object. In your case, a method definition is basically the same as a "simple" PropertyDefinition where the AssignmentExpression is a function expression. However, with the later you can specify a custom name to the function.
Also see
ECMAScript 5 - Object Initialiser
ECMAScript 6 - Object Initialiser
MDN - Object initializer
if you declare a function inside an object, that function is called the method of the object, but there are still called function, you should probably use the first method rather than using the second one
Related
This question already has answers here:
JavaScript object functions and `this` when unbound and returned in expression/parens
(2 answers)
How does the "this" keyword work, and when should it be used?
(22 answers)
Closed 4 years ago.
Here is an example where o.foo(); is 3 but (p.foo = o.foo)(); is 2?
function foo() {
console.log( this.a );
}
var a = 2;
var o = { a: 3, foo: foo };
var p = { a: 4 };
o.foo(); // 3
(p.foo = o.foo)(); // 2”
If I do something like this then I get 4 which is what I want. How are those 2 examples are different?
p.foo = o.foo;
p.foo(); // 4
This :
(p.foo = o.foo)();
Is pretty much the same as doing this:
d = (p.foo = o.foo);
d();
Basically what it says is that the return of an assignment is the function itself in the global context. On which a is 2.
actually your code is wrong because your snippet doesnt run, you should be doing the following: console.log( this.a );
and now, lets see how this works.
function foo() {
console.log( this.a );
}
this will call this in the scope of the caller, so lets investigate our results.
so, you are setting a=2 globally, and then in the objects o.a = 3 and p.a=4
so:
calling o.foo it will return 3 because this is pointing to o
calling p.foo it will return 4 because this is pointing to p
BUT
calling (p.foo = o.foo)(); it will return 2 because it is not pointing to any object, so it will take your scope (which is the global scope) and then it will return 2.
if you go with:
p.foo = o.foo
p.foo() //4
it will return 4 successfully because it is pointing to p.
Performing that assignment operation before the function call here:
(p.foo = o.foo)();
causes the object reference to p to be lost. If you instead wrote
p.foo = o.foo;
p.foo();
you'd get 4. As it is, you get 2 because the value of this will be window in the function.
Because that parenthesized subexpression is an assignment result, there's no object lookup directly associated with the result of the expression — the value of the assignment expression is just the function reference without a contextual object. Thus the runtime doesn't have a value to use for this when it calls the function, so this is bound by default to window (or the global object in whatever context).
I have encountered the following code online:
function bar() {
return {
x: 4,
y: 5,
z: 6
};
}
var which = "x",
o = {};
( { [which]: o[which] } = bar() );
console.log( o.x );
I understand that this code is an example of the "destructuring syntax" that was introduced in ES6.
I also understand that o[which] is searching for a key named which in object o and if found, return the value for the which key.
But I'm not really sure how the [which]: part of the expression works.
In destructuring syntax, when you see from : to, it means that the value of the property identified by from is taken from the thing being destructured and assigned to the variable or property identified by to. So looking at that line:
( { [which]: o[which] } = bar() );
...we see that the value of the property identified by [which] is retrieved from the object returned by bar and assigned to the property identified by o[which]. Since [which] is used rather than which, it's the value of the which variable that determines the name of the property taken from bar's returned object, just like when you use brackets syntax when retrieving or setting the value of a property on an object.
The non-destructuring version would look like this:
const tmp = bar();
o[which] = tmp[which];
The [which]: construct is part of computed properties syntax (ES2015+).
With ES6, I can create a new object with functions like the following:
var obj = {
something() {}
};
That makes sense. But I can also do this:
var obj = {
'something'() {}
};
Or I can do this:
var obj = {
['something']() {}
};
Is there a difference between these three syntaxes? Why are all of these syntactically valid?
Is there a difference between these three syntaxes?
Not wrt to the results in your example.
However, the different syntaxes do have different characteristics. The way the property name is defined is not specific to method definitions btw, the rules apply to all property names:
Property names that are valid identifier names or number literals don't need to be quoted:
{
foo: ...,
10e4: ...,
if: ...,
}
Anything else needs to be quoted:
{
'foo+bar': ...,
'abc def': ...,
'123,45': ...,
}
The square bracket syntax is new in ES6 and allows you do dynamically compute property names:
{
[getPropertyName()]: ...,
['item' + (i * 3)]: ...,
}
Why are all of these syntactically valid?
Because the grammar allows it:
MethodDefinition :
PropertyName ( StrictFormalParameters ) { FunctionBody }
GeneratorMethod
get PropertyName ( ) { FunctionBody }
set PropertyName( PropertySetParameterList ) { FunctionBody }
PropertyName :
LiteralPropertyName
ComputedPropertyName
LiteralPropertyName :
IdentifierName
StringLiteral
NumericLiteral
ComputedPropertyName :
[ AssignmentExpression ]
(not sure what kind of answer you expect here)
If you consider methods to be equivalent to assigning a function to the property, it seems to make sense to apply the same rules for property names to function/method names.
First and second are the same, and do the same as
obj.something = function something() {}
the third one creates an anonymous function and stores it in obj.something. It's an equivalent to this:
obj['something'] = function() {}
Quotes allow to create keys (and hence function names) that are not valid identifiers in JS, for example:
var obj = {
'123'() {}
};
creates a function with the name 123, believe it or not.
The square brackets syntax allows arbitrary expressions, so you can do
var obj = {
['myfunc_' + getFuncName()] () {}
}
and similar cool things.
This question already has answers here:
Why isn't this object being passed by reference when assigning something else to it?
(4 answers)
Closed 8 years ago.
In the below code we are passing an object. So, according to javascript we are passing a reference and manipulating.
var a = new Number(10);
x(a);
alert(a);
function x(n) {
n = n + 2;
}
But 10 is alerted instead of 12. Why?
n is local to x and first it is set to the same reference as global a. The right hand side n + 2 is then evaluated to be a number (primitive).
The left hand side of the assignment, n, is never evaluated, it is just an identifier there. So our local variable is now set to the primitive value of the right hand side. The value referenced by a is never actually modified. See
var a = new Number(10);
x(a);
alert(a); // 10
function x(n) {
alert(typeof n); // object
n = n + 2;
alert(typeof n); // number
}
When you compute
n + 2
this results in a new "native number" even if n is indeed a Number object instance.
Assigning to n then just changes what the local variable n is referencing and doesn't change the Number object instance. You can see that with
n = new Number(10);
console.log(typeof n); // ---> "object"
console.log(n + 2); // ---> 12
console.log(typeof (n+2)); // ---> "number"
n = n + 2;
console.log(typeof n); // ---> "number"
In Javascript (or Python or Lisp) there's no way to pass the "address" of a variable so that the called function mutates it. The only thing you can do is passing a setter function... for example:
function foo(setter) {
setter(42);
}
funciton bar() {
var x = 12;
foo(function(newx){x = newx;});
console.log(x); // ---> 42
}
Let me try to answer it with examples:
function modify(obj) {
// modifying the object itself
// though the object was passed as reference
// it behaves as pass by value
obj = {c:3};
}
var a = {b:2}
modify(a);
console.log(a)
// Object {b: 2}
function increment(obj) {
// modifying the value of an attribute
// working on the same reference
obj.b = obj.b + 1;
}
var a = {b:2}
increment(a);
console.log(a)
// Object {b: 3}
function augument(obj) {
// augument an attribute
// working on the same reference
obj.c = 3;
}
var a = {b:2}
augument(a);
console.log(a)
// Object {b: 2, c: 3}
Please refer the JSFiddle for working demo.
The answer is rather simple: because ECMAScript is pass-by-value and not pass-by-reference, and your code proves that. (More precisely, it is call-by-sharing, which is a specific kind of pass-by-value.)
See Is JavaScript a pass-by-reference or pass-by-value language? for some additional insight.
ECMAScript uses pass-by-value, or more precisely, a special case of pass-by-value where the value being passed is always a pointer. This special case is also sometimes known as call-by-sharing, call-by-object-sharing or call-by-object.
It's the same convention that is used by Java (for objects), C# (by default for reference types), Smalltalk, Python, Ruby and more or less every object-oriented language ever created.
Note: some types (e.g.) Numbers are actually passed directly by value and not with an intermediary pointer. However, since those are immutable, there is no observable behavioral difference between pass-by-value and call-by-object-sharing in this case, so you can greatly simplify your mental model by simply treating everything as call-by-object-sharing. Just interpret these special cases as internal compiler optimizations that you don't need to worry about.
Here's a simple example you can run to determine the argument passing convention of ECMAScript (or any other language, after you translate it):
function isEcmascriptPassByValue(foo) {
foo.push('More precisely, it is call-by-object-sharing!');
foo = 'No, ECMAScript is pass-by-reference.';
return;
}
var bar = ['Yes, of course, ECMAScript *is* pass-by-value!'];
isEcmascriptPassByValue(bar);
console.log(bar);
// Yes, of course, ECMAScript *is* pass-by-value!,
// More precisely, it is call-by-object-sharing!
If you are familiar with C#, it is a very good way to understand the differences between pass-by-value and pass-by-reference for value types and reference types, because C# supports all 4 combinations: pass-by-value for value types ("traditional pass-by-value"), pass-by-value for reference types (call-by-sharing, call-by-object, call-by-object-sharing as in ECMAScript), pass-by-reference for reference types, and pass-by-reference for value types.
(Actually, even if you don't know C#, this isn't too hard to follow.)
struct MutableCell
{
public string value;
}
class Program
{
static void IsCSharpPassByValue(string[] foo, MutableCell bar, ref string baz, ref MutableCell qux)
{
foo[0] = "More precisely, for reference types it is call-by-object-sharing, which is a special case of pass-by-value.";
foo = new string[] { "C# is not pass-by-reference." };
bar.value = "For value types, it is *not* call-by-sharing.";
bar = new MutableCell { value = "And also not pass-by-reference." };
baz = "It also supports pass-by-reference if explicitly requested.";
qux = new MutableCell { value = "Pass-by-reference is supported for value types as well." };
}
static void Main(string[] args)
{
var quux = new string[] { "Yes, of course, C# *is* pass-by-value!" };
var corge = new MutableCell { value = "For value types it is pure pass-by-value." };
var grault = "This string will vanish because of pass-by-reference.";
var garply = new MutableCell { value = "This string will vanish because of pass-by-reference." };
IsCSharpPassByValue(quux, corge, ref grault, ref garply);
Console.WriteLine(quux[0]);
// More precisely, for reference types it is call-by-object-sharing, which is a special case of pass-by-value.
Console.WriteLine(corge.value);
// For value types it is pure pass-by-value.
Console.WriteLine(grault);
// It also supports pass-by-reference if explicitly requested.
Console.WriteLine(garply.value);
// Pass-by-reference is supported for value types as well.
}
}
var a = new Number(10);
x(a);
alert(a);
function x(n) {
n = n + 2; // NOT VALID as this would essentially mean 10 = 10 + 2 since you are passing the 'value' of a and not 'a' itself
}
You need to write the following in order to get it working
var a = new Number(10);
x(a);
alert(a);
function x(n) {
a = n + 2; // reassign value of 'a' equal to the value passed into the function plus 2
}
JavaScript parameter passing works similar to that of Java. Single values are passed by value, but object attributes are passed by reference via their pointer values. A value itself will not be modified in a function, but attributes of an object would be modified.
Consider the following code:
function doThis(param1, param2) {
param1++;
if(param2 && param2.value) {
param2.value++;
}
}
var initialValue = 2;
var initialObject = {value: 2};
doThis(initialValue, initialObject);
alert(initialValue); //2
alert(initialObject.value); //3
http://jsfiddle.net/bfm01b4x/
This question already has answers here:
How does JavaScript .prototype work?
(26 answers)
Closed 8 years ago.
Given:
var x = function () {
};
x.prototype = { abc: 25 };
Can someone explain to me what this means. Could this be done all inside a function without the .prototype?
var x = function () {
// something here ?
};
Prototypes are how the class model works in JavaScript - you've created a class x that has a property abc which defaults to 25:
var obj = new x();
alert(obj.abc); // 25
The function x is the class constructor, it is called when a new instance of that class is created and can initialize it. And that means of course that you can just set the abc property there:
var x = function()
{
this.abc = 25;
};
var obj = new x();
alert(obj.abc); // 25
This is supposedly the less efficient approach however:
You have to manipulate each object created rather than setting the property on the prototype once and forever.
The property is stored on each object and consumes memory each time, as opposed to being stored once on the prototype.
ECMAScript Harmony has a nicer syntax for defining classes and prototypes, however this one isn't implemented in any browser yet:
class x {
constructor() {
...
}
public abc = 25;
}
This is equivalent to your code defining the prototype, merely grouping related operations a little better.