Hey guys I'm kind of new to JS and found out that functions are also objects.
This means I can add properties to them like this:
let func = function(){};
func.foo = "foo";
console.log(func.foo); // prints foo
However when we now do this:
console.log(func);
It will return (using chrome):
Why does it not show the properties of the object like it usually shows on other type of objects?
Also when we for instance try to console.log(Function) it will return the following output:
What is this native code? What I got from other sources was that it is code written in another programming language(C, C++) that programmed the functionality of this constructor.
Thanks in advance!
Chrome’s console displays functions’ bodies instead of their properties, because that’s usually more useful. It’s much easier to tell when you don’t use an empty function:
And it’ll indeed substitute in [native code] when there is no JavaScript body to be shown.
As #ibrahim mahrir points out, you can use console.dir(func) to get both the default inspection and an expandable list of properties.
Related
Is it possible to make an object callable by implementing either call or apply on it, or in some other way? E.g.:
var obj = {};
obj.call = function (context, arg1, arg2, ...) {
...
};
...
obj (a, b);
No, but you can add properties onto a function, e.g.
function foo(){}
foo.myProperty = "whatever";
EDIT: to "make" an object callable, you'll still have to do the above, but it might look something like:
// Augments func with object's properties
function makeCallable(object, func){
for(var prop in object){
if(object.hasOwnProperty(prop)){
func[prop] = object[prop];
}
}
}
And then you'd just use the "func" function instead of the object. Really all this method does is copy properties between two objects, but...it might help you.
ES6 has better solution for this now. If you create your objects in a different way (using class, extending 'Function' type), you can have a callable instance of it.
See also: How to extend Function with ES6 classes?
Following the same line of #Max, but using ES6 extensions to Object to pass all properties and prototype of an object obj to the callable func.
Object.assign(func, obj);
Object.setPrototypeOf(func, Object.getPrototypeOf(obj));
Others have provided the current answer ("no") and some workarounds. As far as first-class support in the future, I suggested this very thing to the es-discuss mailing list. The idea did not get very far that time around, but perhaps some additional interest would help get the idea moving again.
https://esdiscuss.org/topic/proposal-default-object-method
"CALLABLE OBJECTS"
I haven't seen mention of this type of answer yet.. but this is how I do "callable" objects:
<< PSEUDO CODE >>
{...objectWithFunctionsInside}[keyString](optionalParams)
short example defining first, simplest and preferred method if I just want a "callable object," in my definition:
let obj = {
o:()=>{return("oranges")},
b:()=>{return("bananas")},
s:"something random here, doesn't have to be functions"
}
obj["o"]()
short example of nameless object being run within a function's return, with parameters (note parameters works in the first example too):
function autoRunMyObject(choice,param){
return{
o:(p)=>{return(p+"oranges")},
b:(p)=>{return(p+"bananas")},
}[choice](param)
}
autoRunMyObject("b","orange you glad I didn't say ")
and that's pretty much it
You could even get weirder with it and do nameless functions that auto-run themselves and produce an output right away... for no reason, lol.
... hit F12 and copy this code into your browser console and press enter, you'll get an output right away with the full string:
((autoparam="o")=>{return{
o:(p)=>p+"oranges",
b:(p)=>p+"bananas",
}[autoparam]("I guess this time it's ")})()
You could even pass in the string of "b" in the final parenthesis for a different output from the default "o".
Also, each of my examples (minus the pseudo code first example) are easily copy/paste-able into the browser console for quick testing -- it's a nice place to experiment with JS.
In summary -- this is how I like to do "callable objects"
It's much better than
SWITCH(){CASE:BREAK;};
statements and
IF{}ELSE IF(){}ELSE IF(){};
chains.
Node.js querystring.parse() method returns what looks like to be an object, but one without a constructor. According to https://nodejs.org/api/querystring.html :
"... The object returned by the querystring.parse() method does not prototypically inherit from the JavaScript Object. This means that typical Object methods such as obj.toString(), obj.hasOwnProperty(), and others are not defined and will not work."
This easily causes bugs because typically you would assume that every Object understands some basic methods like toString() and that it has a "constructor" which more or less tells us its "type".
What's the best way to handle these rather incapable Objects? I tried:
let myOb = new Object(dumbObject);
But that produces a result which does not have the toString() -method either and does not have the property 'constructor'.
What's the best way to turn these dumb objects into ordinarily behaving ones? And, why would anybody want to create such objects in the first place?
I think (from the top of my head)
let newObject = JSON.parse(JSON.stringify(dumbObject))
should work.
If you want a more generic way to call toString() on an object, you can call it from Object.prototype using .call().
var s = Object.prototype.toString.call(smartObject);
But why? It's just going to give you "[object Object]" on any plain object. Why is it important to get that string?
var p = {};
var s = Object.create(null);
console.log(p.toString());
console.log(Object.prototype.toString.call(s));
typically you would assume
No, you wouldn't. If you make such assumptions, document them in your interface.
What's the best way to turn these dumb objects into ordinarily behaving ones?
Use Object.assign with an ordinary object as the target. Alternatively, you can also change the prototype by using Object.setPrototypeOf, but that's not recommended.
Or just create the properties like .toString or .constructor that you need. See this example.
And, why would anybody want to create such objects in the first place?
Because you need this safety when using objects instead of Maps. See this example.
Explicitly set the prototype of your dumb object with Object#setPrototypeOf
var dumbObject = Object.create(null);
Object.setPrototypeOf(dumbObject, Object.prototype);
dumbObject.toString() //runs fine
Thanks for all the answers, one of which contained a link to another question which really was my question as well, even if I didn't know that at first. That other question is: How to create a JS object with the default prototype from an object without a prototype?
From it I found the answer which I think is the simplest solution so far: Use Object.assign(). Like this:
let orphan = require('querystring').parse("{}") ;
// console.log ( "Got value: " + orphan ) ;
// Above causes the error:
// -> TypeError: Cannot convert object to primitive value
let oa = (x) => Object.assign({}, x);
console.log ("Got value: " + oa (orphan) ) ;
Note the issue is not particularly about "querystring" but with objects which have no prototype in general. Yes we should probably call these poor objects "orphans" instead of "dumb". But I think "dumb" is still quite good term as well. An object which has no prototype has very few (or no?) methods so it can answer very few if any questions we would like to ask it.
I have an odd situation in my Javascript code which I cannot explain. So far it has been observed only on Safari/Mac.
I have a line like this:
dict[id].sliceHovered = true;
And sometimes it throws an error:
Attempted to assign to readonly property.
Also:
dict is a bare blank object which I create myself with dict={}.
id is supplied by outside data, so it can be anything (I don't yet know which particular value causes this).
sliceHovered is obviously not a name of something that Javascript has built
in.
The objects in the dict are of my own type. They have a sliceHovered member, but it's not a Javascript defined property (as in Object.defineProperty()), just a regular property (the constructor executes this.sliceHovered=false).
"use strict" is on.
Object.freeze(), Object.seal(), Object.preventExtensions() and const are not used anywhere in the entire codebase.
Thus it's extremely puzzling as to how such an error could be thrown here. If I had an indexing error and dict[id] would be undefined or null, the error would be different. My only idea is that since the dict is created as dict={} then it inherits from Object and maybe id maps to some inherited property. But that means that the object returned from dict[id] would have to be read-only itself, because sliceHovered is definitely not a name of an existing Javascript property.
However I cannot think of any Javascript objects that would be intrinsically read-only like that.
Any ideas what could be wrong here?
You can check this situation
My only idea is that since the dict is created as dict={} then it inherits from Object
with: var dict = Object.create(null);
Also try to use Object.getOwnPropertyDescriptor(dict, id) to make sure descriptors have right values.
I'm trying to write an object explorer that shows the user the properties and values of an object. My idea is that the will be able to drill down to see objects within objects, click on hyperlinks to examine the methods' source code and otherwise see the properties values.
Here's what I've got so far (jsFiddle).
Q: Help! I don't know what I'm doing! One thing I noticed is that I'm apparently not getting any properties where hasOwnProperty is true. Another thing is I need the function to be recursive. Another is: I think I remember reading somewhere of a JavaScript function that can get the text of a JavaScript function.
So, to answer your question: "What's the question?" I guess I can say "Can you help me write this generic JavaScript object explorer as possibly a jQuery plugin?"
Your question is quite general. To your two specific points:
In order to make your function recursive, I believe you can simply copy this block of code from your 'bodyLog' function to the place you have commented your recursion. You will want to add one to 'level' as you pass it down to your recursive call.
// $(obj).each(function(index,Element) { // EDIT shouldn't need this iteration, you're inside the loop
result += showObjectsMethodsAndValues(Element,level+1,true);
result += showObjectsMethodsAndValues(Element,level+1,false);
//});
The method that gets the string body of a function is simply calling '.toString()' on the method object. So if you do:
var myFun = function(a, b) {
return a+b;
};
alert(myFun.toString());
You will see the body of the function printed out. For built-in objects you will probably see "[native code]" as the body of the function, rather than real javascript code.
The reason you aren't seeing any hasOwnProperty properties is that I doubt the jQuery object has any. All of it's properties likely live in it's prototype object. Try this:
var myObj = {foo: 1, bar: 2};
myObj.prototype = {baz: 3};
Then call your function on myObj. Foo and bar should come back with hasOwnProperty true, baz will return false. I believe all of jQuery's properties live in it's prototype object, so they will all return false.
http://www.netgrow.com.au/files/javascript_dump.cfm is a good candidate.
Trying to grasp Prototyping in Javascript. Trying to create my own namespace to extend the String object in JavaScript.
Here is what I have so far (a snippet):
var ns {
alert: function() {
alert (this);
}
}
String.prototype.$ns = ns;
As you can see, I am trying to place what will be a series of functions into the ns namespace. So I can execute a command like this:
"hello world".$ns.alert();
But the problem is, the this doesn't reference the text being sent (in this case, "hello world"). What I get is an alert box with the following:
[object Object]
Not having a full grasp of the object-oriented nature of JavaScript, I am at a loss, but I am guessing I am missing something simple.
Does anyone know how to achieve this (get the source text from the nested object)? Short of that, I am left with having to do procedural programming ( ns.alert("hello world"); ) which I am trying to avoid.
Thanks -
This is happening because when you invoke a reference, its base object is set as the this value of the invoked method (more technical details here).
So when you invoke "hello world".$ns.alert(); the this value inside your alert method, will refer to "hello world".$ns, which is String.prototype.$ns.
I don't think adding object levels (namespaces) inside the prototype of built-in objects can be useful, I usually recommend to not modify objects you don't own.