Does JavaScript have the equivalent of Python's __getattribute__? In the sense that I'd like an object, a, for which a reference to a property x is equivalent to a.__get__('x'). Trying to get this to work in V8. Possible?
Example: an object which makes REST-ful calls:
RESTful("some-url").foo({x:1}) => response of call to "some-url/foo?x=1"
It is not possible for properties, though there is a non-standard way (__noSuchMethod__) for methods which is only available for Firefox.
Related
For example I loaded a script on some website, and I would like to know if JSON.parse/stringify wasn't monkey patched.
I noticed that if I use toString on the function in Chrome/FF, JSON.stringify.toString, then I get back:
function stringify() {
[native code]
}
My question is do you think this is a good way to verify if a function was monkey patched? Also would love to hear of any other approaches to this problem.
One could easily fake JSON.stringify.toString
JSON.stringify = function() {}
JSON.stringify.toString = function() {return 'ha-ha'}
console.log(JSON.stringify); //ha-ha
A little more robust way would be to use Function.prototype.toString
Function.prototype.toString.call(JSON.stringify)
But really bad monkeypatcher could patch Function.prototype.toString as well :)
Yes, this is the only practical way to check whether or not a native function had been overridden or not.
const isNative = fn => !!fn.toString().match(/\[native code\]/)
console.log(isNative(JSON.stringify));
A more robust solution could use Function.prototype.toString() instead of direct call of fn.toString(), but both are monkeypatchable as well. The joys of JavaScript :)
The spec ( http://www.ecma-international.org/ecma-262/7.0/index.html#sec-function.prototype.tostring ) does not specify the exact string returned for a builtin function :
19.2.3.5 Function.prototype.toString
When the toString method is called on an object func, the following
steps are taken:
If func is a Bound Function exotic object, then Return an
implementation-dependent String source code representation of func.
The representation must conform to the rules below. It is
implementation dependent whether the representation includes bound
function information or information about the target function. If
Type(func) is Object and is either a built-in function object or has
an [[ECMAScriptCode]] internal slot, then Return an
implementation-dependent String source code representation of func.
The representation must conform to the rules below. Throw a TypeError
exception. toString Representation Requirements:
The string representation must have the syntax of a
FunctionDeclaration, FunctionExpression, GeneratorDeclaration,
GeneratorExpression, ClassDeclaration, ClassExpression, ArrowFunction,
MethodDefinition, or GeneratorMethod depending upon the actual
characteristics of the object. The use and placement of white space,
line terminators, and semicolons within the representation String is
implementation-dependent. If the object was defined using ECMAScript
code and the returned string representation is not in the form of a
MethodDefinition or GeneratorMethod then the representation must be
such that if the string is evaluated, using eval in a lexical context
that is equivalent to the lexical context used to create the original
object, it will result in a new functionally equivalent object. In
that case the returned source code must not mention freely any
variables that were not mentioned freely by the original function's
source code, even if these “extra” names were originally in scope. If
the implementation cannot produce a source code string that meets
these criteria then it must return a string for which eval will throw
a SyntaxError exception.
So checking for [Native Code] may or may not work depending on the interpreter. Furthermore, an implementation could well implement builtin functions as normal javascript code.
So in answer to your question, you cannot determine, is a Javascript specified way whether a builtin function has been monkey-patched.
That said it appears that Chrome and Firefox both return the [Native Code] string subject to verification on other implementations that may be a pragmatic solution.
I just wanted to add that, after ES6, all solutions that involve checking "[native code]" are even less reliable because of ES6 proxy traps.
// Example monkey-patching the Fetch API using an ES6 proxy trap
window.fetch = new Proxy(window.fetch, {
apply(fetch, that, args) {
const result = fetch.apply(that, args);
result.then((response) => {
console.log("Intercepted!", args, response);
});
return result;
}
});
// True
console.log(window.fetch.toString().includes("[native code]"));
// True
console.log(Function.prototype.toString.call(window.fetch).includes("[native code]"));
For more info, check this answer.
I tried to develop some of the ideas from other replies into a working script - here it is:
https://gist.github.com/mindplay-dk/767a5313b0052d6daf2b135fdecd775f
Paste it into the Chrome (or Edge) console and press ENTER - it'll print out a list of any constructors and class-methods not matching their native counterparts. (It does this by comparing against the native APIs in an iframe - which it creates via document.createElement, so, technically, it's possible to fool it by overriding that method, if you were intending to do so deliberately; this isn't a security tool.)
Note that this currently gives false positives for window.location, window.fetch and window.length - this appears to be because these properties aren't correctly reflected by their native browser implementations? If you know how to fix it, please post a comment.
Here is example output from a site that was incorrectly loading some IE11 polyfills into Chrome:
I tried googling but couldn't find a precise answer, so allow me to try and ask here. If the question does not seem proper, please let me know and I'll delete it.
In JS you've got three different way of writing certain build in functionalities:
str.length
str.toString()
parseInt(str)
I wonder if there is a reason behind these different ways of writing. As a new user I don't grasp why it couldn't be streamlined as: length(str) / toString(str) / parseInt(str) or with dot formulation.
I however think if I do know the reason behind these differences, it would give me a better understanding of JavaScript.
Length is one of the attributes of string in JavaScript. Hence you use string.length to get the length of the string.
toString is a function for string objects, hence we use stringobj.toString().
parsInt(str) is a global function which takes string as a parameter.
JavaScript is object-oriented, so there are functions or procedures which require first an object to use as this in their bodies. str.length is a property, both syntactically and semantically. It doesn't require any parameters and represents some quality of the object. obj.toString() is a method (a function attached to an object), which doesn't represent any characteristics of the object, but rather operates on its state, computes some new values, or changes the state of the object a lot. parseInt(str) is a "global" function, which represents an operation not attached to any type or object.
Under the hood, these three ways may be well implemented with just calling a function, passing this as the first parameter (like C# does, for example). The semantic difference is the important one.
So why not use just the third syntax, like for example PHP does? First, it doesn't bloat the global environment with lots of functions which only work for one specific case and type, allowing you to specify any new function you want without breaking the old functionality. Second, it ecourages you to use object-oriented concepts, because you can already see working objects and methods in the language, and can try to make something similar.
And why isn't parseInt a method? It can as well be str.toInt() without any issues, it's just the way JavaScript designers wanted it to be, although it seems also a bit logical to me to make it a static method Number.parseInt(str), because the behaviour of the function is relevant more to the Number type than the String type.
JavaScript is based around objects. Objects have properties (e.g. a User object may have name and age properties). These are what define the user and are related to the user. Properties are accessed via dot-notation or brackets notation (to access Eliott’s age, we’ll use either eliott.age or eliott['age'] — these are equivalent).
These properties can be of any type — String, Number, Object, you name it — even functions. Now the proper syntax to call a function in JS is to put round brackets: eliott.sayHello(). This snippet actually fetches Eliott’s sayHello property, and calls it right away.
You can see Eliott as a box of properties, some of which can be functions. They only exist within the box and have no meaning out of the box: what would age be? Whose age? Who’s saying hello?
Now some functions are defined at the global level: parseInt or isNaN for instance. These functions actually belong to the global box, named window (because legacy). You can also call them like that: window.parseInt(a, 10) or window.isNaN(a). Omitting window is allowed for brevity.
var eliott = {
name: 'Eliott',
age: 32,
sayHello: function () { console.log('Hello, I’m Eliott'); }
};
eliott.name; // access the `name` property
eliott.age; // access the `age` property
eliott.sayHello; // access the `sayHello` property
eliott.sayHello(); // access the `sayHello` property and calls the function
sayHello(eliott); // Reference error: `window.sayHello` is undefined!
Note: Some types (String, Number, Boolean, etc.) are not real objects but do have properties. That’s how you can fetch the length of a string ("hello".length) and reword stuff ("hello, Eliott".replace("Eliott", "Henry")).
Behaviour of these expressions is defined in ECMAScript grammar. You could read the specification to understand it thoroughly: ECMAScript2015 specification. However, as pointed out by Bergi, it's probably not the best resource for beginners because it doesn't explain anything, it just states how things are. Moreover I think it might be too difficult for you to be able to grasp concepts described in this specification because of the very formal language used.
Therefore I recommend to start with something way simpler, such as a very basic introduction to JavaScript: JavaScript Basics on MDN. MDN is a great resource.
But to answer your question just briefly:
str.length is accessing a property of the str object.
parseInt(str) is a function call
str.toString() is a call of a function which is a property of the str object. Such functions are usually named methods.
Functions and methods are in fact very similar but one of the differences (except for the obvious syntax difference) is that methods by default have context (this) set to refer to the object which they're part of. In this case inside of toString function this equals to str.
Note: Accessing a property (as in str.length) could in effect call a getter function but it depends on how the object is defined, and is in fact transparent for the user.
I would like to get the binary form of a number, e.g 6 -> "0110"
I've tried (js/toString ...) but no matter what syntax I use, the repl always returns "[object Window]". What does this mean?
I'm also confused because toString is part of goog.math.Integer, and yet when I try to use js/isOdd, part of the same library, it says it is not defined. I tried manually requiring it via (ns user (:require [goog.math.Integer :as int])), but it made no difference.
I'm also confused as to the difference between (.toString ...) and (js/toString ...).
Any help with the specific problem and/or the nuances of js functions in cljs would be most appreciated. Thanks!
You should use (.toString 6 2). Using (js/toString ...) amounts to toString(...) which you can try evaluating yourself in a typical javascript browser console. You'll see you'll also get an "object Window".
(js/thing) is used for referring to a javascript runtime symbol. In particular, if you've loaded code separate from your compiled clojurescript (e.g. loaded through a different script), you can refer to the loaded symbols using the js/... syntax. js/thing, in this case, will refer to thing in the top level scope of javascript.
For example, say you're using the ROT.js library which exposes its API through the ROT object. You can access its functions in clojurescript (assuming the library has been loaded), using js/ROT. Creating an instance of its Display object found in ROT.Display would then be accomplished using (js/ROT.Display. params).
Loaded Closure compatible code, on the other hand, is accessed depending on how they've been required in the namespace. In general, if you've loaded the goog.math library with (ns test (:require [goog.math :as math]), you can access everything under goog.math using (math/something).
The (.function object params) syntax is used for calling methods of a javacript object and would correspond to object.function(params). Remember that javascript objects are different from values and objects you create through pure clojurescript code. Use (.-property object), if you just want to get the value of that object's property instead. You can also lookup doto, .., and the threading macros ->, ->> for more ways to deal with javascript objects inside clojurescript. Most of the interop facilities provided for java in clojure holds for javascript/clojurescript. I also recommend reading http://www.spacjer.com/blog/2014/09/12/clojurescript-javascript-interop/.
As for the isOdd, that is an instance method of an instance of goog.math.Integer. First create an instance of that (e.g. (def e (new math/Integer ...)) and then you can call .isOdd on that instance. Look through the goog.math.Integer documentations to see which static properties and methods are accessible straight from the Integer scope.
This is a parser error, there are three ways to make this work, creating a var with the number and calling .toString on that, writing the number with an extra a dot or writing the number in parentheses.
If you try 6.toString(2) on a JavaScript console you will get this error:
SyntaxError: Unexpected token ILLEGAL
But this 6..toString(2) works. This is because the JavaScript parser expects a number followed by a dot to be a float literal. When you write 6. the parser expects the next character to be a number not t, when you write 6.. the first dot is parsed as part of the number (creating the number 6.0) and the second dot is parsed as a method call on the created number.
In ClojureScript the compiler knows about this "feature" of JavaScript so you can pass the 6 literal to toString:
cljs.user> (.toString 6 2)
"110"
cljs.user> (.toString 6. 2)
"110"
The ClojureScript compiler generates the correct code in both cases. In the first case it generates (6).toString(2) and in the second case it generates 6.0.toString(2).
(js/toString 6) is calling the toString defined on the window global object. No matter what you pass the result is always the same. You can check that calling by window.toString() in a JavaScript console.
(.toString target args) is calling the toString defined in the target object passing args as parameters of the method.
I wanted to be able to create an object that had it's own intrinsic value. That way I could use it in an expression as if it was a regular variable. It turned out to be quite easy - so easy I am wondering if I am missing something. All it seems to take is to make sure the object contains a method "valueOf". Like so:
var p = {
a: 12;
valueOf: function(){return this.a+12}
}
alert(p/3); // =8
It's probably a good idea to include a "toString" method too. What seems to be happening is that without the valueOf method, a reference to the object goes up the prototype chain until it finds the method on Object, which just returns "object Object". By providing a local one, the method can return anything.
It seems to work in all browsers that I tried.
It is really another way to provide a getter-like functionality. But a little better because getters can only be applied to properties of objects. This way you can use the object itself.
What do you think? Is this safe? Any pitfalls?
Well I started using this pattern and found one issue. If you create an object p like the one above, you have to guess how the interpreter will view a reference to the object.
For example, if P is used in arithmetic expression, it calls the object's valueOf() method to get its value. But when you try to access a property of p such as p.a, then it treats p as an object and retrieves the property as you expect.
In a getter, by contrast, accessing p.a when there is a getter on p would first run the getter and then try to get the property 'a' of the result. Subtly different, but important.
It's all quite correct and seems to "guess" correctly what to do. But using the pattern does rely on knowing this behavior, which AFAIK is not documented anywhere.
In Ruby, you can capture a call to a method which is missing and define it on the fly.
What I wanna accomplish in JavaScript is to have an object with no methods. I want a missing method to be translated into a call to emit():
app.isReady() -> app.emit("isReady")
soldier.kills() -> soldier.emit("kills")
I think it's better to capture the missing method error and run emit(methodName) rather than defining all methods (from a fixed list) at runtime. That way we don't have performance overhead if there are hundreds or thousands of events for an object.
What is the best way to do this?
UPDATE: This is an API design so I rather stay out of:
try {
app.isReady()
} catch(e) {
...
}
I want to know how I can accomplish this behind the scenes so the users can use methods as usual.
In that way we don't have a performance overhead if there are hundreds/thousands of events for an object.
I think it's a massive misconception to think the performance overhead of adding methods to an object is smaller then the performance overhead of converting method invocations into emit calls.
However you cannot implement this feature in ES5
One could however implement this using Harmony proxies.
I recommend looking at simulating __noSuchMethod__.
I believe ES6 proxies are experimental and can be turned on in V8 so you could use them with node.js today.
It's not possible to do that consistently at this stage, unless you can guarantee your app will only run on Mozilla, in which case noSuchMethod is what you're after.
As far as I know, none of the other browsers implement this yet.
Use a RegExp test on the function pointer by using the following process:
pass the object literal as an argument
pass the name of the default method as a string
pass the name of the fallback method as a string
using subscript notation to dereference the function pointer
use a regexp to check the type against the name function
if it succeeds, call the default using subscript notation
if it fails, call the fallback using subscript notation
For example:
/* Define mapping */
var app = {"emit": emit};
/* Define interface */
function emit(){}
function \u1000missing(object, method, fallback)
{
/* Existence check */
if (/function/.test(object[method]) )
{
object[method]();
}
/* reify */
else
{
object[fallback](method)
}
}
\u1000missing(app,"isReady","emit")
You might ask why you'd ever want to use subscript notation. Subscript notation allows for dynamic creation of properties and methods. So if you ever do any sort of metaprogramming, you'll most likely be using the subscript notation.
References
Are there equivalents to Ruby's method_missing in other languages?
JSPerf: Method Missing
Handling a call to a missing method in different languages
jQuery is a Monad
Message forwarding in Smalltalk
Performance from Aligning Smalltalk and JavaScript Classes
Can Perl be Smalltalk?
How learning Smalltalk can make you a better developer
Reflective Facilities in Smalltalk-80
12.1. QMetaObject - The Meta Object Pattern
Object Programming and Object-Oriented Programming
Things you should know about JavaScript
Respond to an Unknown Method Call
Creating Thread-Safe Components With OnMissingMethod()
On the design of the ECMAScript Reflection API (pdf)
Does Not Understand
I've create a Node.js package to deal with your situation. It's called auto-object.
Here's a glance:
const myObject = autoObject.createObject(function(name) {
if(name.startsWith("say")) {
return function() {
return name.substr(3);
}
}
return name;
});
myObject.foo; ///< "foo"
myObject.sayFoo(); ///< "Foo"
myObject.sayBar(); ///< "Bar"
What's more, this works with class too.