Is JavaScript function.bind() supported in google sheets? - javascript

Here a simple code i'm trying to run in google sheets script.
The purpose is supplying the foreach callback function additional parameters.
function print(str, num) {
Logger.log(str + ": " + num);
}
function test()
{
var array = [1,2,3];
var str = "Stam";
//This line has an exception
// TypeError: Cannot convert null to an object
array.forEach(print.bind(null, str));
}
test();
this code is based on the solution described here.
I know there are other solutions, though i want to understand why this one does not work.
I wounder maybe it is not supported with google sheets.

How about this answer? Please think of this as just one of several possible answers.
At Javascript, when null of bind(null, str) is used, this is used. At Google Apps Script, when null is used for bind(null, str), an error occurs like "Cannot convert null to an object". I think that this might be the specification of Google side. I'm not sure whether this is modified in the future update. So as the current workaround, how about using this instead of null? Or if you want to use bind(null, str) like null under the strict mode, how about using {} instead of null like bind({}, str)?
By the way, I think that test(); at the last line of your script can be removed. Because in your case, when test() is run at the script editor, test() is run 2 times by test(); at the last line. test(); at the last line is run as the global.
From above situation, when your script is modified, how about the following modification?
Modified script:
function print(str, num) {
Logger.log(str + ": " + num);
}
function test() {
var array = [1,2,3];
var str = "Stam";
array.forEach(print.bind(this, str));
}
or you can also modify test() of your script as follows. The following test() retrieves the same result with above one.
function test() {
var array = [1,2,3];
var str = "Stam";
array.forEach(function(e) {print(str, e)});
}
Result:
When you run test() at the script editor, you can see the following result at the log.
Stam: 1
Stam: 2
Stam: 3
Reference:
Function.prototype.bind()
If I misunderstood your question and this was not the direction you want, I apologize.

Related

a javascript function does not work on the console

I am following a tutorial to learn javascript and I am trying to run my function in the console to see the output like this
and this is my code
var output = [];
var count = 1;
function fizzBuzz() {
output.Push(count);
count++;
console.log(output);
}
but instead, it shows like this in the console
so what is the reason for this? Could you help me please
also I am a very beginner
To call a function you have to end with (), otherwise it just shows you what the actual function is as it would a variable, so fizzbuzz gives you the content of the function, fizzbuzz() executes the function.
As a side note, the p in push should be lowercase.

Give eval a value in JavaScript

very basic JavaScript programmer here!
I was busy on some code with variables that look like this:
blocktype1;
blocktype2;
blocktype3;
blocktype4;
... //everything between blocktype4 and blocktype70, the three dots are not actual code!
blocktype70;
Now I was using eval() in a function where a value was given to one of the blocktype variables. The blocktype depended on the variable "number".
This is what I had for that part:
eval("blocktype" + number) = 3
What I want is, say "number" is 27, then I want the variable blocktype27 to get a value of 3.
When I check the console it says:
ReferenceError: Invalid left-hand side in assignment
Could anyone possibly help me?
I would prefer just vanilla JavaScript and still the use of eval.
Thank you for your time!
The 'correct' solution would probably be to use an Array which is ideal for sequences and are accessible by index.
var number = 1;
var val = 3;
var blocktype = []; // so clean
blocktype[number] = val;
However, properties can be accessed as with the bracket notation as well. This assumes the variables are in global scope and are thus properties of the global (window) object.
var blocktype1; // .. etc
window["blocktype" + number] = val;
The problem with the eval is that is effectively the same as doing f() = 3 which does not make sense: only variables/properties can be assigned to1.
However eval is a built-in function and the results of a function cannot be assigned to, per the error message. It could be written as
var blocktype1; // .. etc (see dandavis' comment)
eval("blocktype" + number + " = " + val);
// What is actually eval'd is:
// eval("blocktype1 = 3")
which quickly exposes a flaw with eval. If val was the string "Hello world!" with would result in eval("blocktype1 = Hello world!") which is clearly invalid.
1 For the gritty: the left-hand side of an assignment has to be a Reference Specification Type, which is a more wordy way of describining the above behavior. (It is not possible for a JavaScript function to return a RST, although it could technically be done for vendor host objects.)
Feel free not to accept this, since it's specifically not using eval(), but:
You can allocate an array of size 71 like so:
var blocktype = new Array(71);
(your number values apparently start at 1, so we'll have to ignore the first element, blocktype[0], and leave room for blocktype[70], the 71st)
You can now assign elements like this:
blocktype[number] = 3;
and use them like so:
alert( blocktype[number] );

NewBee on NodeJs or PhantomJS: Function names on Javascript

I am just learning NodeJS and/or PhantonJS.
As a programmer with a lot of C experience, I do not like the way NodeJs code is written and find it a bit messy/unreadable. (Sorry if I ruffled any feathers)
In spirit of cleaning up the code, I was trying to do this and found a block.
In C or C++, we should be able to pass a function by name but in NodeJS/PhantomJS it does not seem to work.
Am I doing somthing wrong ?
Can someone explain to me how this is looked at by the Javascript interpreter ?
var page = require('webpage').create();
var printS = function (s) {
console.log(s);
phantom.exit();
}
/* This works */
page.open('http://net.tutsplus.com', function (s) {
console.log(s);
phantom.exit();
});
/* This does not work
page.open('http://net.tutsplus.com', printS(status));
*/
/*But this works
page.open('http://net.tutsplus.com', function (s) { printS(s);} );
*/
page.open('http://net.tutsplus.com', printS(status));
fails because you're not passing the function but rather the result of invoking the function on status. If you want to pass the function, you'd do it this way
page.open('http://net.tutsplus.com', printS);
I thought it might be helpful to have a more extensive explanation. Let's start simple:
In JavaScript, we have values and variables. Variables are containers for values. Almost everywhere where we can use values, we can use variables.
In JavaScript source code, we express values through literals, e.g. the number literal 42. We can directly pass that value to a function:
f(42);
Additionally, instead of passing the value directly, we can pass a variable to the function:
var v = 42;
f(v);
That is, we can substitute values with variables.
Lets consider
var printS = function() { ... };
This clearly is a variable whose value is a function. If we'd directly pass that value to a function (i.e. we pass a function to a function), it would look like:
f(function() { ... }); // similar to f(42)
That's exactly what you have in your first case:
page.open('http://net.tutsplus.com', function (s) {
// ...
});
Since we know that we can replace values with variables, we can just substitute function() { ... } with printS:
var printS = function() { ... }; // similar to var v = 42;
f(printS); // similar to f(v)
So your example would become
page.open('http://net.tutsplus.com', printS);
What is wrong with
page.open('http://net.tutsplus.com', printS(status));
then?
Notice that you added additional characters after printS, namely (status). They don't appear in the your first example where you inlined the function:
page.open('http://net.tutsplus.com', function (s) {
// ...
});
There is no (status) here. Hence these two constructs cannot be not equivalent.
page.open accepts a function value as second argument, but printS(status) doesn't evaluate to the function printS, it calls the function printS and passes the return value to page.open.
Why does
page.open('http://net.tutsplus.com', function (s) { printS(s);} );
work?
Lets remove the content and the argument of the function, and it becomes:
page.open('http://net.tutsplus.com', function () { ... } );
That looks exactly like one of the examples above. function () { ... }, is a function literal, so to speak. It creates a function value. There are no (...) after it which would call the function.
This doesn't work as you hope because page.open wants a function as its second argument... this callback pattern is very common in JavaScript. In your doesn't-work example, printS is being called with status as its argument, and it returns undefined. As undefined is not a function, it doesn't behave as you wish.
In your browser console or the node repl:
> printS = function (s) { console.log(s); };
function (s) { console.log(s); }
> typeof printS('hi');
hi
"undefined"
> typeof function (s) { printS(s); };
"function"
Another thing to know about JavaScript is that its dynamic typing and fairly generous type coercion can result in baffling behavior with no helpful errors to point you towards the root cause of your problem. A debugger or copious use of console.log() is frequently helpful in understanding these sort of problems.

JavaScript: alert object name as a string

I'm trying to alert any JavaScript object as a string, in a function. This means if the parameter given to the function is window.document, the actual object, it should alert "window.document" (without quotes) as a literal string.
The following calls...
example(window);
example(window.document);
example(document.getElementById('something'));
...calling this function...
function example(o) {/* A little help here please? */}
...should output the following strings...
window
window.document
document.getElementById('something')
I've attempted to do this with combinations of toString() and eval() among some more miscellaneous shots in the dark without success.
No need insane backwards compatibility, newer ECMAScript / JavaScript features/functions are fine. Feel free to inquire for clarifications though the goal should be pretty straight forward.
This is not possible to do in a self contained script.
If using a preprocessor would be an option, then you could write one which converts example(whatever) into example('whatever'). Other than that I'm afraid you're out of luck.
The first problem is that objects don't have names.
The second problem is that from your examples, you're not really wanting to print the (nonexistent) name of an object, you want to print the expression that evaluated into a reference to an object. That's what you're trying to do in this example:
example(document.getElementById('something'));
For that to print document.getElementById('something'), JavaScript would have had to keep the actual text of that expression somewhere that it would make available to you. But it doesn't do that. It merely evaluates the parsed and compiled expression without reference to the original text of the expression.
If you were willing to quote the argument to example(), then of course it would be trivial:
example( "document.getElementById('something')" );
Obviously in this case you could either print the string directly, or eval() it to get the result of the expression.
OTOH, if you want to try a real hack, here's a trick you could use in some very limited circumstances:
function example( value ) {
var code = arguments.callee.caller.toString();
var match = code.match( /example\s*\(\s*(.*)\s*\)/ );
console.log( match && match[1] );
}
function test() {
var a = (1);
example( document.getElementById('body') );
var b = (2);
}
test();
This will print what you wanted:
document.getElementById('body')
(The assignments to a and b in the test() function are just there to verify that the regular expression isn't picking up too much code.)
But this will fail if there's more than one call to example() in the calling function, or if that call is split across more than one line. Also, arguments.callee.caller has been deprecated for some time but is still supported by most browsers as long as you're not in strict mode. I suppose this hack could be useful for some kind of debugging purposes though.
Don't know why you need this, but you can try walking the object tree recursively and compare its nodes with your argument:
function objectName(x) {
function search(x, context, path) {
if(x === context)
return path;
if(typeof context != "object" || seen.indexOf(context) >= 0)
return;
seen.push(context);
for(var p in context) {
var q = search(x, context[p], path + "." + p);
if(q)
return q;
}
}
var seen = [];
return search(x, window, "window");
}
Example:
console.log(objectName(document.body))
prints for me
window.document.activeElement

alert the object

I am setting an object like this
n.name = n.name.join(String.fromCharCode(255));
n.description = n.description.join(String.fromCharCode(255));
I want to be able to alert(n); but it tells me [Object]
is there a way to alert complete object?
thanks
Javascript supports adding a toString() function to your objects. This will get called when you alert your object. For example:
n.toString = function(){
return this.name + '\n' + this.description;
}
then alert(n); will display whatever content your function specifies.
I was asking the same kind of question as Autolycus today. I'm using jqGrid and I wanted to see what the object it created actually was. I didn't create the object and I wanted to see what it looked like. I know it's probably old school, but I still use alerts in javascript for some of my debugging (though I agree FireFox & Firebug are the way to go for most things).
I found an answer to what I was looking for here: http://javascript.internet.com/debug-guide.html, which is unbelievably old.
But I tweaked it to give me what I needed and since I think it answers Autolycus's question in a new way and I think someone else might be looking here, like me, for this someday, here it is:
obj = n;
var temp = "";
for (x in obj) {
temp += x + ": " + obj[x] + "\n";
}
alert (temp);
I apologize in advance if answering an old question is breaking some kind of rule.
all best,
ember
I like the var_dump in php, so I often use a function like this to dump variables
function var_dump(object, returnString)
{
var returning = '';
for(var element in object)
{
var elem = object[element];
if(typeof elem == 'object')
{
elem = var_dump(object[element], true);
}
returning += element + ': ' + elem + '\n';
}
if(returning == '')
{
returning = 'Empty object';
}
if(returnString === true)
{
return returning;
}
alert(returning);
}
There are a couple of alternatives:
1. Use http://www.gscottolson.com/blackbirdjs/
2. Use console.log() that comes with Firebug, but requires Firefox (even if you only target only IEs, it's still wise to use Firefox and Firebug as aprt of testing of your web app development)
It depends what you mean by alerting the complete object.
You can't really just output every object as a string and have it make sense. To define how an object will display itself as a string we use the .toString(); method.
So try alert(n.toString()); and see if that will give you what you want. If the object is your own, then define the toString(); and have it return a string of the parameters and fields that you want to output.
Something like...
alert(n.name);
...I think is what you want.
If you are trying to debug, you would be better suited to using FireFox/Firebug instead of inserting a load of alerts();

Categories