Consider the following code:
var f = function() { return 10; }
typeof f; // returns "function"
f(); // returns 10
var g = f;
g(); // returns 10, obviously
var h = new f;
h; // console evaluates to f - ????
h(); // Type error - called_non_callable
typeof h; // returns "object"
So, what is h here? The Chrome console seems to evaluate it as f, but it isn't callable. What does it mean to "new" a function like this? How is h now related to f?
As an aside, these two lines appear to be equivalent:
var h = new f;
var h = new f();
What's up with that?
The root of your confusion is the way that Chrome represents objects on its console.
The expression new f() in your example is represented as 'f' on the Chrome's console output, but just as a mere "convenience" of this particular console, for example, logging the following object:
({constructor: function Foo(){}});
Will show it represented as "Foo". Basically the console tries to find a representation of which constructor your object is instance of.
So, the console shows you f, but you are not logging the function, the new operator produces an object that inherits from f.prototype.
You are returning 10 from the function, but since you call it with new, and the return type is a primitive, the value is discarded, the newly created object that inherits form f.prototype is returned.
For example:
var F = function () { return 10; };
F.prototype.inherited = 'foo';
var h = new F(); // the 10 returned is ignored
h instanceof F; // true
h.inherited; // "foo"
On the other hand, if you return an object from a constructor, the object instance that the new operator creates behind the scened (and inherits from the constructor's prototype) will be lost, for example:
var F = function () { return {}; };
F.prototype.inherited = 'foo';
var h = new F(); // the empty object is returned
h instanceof F; // false
h.inherited; // undefined
Yes, new f; and new f(); are completely equivalent, although people recommend using the parentheses to add clarity to your code.
this is how object-orientation in JavaScript works. if you call new on a function, this function would be treated as if it's a constructor of a class (the keywords class to define a class like other languages do doesn't exist in js).
so calling var h = new f(); makes h an object of class f, and an object itself isn't callable (that's why you get called_non_callable).
if you want to give your "class" some methots, you should do it like this:
function cat(name) {
this.name = name;
this.talk = function() {
alert( this.name + " says meeow!" )
}
}
cat1 = new cat("felix")
cat1.talk() //alerts "felix says meeow!"
cat2 = new cat("ginger")
cat2.talk() //alerts "ginger says meeow!"
that's an example from page 2 of this tutorial. for more information, read that or ask Google for object-orientation in JavaScript.
I'd recommend reading https://developer.mozilla.org/en/JavaScript/Reference/Operators/Special/this, especially the section on "Function context".
In a nutshell, when you new function, you're creating a new object:
var h = new f;
This says: "Create a new object referenced by the variable named h of type f". The function is then treated as a constructor rather than what you're expecting.
Once the object has been created, it's no longer callable (which is why you're experiencing an error on the line h().
In most language (Javascript not excluded), the () of a constructor are optional (unless there are required parameters (in some languages)).
Basically, the new keyword calls f as the constructor of a new object. The first reply to this question, on StackOverflow, sums it up quite nicely:
What is the 'new' keyword in JavaScript?
In JavaScript, functions aren't just functions, and they're not just objects; they're also used to defined constructors for types.
Generally speaking, when you have a function f, that function defines a type, whether that was intended or not. So the line
var h = new f();
defines an object h whose type is f.
I've never seen the line
var h = new f;
but I'm assuming it does the same as the other line.
Related
I am working with Javascript and Appdescriptors in JSON format.
What I want to do is creating a instance of a Class, where the classname is saved as string in oModelConf[sModelName].type. If that is not the case I want to take "sap.ui.model.odata.ODataModel"
Related Question offers this solution:
function instantiate(className, args) {
var o, f, c;
c = window[className]; // get reference to class constructor function
f = function(){}; // dummy function
f.prototype = c.prototype; // reference same prototype
o = new f(); // instantiate dummy function to copy prototype properties
c.apply(o, args); // call class constructor, supplying new object as context
o.constructor = c; // assign correct constructor (not f)
return o;
}
This is not a very good solution I think.
EDIT It does not work for me because my class is not defined on window, so window[className] is undefined. I do not know where my function is defined in SAPUI5
A second Solution:
eval(`a = new ${oModelConf[sModelName].type || "sap.ui.model.odata.ODataModel"}(sServiceUrl, true);`);
This is not a better solution because we should not use eval().
Are there any better solutions?
EDIT2
Because of the url in pimskies answer I found an other solution:
Since window.sap.ui.model.odata.ODataModel is the same as sap.ui.model.odata.ODataModel and window.sap is the same as window[sap]
I could take my string, and replace all . with ][, put the right brackets to front and end.
I will not code that because it is not a going solution.(I should not have coded the evalthing too...)
You could use jQuery.sap.getObject to access the class:
var ModelClass = jQuery.sap.getObject(oModelConf[sModelName].type || "sap.ui.model.odata.ODataModel");
var model = new ModelClass();
Edit: An other way (which i would recommend if you use AMD)
If you are using the modern AMD modules and you don't know if the module containing your class has already been loaded, you should use sap.ui.require() to load the module asynchronously. It requires the module to be specified via its unified resource name (the conversion is probably the most ugly part):
var className = oModelConf[sModelName].type || "sap.ui.model.odata.ODataModel";
var urn = className.replace(".", "/"); //Convert to unified resource name
sap.ui.require([urn],function(ModelClass){
//This function is called when the module is available
var model = new ModelClass();
...
});
Maybe map the string to a class?
function Foo() {
console.log('new foo');
}
function Bar() {
console.log('new bar');
}
var objects = {
'foo': Foo,
'bar': Bar
};
var cls = objects.foo || Bar;
new cls();
https://jsfiddle.net/ckd56d9v/1/
Or take a look at this answer: https://stackoverflow.com/a/9804142/5930258
What not combine the two? Since window[className] is failing, replace it with
oModelConf[className].type || sap.ui.model.odata.ODataModel...
function instantiate(className, args) {
var o, f, c;
c = oModelConf[className] || sap.ui.model.odata.ODataModel;
f = function(){}; // dummy function
f.prototype = c.prototype; // reference same prototype
o = new f(); // instantiate dummy function to copy prototype properties
c.apply(o, args); // call class constructor, supplying new object as context
o.constructor = c; // assign correct constructor (not f)
return o;
}
This seems strange to me. I have
var j = "x";
var k = "y";
function fun1 ( a, b) {
var j = a;
var k = b;
console.log("this.j is:", this.j);
console.log("this.k is:", this.k);
this.j = a;
this.k = b;
return this.j + this.k;
};
console.log("j is ", j);
console.log("k is ", k);
console.log("fun1(3,4) is ", fun1(3,4));
console.log("j is ", j);
console.log("k is ", k);
console.log("fun1(2,7) is ", fun1(2,7));
console.log("j is ", j);
console.log("k is ", k);
When I run this in Node.js, I get:
j is x
k is y
this.j is: undefined
this.k is: undefined
fun1(3,4) is 7
j is x
k is y
this.j is: 3
this.k is: 4
fun1(2,7) is 9
j is x
k is y
Why aren't j and k being set to arguments a and b in the function when they are declared? It just doesn't seem right that I have to do BOTH var j = a; AND this.j = a; !! What am I doing wrong?
In node, the output properly shows that the j and k variables in global are not being clobbered by the local variables j and k in fun1. When I run this in Chrome or Firefox, the global variables DO GET clobbered. In other words I get
j is x
k is y
this.j is: undefined
this.k is: undefined
fun1(3,4) is 7
j is 3
k is 4
this.j is: 3
this.k is: 4
fun1(2,7) is 9
j is 2
k is 7
Why isn't the local scope protecting the global var?
Thanks for any hints.
I recommend you to go read that! :) That explain precisely how to use this and what is the this!
Read here! Mozilla Developper Network
Here is the article if the link is dead. (Sorry, the formating is not perfect and the text is very long.)
Summary
A function's this keyword behaves a little differently in JavaScript
compared to other languages. It also has some differences between
strict mode and non-strict mode.
In most cases, the value of this is determined by how a function is
called. It can't be set by assignment during execution, and it may be
different each time the function is called. ES5 introduced the bind
method to set the value of a function's this regardless of how it's
called.
Syntax this Global context In the global execution context (outside of
any function), this refers to the global object, whether in strict
mode or not.
console.log(this.document === document); // true
// In web browsers, the window object is also the global object:
console.log(this === window); // true
this.a = 37; console.log(window.a); // 37 Function context Inside a
function, the value of this depends on how the function is called.
Simple call
function f1(){ return this; }
f1() === window; // global object In this case, the value of this is
not set by the call. Since the code is not in strict mode, the value
of this must always be an object so it defaults to the global object.
function f2(){ "use strict"; // see strict mode return this; }
f2() === undefined;
In strict mode, the value of this remains at
whatever it's set to when entering the execution context. If it's not
defined, it remains undefined. It can also be set to any value, such
as null or 42 or "I am not this".
Note: In the second example, this should be undefined, because f2 was
called without providing any base (e.g. window.f2()). This feature
wasn't implemented in some browsers when they first started to support
strict mode. As a result, they incorrectly returned the window object.
As an object method
When a function is called as a method of an object, its this is set to
the object the method is called on.
In the following example, when o.f() is invoked, inside the function
this is bound to the o object.
var o = { prop: 37, f: function() {
return this.prop; } };
console.log(o.f()); // logs 37 Note that this behavior is not at all
affected by how or where the function was defined. In the previous
example, we defined the function inline as the f member during the
definition of o. However, we could have just as easily defined the
function first and later attached it to o.f. Doing so results in the
same behavior:
var o = {prop: 37};
function independent() { return this.prop; }
o.f = independent;
console.log(o.f()); // logs 37 This demonstrates that it matters only
that the function was invoked from the f member of o.
Similarly, the this binding is only affected by the most immediate
member reference. In the following example, when we invoke the
function, we call it as a method g of the object o.b. This time during
execution, this inside the function will refer to o.b. The fact that
the object is itself a member of o has no consequence; the most
immediate reference is all that matters.
o.b = {g: independent, prop: 42}; console.log(o.b.g()); // logs 42
this on the object's prototype chain
The same notion holds true for methods defined somewhere on the
object's prototype chain. If the method is on an object's prototype
chain, this refers to the object the method was called on, as if the
method was on the object.
var o = {f:function(){ return this.a + this.b; }}; var p =
Object.create(o); p.a = 1; p.b = 4;
console.log(p.f()); // 5 In this example, the object assigned to the
variable p doesn't have its own f property, it inherits it from its
prototype. But it doesn't matter that the lookup for f eventually
finds a member with that name on o; the lookup began as a reference to
p.f, so this inside the function takes the value of the object
referred to as p. That is, since f is called as a method of p, its
this refers to p. This is an interesting feature of JavaScript's
prototype inheritance.
this with a getter or setter
Again, the same notion holds true when a function is invoked from a
getter or a setter. A function used as getter or setter has its this
bound to the object from which the property is being set or gotten.
function modulus(){ return Math.sqrt(this.re * this.re + this.im *
this.im); }
var o = { re: 1, im: -1, get phase(){
return Math.atan2(this.im, this.re); } };
Object.defineProperty(o, 'modulus', {
get: modulus, enumerable:true, configurable:true});
console.log(o.phase, o.modulus); // logs -0.78 1.4142 As a constructor
When a function is used as a constructor (with the new keyword), its
this is bound to new object being constructed.
Note: while the default for a constructor is to return the object
referenced by this, it can instead return some other object (if the
return value isn't an object, then the this object is returned).
/* * Constructors work like this: * * function MyConstructor(){ *
// Actual function body code goes here. * // Create properties on
|this| as * // desired by assigning to them. E.g., * this.fum =
"nom"; * // et cetera... * * // If the function has a return
statement that * // returns an object, that object will be the *
// result of the |new| expression. Otherwise, * // the result of
the expression is the object * // currently bound to |this| * //
(i.e., the common case most usually seen). * } */
function C(){ this.a = 37; }
var o = new C(); console.log(o.a); // logs 37
function C2(){ this.a = 37; return {a:38}; }
o = new C2(); console.log(o.a); // logs 38 In the last example (C2),
because an object was returned during construction, the new object
that this was bound to simply gets discarded. (This essentially makes
the statement "this.a = 37;" dead code. It's not exactly dead, because
it gets executed, but it can be eliminated with no outside effects.)
call and apply
Where a function uses the this keyword in its body, its value can be
bound to a particular object in the call using the call or apply
methods that all functions inherit from Function.prototype.
function add(c, d){ return this.a + this.b + c + d; }
var o = {a:1, b:3};
// The first parameter is the object to use as // 'this', subsequent
parameters are passed as // arguments in the function call
add.call(o, 5, 7); // 1 + 3 + 5 + 7 = 16
// The first parameter is the object to use as // 'this', the second
is an array whose // members are used as the arguments in the function
call add.apply(o, [10, 20]); // 1 + 3 + 10 + 20 = 34 Note that with
call and apply, if the value passed as this is not an object, an
attempt will be made to convert it to an object using the internal
ToObject operation. So if the value passed is a primitive like 7 or
'foo', it will be converted to an Object using the related
constructor, so the primitive number 7 is converted to an object as if
by new Number(7) and the string 'foo' to an object as if by new
String('foo'), e.g.
function bar() { console.log(Object.prototype.toString.call(this));
}
bar.call(7); // [object Number] The bind method
ECMAScript 5 introduced Function.prototype.bind. Calling
f.bind(someObject) creates a new function with the same body and scope
as f, but where this occurs in the original function, in the new
function it is permanently bound to the first argument of bind,
regardless of how the function is being used.
function f(){ return this.a; }
var g = f.bind({a:"azerty"}); console.log(g()); // azerty
var o = {a:37, f:f, g:g}; console.log(o.f(), o.g()); // 37, azerty As
a DOM event handler
When a function is used as an event handler, its this is set to the
element the event fired from (some browsers do not follow this
convention for listeners added dynamically with methods other than
addEventListener).
// When called as a listener, turns the related element blue function
bluify(e){ // Always true console.log(this === e.currentTarget);
// true when currentTarget and target are the same object
console.log(this === e.target); this.style.backgroundColor =
'#A5D9F3'; }
// Get a list of every element in the document var elements =
document.getElementsByTagName('*');
// Add bluify as a click listener so when the // element is clicked
on, it turns blue for(var i=0 ; i
elements[i].addEventListener('click', bluify, false); } In an in–line
event handler
When code is called from an in–line handler, its this is set to the
DOM element on which the listener is placed:
Show this
The above alert shows button. Note however that only the
outer code has its this set this way:
Show inner
this In this case, the inner function's this isn't set so it
returns the global/window object (i.e. the default object in
non–strict mode where this isn't set by the call).
I want to know from where does console.log get the name of the constructing function when printing an object. Also, does that actually effect anything code wise?
function F() {
this.test = 'ok';
}
var f = new F();
console.log( f );
The output of console.log (in Chrome) is:
F {test: "ok"}
Where does the console.log get the F in F {test...?
If I change F.constructor, F.prototype, and f.constructor to something random, it still prints the original F:
function G() {
this.fail = 'bad';
}
function F() {
this.test = 'ok';
}
F.prototype = G;
F.constructor = G;
var f = new F();
console.log( f );
The output is still the same - F {test: "ok"}
Is this information is simply kept privately by the browser, my question is does it affect JavaScript code in any way? That is, will it creep up during comparison or inheritance, after I override the constructor's prototype and constructor properties?
UPDATE
The original purpose was to do the following.
function Person ( _name ) {
this.name = _name;
}
function Construct( _constructor, _args, _context ) {
function F () {
var context = _context || this;
return _constructor.apply( context, _args );
}
/* I want to have the constructed object by identified
as _constructor and not a F */
F.prototype = _constructor.prototype;
return new F();
}
function Make ( _who ) {
if ( 'person' === _who ) {
/* Remove the first argument, who, and pass along all the rest.
Constructors cannot be called with .apply so I have to use
this technique. */
return Construct( Person, Array.prototype.slice.call( arguments, 1 ) );
}
}
var dev = Make( 'person', 'John Doe' );
console.log( dev ); // prints `F {name: "John Doe"}`
As you can see, the resulting print of dev outputs F {name: "John Doe"}, which made me question whether I may run into problems later on if I'd like to make comparisons or inheritance with instances constructed in such a way.
Changing F.prototype replaces the content of F, not the name. The old prototype object still exists and a reference to it is stored internally in each instance of the old F. You cam check it by calling f.__proto__´ (deprecated) or Object.getPrototypeOf(f).
Note that __proto__ is an accessor proterty (internally a getter, not a real property), so it cannot be changed.
It's not difficult, because f is finally an instance of F and the order of scope resolving (this, prototype, ...) is obvious :-)
For example, you can run this code and you'll see that in this case it will print G:
function G() {
this.fail = 'bad';
}
function F() {
this.test = 'ok';
}
F.prototype = G;
F.constructor = G;
var f = new F(); // Prints F
console.log(f);
f.prototype = G; // Redefining f type info
f.constructor = G;
console.log(f); // Prints G
Your creating a new instance of F, so the browser prints that in order to help you keep track of your logging. Even though you change the prototype would you still have to create a new "F" in order to get the object.
function A () { something: 123 }
new A();
console.log result: A {}
new B();
console.log result: ReferenceError: B is not defined
object.constructor.name is another way of getting the name of an object constructor.
May I suggest another approach for the original intention? There is no problem with just using a different reference to the prototype object instead of the original one, so you can do
function construct(constructor, args, context) { //lowercase, as it's a function, not a class
return new constructor(args);
}
This should create the right object in the first place, no need to swap any prototypes.
I have the following piece of code:
var Test = function () {
};
Test.prototype.doSomething = function() {
return "done";
};
Now, I create an object of Test
var t = new Test();
alert(t.doSomething()); // Correct alerts "done"
Now I add another method to the prototype:
Test.prototype.fly = function() { return "fly"; };
alert(t.fly()); // Correctly alerts "fly" (existing objects get "live udpated")
Now, I make the prototype point to a blank object:
Test.prototype = {};
alert(t.doSomething()); // Continues to alert "done", but why?
alert(t.fly()); // Continues to alert "fly", but why?
var t2 = new Test();
alert(t.doSomething()); // As expected, this does not work
When I add a method to prototype, it reflects correctly on all new and existing objects
When I "blank" out the prototype by doing <name>.prototype = {};, it only "blanks" out new instances, but not existing ones. Why?
An analogy is this:
var a = {foo : 'bar'};
var b = a; //the same object as a
var c = a;
var d = a;
a.apple = 'orange';
a = 1; //a === 1. b, c and d stay the same, pointing to the object with apple
What I did here is replace what a was pointing, but not the object itself.
When you added fly, you are modifying that single prototype object which all instances share, the object that Test.prototype is currently pointing to.
But when you assigned a blank object to Test.prototype, you modified what Test.prototype was pointing to. It does not modify what the existing instances are pointing to. But from this point on, any new instances will now use the new object on Test.prototype as their prototype object.
If you are familiar with C, I'd rather think of JS variables as pointers rather than references.
I'm completing the previous answer, if you want reflect your changes on all instances you must update the prototype correctly.
Prototype property is an object and you can delete a propery with the reserved keyword 'delete'.
If you want delete 'doSomething' property :
delete Test.prototype.doSomething;
consider
function Foo(){}
Foo.prototype = {a:{"VMAddress":"#1234"}}
consider that Foo.prototype.a object has VMAddress "#1234"
if you create object now then,
var f1 = new Foo();
now f1.a will point to the same object ie with Virtual Machine address "#1234"
if you look
f1.a === Foo.prototype.a ;//prints tue
If you change prototype to some other value now,
Foo.prototype = {a:{"VMAddress":"#5678"}}
and if you create object now then,
var f2 = new Foo();
although
f2.a === Foo.prototype.a; //prints true because both point to same VM address #5678
but
f1.a === f2.a; //prints false
why??
because their VM address are different(one is #1234 and other is #5678) and infact they are different object
final verdict
the prototype chain at the time of object creation decides what an object's prototype will be.
I am reading JavaScript: The Good Parts. In the book, a beget function is defined. Its purpose is to create and return a new object, which uses the other object as its prototype. Why does the beget function instantiate a new function instead of an object?
if( typeof Object.beget !== 'function' ){
Object.beget = function(o){
var F =new Function(){}; // this line, why it cannot be var F = new Object();
F.prototype = o;
return new F();
}
}
This has everything to do with the new keyword. In JavaScript, new only works with functions (which are a special type of object).
If you use new on just about any function, you will get an object back.
alert(typeof console.log); // function
var dumb = new console.log(); // dumb is an object
The type of object you get back depends on that function's prototype object.
alert(typeof console.log.prototype); // object, any new objects created by the new keyword will be of this type.
alert(typeof Function.prototype); // function, new objects are functions.
alert(typeof new Function()); // function, see?
alert(typeof (function(){})); // function, using literal syntax, equivalent
You may have noticed from above that Function itself is a function. In fact, all of the built-in constructors are functions (Function, Object, Number, Array, etc). Capitalization is just a convention to distinguish how you use a function.
So to get back to your question, the author uses an empty Function object simply because it can be used as a constructor. Objects cannot.
He then changes the constructor's prototype, so that it will return objects of that type.
Object.beget = function(o) {
var F = new Function(); // now F can be used as a constructor.
F.prototype = o; // All new objects F creates will be based on o.
return new F();
};
To add on to previous answers and avoid some confusion, this beget() function was replaced with create() via an errata, so different books seem to have different version of the code. The book on Safari Books Online has it printed like this:
if (typeof Object.create !== 'function') {
Object.create = function (o) {
var F = function () {};
F.prototype = o;
return new F();
};
}
Note that it no longer encourages the use of the new keyword on line 3.
In my opinion,as the MDN said
The new operator creates an instance of a user-defined object type or of one of the built-in object types that has a constructor function.
Syntax
new constructor[([arguments])]
Parameters
constructor
A function that specifies the type of the object instance.
arguments
A list of values that the constructor will be called with.
So,wo have to use a function to create a new instance.
For example:
var list = new Array();
typeof Array;//"function"
This Array is not a object,but a constructor function.
For one thing, you can't use () on a generic object nor on anything else that isn't a function. You'll get an error something like "TypeError: F is not a function."
// create a temporary function
var F =new Function(){};
// set the prototype of the function to be o
F.prototype = o;
// create a new object from the function
return new F();
Because that's how new works. new creates a new object and places F.prototype in the prototype chain.
new F() === Object.create(F.prototype)
My books is
if (typeof Object.beget !== 'function') {
Object.beget = function (o) {
var F = function () {};
F.prototype = o;
return new F();
};
}
your answer is in the book only. The beget method created a new object and that object is used as its prototype.
Below line is used to check if beget method is already used or not !
if( typeof Object.beget !== 'function' )
And then..
A constructor, F, is defined, its prototype is set to the passed in object and then a new instance is returned.