this is very confused me, and here is my simple html file:
<html>
<head>
</head>
<body>
<div id="misc">Test</div>
</body>
</html>
in Firebug console: I have this script:
var c = document.documentElement.childNodes[2].childNodes[3];
alert(c.id); //Return misc
alert(c.constructor); // Return [object HTMLDivElement]
As far as I know, a constructor of a function is a function (which is also a object but I'm not talking about that Function Object here). Now c's constructor is a object, and if I ask c'constructor constructor (which is c.constructor.constructor), It'll now return a "real" function, like this:
function Object() {
[native code]
}
I don't know why c.constructor is an object ( [object HTMLDivElement] ), it should be a function as expected.
Could you help me understand this one?
Thank you!
The short answer is: c does not have a regular constructor.
The longer answer: native objects like DOM elements, Function objects, the global object (usually window in browsers), the innerHTML function, etc. don't have regular constructors. This is because they are usually not implemented in JavaScript but at a lower level (in whatever language the browser or interpreter was written in).
The JavaScript language specification allows this - native built-in objects do not have to be normal javascript objects. The real reason is historical -- the specs were written by basically reverse engineering Netscape Navigator and having all the contributors agree on what was written. Since then everyone just stuck to it for backwards compatibility. The practical reason usually given these days is performance: if browsers are allowed to do this then they can be faster since native objects need not carry the heavy baggage of normal JavaScript objects.
In your specific case, DOM elements don't have regular constructors. There are 2 ways you can "construct" DOM objects:
document.createElement(). This is the official DOM method for creating <div>s, <span>s etc. In most browsers this method is not a normal constructor since DOM elements don't normally inherit form its prototype.
innerHTML(). This is a thin interface to access the browser's HTML compiler. It's the same compiler that the browser uses to parse regular web pages. Again, this is in no way a regular constructor since it doesn't even return the object(s) it creates.
Since DOM elements don't have normal constructors, browsers may return anything for their constructor property including nothing at all. What you are seeing in your case is mostly left over implementation detail that have leaked through to the javascript engine. It's not something you're supposed to access or use. Much less depend on to develop applications.
Related
I was wondering how accessing to strings is done. The String object exposes methods such as char(Code)At for public access, but doesn't use them itself as part of its other methods, for example indexOf, but instead accesses the string through an internal structure. However, when using a RegExp, I assume it can't use String's private properties, so it has to call the public API as any other class. I wrote a short test to see that, but it doesn't seem that's what happens: https://jsfiddle.net/n5pxe94L/
String.prototype[Symbol.iterator]=function*()
{
console.log("My custom iterator!");
yield "t";
};
const originalFunc=String.prototype.charCodeAt;
String.prototype.charCodeAt=function(index)
{
console.log("Used!");
return originalFunc.call(this,index);
}
new RegExp("a").test("Lalalala");
When I run this test, it doesn't print anything, which indicates the functions I overrode aren't used! So how does RegExp access the string it analyzes?
It's all done in the JavaScript engine however that engine sees fit to do it. Each JavaScript implementation may take a different approach, but they all have direct, very low-level access to the string's content. For performance reasons I'd expect these access methods to be highly optimized and direct, not allowing for overrides like you've attempted here as that would slow things down in the 99.9999% of cases where no such override exists.
JavaScript is not stuck using functions exposed in the API, it may have many others that are hidden from developers and for internal use only.
If you're writing JavaScript code you're stuck using the features available to you. If you're writing a JavaScript runtime you can do whatever you want.
Originally I wanted to simply answer along the lines of RegExp accesses the underlying string structure in C but I got curious so started digging into the source code of various javascript engines.
All the javascript engines commonly in use (which are V8 for Chrome and node.js, Chakra for Edge and JavascriptCore for Safari) implement regexp processing in C++. I couldn't find the exact regexp processing functions in Chakra and JavascriptCore but I'm sure if I spend a few days reading the code I'll find it.
For Chakra you will see that most of the Regexp methods in C++ accept an argument called input which is defined as Char*. I'm not sure if input is the string or the regexp pattern but I'm guessing it's the string. But note that it is Char not char so it is probably a custom class in the project. You can start by looking at the Chakra RegexpRuntime implementation here: https://github.com/microsoft/ChakraCore/blob/master/lib/Parser/RegexRuntime.cpp
For JavascriptCore best I can tell is that they pass the C++ JSString object to the regexp function. This is as close as to actually using the actual String prototype in js but it probably has methods not available to js: https://github.com/WebKit/webkit/blob/master/Source/JavaScriptCore/runtime/RegExpObject.cpp
I got the furthest with V8 in the last 15 minutes. V8 passes a parameter called subject as the string to regexp functions. This is a String object which is then converted to String::FlatContent. Now what is FlatContent? It is an array-like object (see the Vector class) of either 8 bit or 16 bit values that you can access using the [] operator in C++. This allows them to loop through the string using regular array indexing. You can start by checking out regexp.cc: https://github.com/v8/v8/blob/master/src/regexp/regexp.cc
As you can see, none of them access strings via Javascript's String object as is. The closest that works kind of how you expected them to behave is Apple's JavascriptCore in Safari but even then it's not using merely APIs exposed via javascript.
Note: I now believe this question was based on assumptions about the javascript specification which are actually implementation specific.
I am attempting to build a runtime debugging hook system for a complex dynamic javascript application. A series of choices have let me to choose to use javascript Proxy and Reflect metaprogramming constructs to interpose function calls in the application I am debugging, wrapping all incoming functions arguments in Proxy/Reflect constructs.
The approach involves replacing high level application functions with Proxies and using traps and handlers to provide debugging functionality, ultimately passing arguments through to the application in a transparent way. All property get/set and function executions act as normal. However, by wrapping all objects and functions in Proxies allows tracing of the runtime.
I am installing this hook system into Chrome.
(Note: Please do NOT provide an answer suggesting a different methodology for debugging hooks - options have been evaluated extensively.)
The issue is that some javascript methods in the application invoke closures and pass "this" parameters. When "this" parameters are wrapped in a Proxy, the runtime fails to execute a closure, instead throwing an "Illegal Invocation" Exception.
I have tried reengineering the debugging hook system to not wrap arguments for some methods, or selectively wrap arguments. I have not been able to find a way to tell if an argument is intended to be used as a context, making code that tries this approach hardcoded to many possible methods and calling conventions. Ultimately this is too fragile to calling convention edge cases and requires too many case statements.
I have also removed the logic for wrapping arguments before passing them through. This removes the benefit from the debug hooking system, and so I have always reverted the logic to wrap all incoming arguments.
alert.apply(this, [1]);
p = new Proxy(this, {});
try {
alert.apply(p, [1]);
} catch (e) {
console.log(e);
}
This throws an "Illegal Invocation" Exception.
typeof this === 'object'
true
But it seems that contexts are objects just like everything else.
I expect that passing a Proxy() through to context should succeed in an invocation. Barring this, I would expect the type of a context to be specific enough to determine whether it should be wrapped in a Proxy() or not.
I have two questions.
(1) What are the semantics of context binding closures in javascript that would cause binding to a Proxy(context) to fail with an illegal invocation?
(2) What type of object are contexts, and how can a javascript method tell one apart from other javascript objects by inspecting its properties at runtime?
What type of object are contexts, and how can a javascript method tell one apart from other javascript objects by inspecting its properties at runtime?
There is no special type. Every object can become a context by calling a method upon it. Most objects that will become a context of a method call do have that very method as an (inherited) property, but there's no guarantee.
You cannot tell them apart.
What are the semantics of context binding in javascript that would cause binding to a Proxy(context) to fail with an illegal invocation?
When the method is a native one. In user code functions, the this context being a proxy doesn't make a difference, when you access it then it will just behave as a proxy.
The problem is native methods that expect their this argument to be a native object of the respective type. Sure, those objects are still javascript objects, but they may contain private data on internal properties as well. A proxy's target and handler references are implemented through such internal properties as well, for example - you can sometimes inspect them in the debugger. The native methods don't know to unwrap a proxy and use its target instead, they just look at the object and notice that it doesn't have the required internal properties for the method to do its job. You could've passed a plain {} as well.
Examples for such methods can be found as builtins of the ECMAScript runtime:
Map.prototype.has/get/set/…
Set.prototype.has/get/set/…
TypeArrayPrototype.slice/copyWithin/map/forEach/…
Number/String/Boolean prototype methods
But also (and even more of them) as host objects supplied by the environment:
window.alert/prompt
EventTarget.prototype.addEventListener/removeEventListener
document.createElement
Element.prototype.appendChild/remove/…
really just anything that's browser-specific
but also in other environments, like the nodejs os module
I have tried unwrapping Proxies in the right places by coding in edge cases and by blanket/heuristic policies.
I think the only reasonable approach would be to check whether the called function is a native one, and unwrap all arguments (including the this argument) for them.
Only a few native functions could be whitelisted, such as most of those on the Array.prototype which are explicitly specified in the language standard to work on arbitrary objects.
Is there any way to reliably whether a JavaScript object is an exotic object type, and if so what its type is?
By "exotic", I mean (for the purposes of this question) anything which is could not be created using Object.create. This includes everything the ES2016 spec defines as exotic (any "object that does not have the default behaviour for one or more of the essential internal methods") plus anything created by the ObjectCreate specification method with a non-empty internalSlotsList, plus any kind of host object.
By "reliable", I mean not subject to being tricked by adding / removing properties from the object, using Object.create or Object.setPrototypeOf to give the object an unexpected prototype, modifying the object's ##toStringTag, or a constructor's ##hasInstance. This is important for library functions that need to correctly handle arbitrary user data.
(This means, in particular, that instanceof and Object.prototype.isPrototypeOf() are not useful. For example: var a = Object.create(Array.prototype) makes a something that looks and smells like an array—a instanceof Array === true and a.push and a.pop work as expected—but lacks the magic behaviour .length and is easily shown not to be an actual array exotic: Array.isArray(a) === false.)
By "type", I mean roughly what the ECMAScript 5.1 language specification referred to as [[Class]] - i.e., that quality that separates an Array instance, with its special [[DefineOwnProperty]] behaviour, from an ordinary Object.
Examples
Some cases are pretty easy:
Array exotic objects can be reliably detected using Array.isArray(a).
Functions can be reliably detected using typeof f === 'function'.
But is there any way to detect if a function is a bound function, native function or closure?
Some other exotic objects can be reliably detected by careful application of methods from their prototype object, e.g.
Sets can be detected by calling Set.prototype.has.apply(s, undefined), and seeing whether it throws a TypeError or not.
Is there any general way to make such a detection?
In particular:
Is there any general way to determine whether an object is plain or exotic?
Is there any general way to determine the type of an exotic object?
I note that Object.toString.apply(o) used to work reasonably well for this purpose: although in many browsers it would lie about the type of host objects, for all the types defined in the ES 5.1 spec it could be counted on to reliably tell you whether the object was a plain [object Object] or an exotic [object <Type>]. In ES6 and later, however, modifying ##toStringTag will subvert this test.
A means of detection which works in any conformant JS implementation would be ideal, but a means that is specific to Node.js would still be useful.
But is there any way to detect if a function is a bound function, native function or closure?
No. They are all plain and simple functions.
Some other exotic objects can be reliably detected by careful application of methods from their prototype object, e.g.
Sets can be detected by calling Set.prototype.has.apply(s, undefined), and seeing whether it throws a TypeError or not.
You can use the instanceof operator to test if an object is an instance of a particular function constructor (or something up its prototype chain).
var mySet = new Set();
console.log(mySet instanceof Set);
I tried Dart SDK after the 1.0 release, and wrote a simple hello-world program in Dart.
Then, with the SDK tool, I generated the JavaScript file: helloworld.dart.js
I went through the output js code, I saw there is a function named convertToFastObject.
The definition is:
function convertToFastObject(properties) {
function MyClass() {};
MyClass.prototype = properties;
new MyClass();
return properties;
}
The usage code is like:
A = convertToFastObject(A);
B = convertToFastObject(B);
I know this code is for various kinds of Browsers, not for Chromium/Chrome only.
I cannot understand, why the function can make the Object faster?
This is a speed optimization for Google's V8 engine.
To be sure, this code snippet looks pretty weird: it assigns properties as the prototype of a constructor MyClass, then uses the constructor to build an instance with new MyClass(), and then returns properties. This is strange because 1) properties is never altered, and 2) the function never uses MyClass or the instance ever again.
Whenever you see strange behaviors like this, you can be fairly sure it's a speed optimization. In this case, the speed is gained by using V8's "hidden class" optimization. From a closely-related section of the Dart source:
// Use the newly created object as prototype. In Chrome,
// this creates a hidden class for the object and makes
// sure it is fast to access.
In the V8 engine, a constructed object is given a "hidden" C++ class to represent its set of properties. By constructing an object whose prototype is the properties object, the property values of properties become part of the new instance's C++ hidden class, which improves property-access speed.
I believe all objects in V8 have hidden classes by default, so the need for this technique isn't immediately obvious. However, it is possible for an object to lose its hidden class (and enter "slow mode" or "dictionary mode") by demonstrating that it doesn't benefit from the optimization. When an object deletes one of its properties or adds too many properties that are unrelated to the properties of any other objects, V8 assumes that a shared hidden class isn't valuable, because the object has no other similar object to share its hidden class with. This convertToFastObject function can re-instate a "slow mode" object's right to a hidden class by using it as the prototype of a newly constructed instance.
Related hidden class question, arising from a different Dart optimization: What is this generated code supposed (intended) to do?
Where data is stored in a script contributes directly to the amount of time it takes to execute. In general, there are four places from which data can be accessed in a script:
-Literal value
-Variable
-Array item
-Object property
Reading data always incurs a performance cost, and that cost depends on which of these four locations the data is stored in. if you create a property using the "Object.Prototype.", the scope here is "Object.Prototype" which is smaller than the object's scope "Object." that hold in addition the local vars and stuff non enumerable. That is why creating proprieties using Prototype have a faster access ! Read these 2 articles to get better understanding:
1- http://oreilly.com/server-administration/excerpts/even-faster-websites/writing-efficient-javascript.html 2-http://www.packtpub.com/article/using-prototype-property-in-javascript
I am currently learning advanced JavaScript, with an aim to build a standards compliant (HTML5, CSS3, ESv5) library. Along my way I have already asked a couple of related questions to try and figure out where to start, what to do, what not to do, what to avoid etc. I have already begun reading the ECMA-262 (ECMAScript version 5) documentation, and have been running a few tests before I get started on development work.
Previous questions:
Writing ECMAScript5 compliant code
What's the difference between JavaScript, JScript & ECMAScript?
In my research I found out that different browsers implement the standard differently, and in that respect, they implement different objects. For example, IE implements an object called ActiveXObject, but this is not the case in FireFox. So I wrote a little test facility which determines if something is defined within the browser.
Consider the following which tests a few known objects (including jQuery since this is not built in).
Again, I have reached a point where I am in need of help:
Questions:
Given the example above, what is the difference between an object and a function?
Do I write functions or objects in ES/JS?
Why is Object a function and not an object?
Is there any hierarchical structure to built in objects / functions?
Can built in objects / functions be redefined as something entirely different?
Can built in objects / functions be undefined?
Can built in objects / functions be assigned new features if they do not already support them natively?
If an object is defined in one browser and not another, how can I compensate for this?
P.S. I do not want answers relating to specific implementations (JavaScript/JScript), rather answers relating to the standard (ECMAScript v5). Thanks in advance!
Given the example above, what is the difference between an object and a function?
In Chrome, all these items are functions. In general however, a function is an object with the addition that it holds code and that you can call it. So, you can also just add properties to functions (like jQuery does: $("selector") or $.ajax).
Do I write functions or objects in ES/JS?
Well, obviously that depends on what you code. function() {} gives you a function; {} gives you an object. (Again, functions are objects in the end.)
Why is Object a function and not an object?
Object is a function because you can call it, either as a constructor or not:
Object(); // returns an empty object
new Object(); // same
Also, given that almost everything is an instance of Object, it follows that Object is a constructor and thus a function. (Note again that functions are also objects.)
Is there any hierarchical structure to built in objects / functions?
As for the ECMAScript built-in objects, there is in a sense. There are constructor functions (String) on the global object, functions for instances (Array.prototype.forEach), and "static" functions (Object.defineProperty which is meant to be used on objects, Array.isArray for arrays).
Can built in objects / functions be redefined as something entirely different?
Sure, you can do Object = null. But any code relying on Object will start throwing exceptions, so it's not recommended at all.
Can built in objects / functions be undefined?
No, an object is not undefined by definition. undefined is not an object and vice-versa. This holds for any object.
Can built in objects / functions be assigned new features if they do not already support them natively?
Yes, if e.g. Array.prototype.forEach does not exist, you could set it yourself. But it should be noted that such functions turn up in for(var key in arr) loops which again can cause code to behave differently. This can be solved using Object.defineProperty by using {enumerable: false}. But there is another caveat: the function is shared across the whole environment (e.g. the current page). If other code is also setting them you're experiencing collisions.
If an object is defined in one browser and not another, how can I compensate for this?
You can "shim" such functions. For e.g. ES5 functions such as Array.prototype.forEach there are shims available which make them available on older browsers as well. Underscore.js may be a good example.
Given the example above, what is the difference between an object and a function?
A function is just an object which is callable. However, I guess you ask for the types of host objects (Node, HTMLCollection etc): Their behaviour is implementation-dependent ("not ecmascript-native") - you can't rely on anything.
Do I write functions or objects in ES/JS?
Huh? You write code, which can be interpreted.
Why is Object a function and not an object?
Object is the native object constructor, and therefore a function (and also an Object).
Is there any hierarchical structure to built in objects / functions?
Do you ask for "Everything is an Object"? If you ask for the structure of DOM interfaces: They are implementation-dependent host objects again, but most implementors have a inheritance system based on the DOM specification.
Can built in objects / functions be redefined as something entirely different? Can built in objects / functions be undefined?
No. You can overwrite the global variables pointing to them (the properties of the global object), but every instance will nevertheless be constructed from the native (then [nearly] unaccessible) constructors.
Can built in objects / functions be assigned new features if they do not already support them natively? If an object is defined in one browser and not another, how can I compensate for this?
Yes, you can extend the native objects and their prototypes. But watch out for host objects, they might not like it. If an object is defined only in certain environments, you can easily test for its existance and possibly shim it (es5, html5).
As part of my research into ECMAScript / JavaScript, I have found the following resource which provides a lot of information regarding the JS DOM.
http://krook.org/jsdom/index-all.html