Evaluation of nested function in JS - javascript

I'm new to JS, I've seen the code with exact the same logic (except my newbie errors) :
function foo(a){
var t = 1;
function(b){
console.log(a+b+(++t));
}
}
bar = foo(5);
bar(6);
bar(6);
what is output of first and second call of bar function going to be ?

H,
Seems like too many problems with your code.
maybe you meant to do something like this:
function foo(a){
var t = 1;
return function(b){
console.log(a+b+(++t));
}
}
var new1 = foo(5);
new1(6);// will output 13
new1(6);// will output 14
anyway,
you can try it on online REPL to test the code yourself.
ONLINE JS REPL
or any modern browser dev tools (F12 on chrome -> console for example)

Related

How to bind console.log to another function call so I can see line number of the script in console where it is called?

My code works but with additional parenthesis like myfunction()();. It should execute with single parenthesis just like normal e.g myfunction();.
I'm building console.time(); console.timeEnd(); polyfill for browsers (e.g <IE10) which do not have native built-in. Note: I have bind() polyfill in-case you think <IE10 does not have it.
Here is my code in "polyfill.js file".
(function() {
'use strict';
var console=window.console, timers={};
if (!console.time) {
console.time = function(name) {
var datenow = Date.now();
name = name? name: 'default';
if (timers[name]) {
console.warn('Timer "'+name+'" already exists.');
}
else timers[name] = datenow;
};
console.timeEnd = function(name) {
var datenow = Date.now();
name = name? name: 'default';
if (!timers[name]) {
console.warn('Timer "'+name+'" does not exists.');
}
else {
var endt = datenow - timers[name];
delete timers[name];
//below is the line where some changes are needed, But I don't know how.
return window.console.log.bind(window.console, name+ ': ' +endt+ 'ms');
}
};
}
}());
Now in another file "main.js file", when I use console.time(); console.timeEnd();, it should log code-line-number of this file in browser console (not the line-number of polyfill.js file). Of-course it works but notice additional parenthesis "()()" below which is not cool.
console.time();
//any code for performance test goes here.
console.timeEnd()(); //Note here "()()". It should be single "()"
I have consulted these 2 stackoverflow questions, but couldn't come up with the right answer.
Wrapping a wrapper of console log with correct file/line number?
A proper wrapper for console.log with correct line number?
I also checked new Error().stack; as an option, but it is also not supported in those browser for which I'm building my polyfill.
Note: If anyone can suggest a solution with eval();, you can. It is also acceptable for me.
There is in fact a function for that called console.trace, which you can read more about in the MDN page.
What it does is print the entire stack trace to the line where it has been called from.
So, for example, running the next code:
function firstFunc() {
secondFunc();
}
function secondFunc() {
console.trace('I was called here!');
}
console.log('Calling firstFunc:');
firstFunc();
will print out this output in the console:
Calling firstFunc:
I was called here!
secondFunc # VM141:6
firstFunc # VM141:2
(anonymous) # VM141:10 // Internal browser trace
Notice that in the given output, all functions are being called and defined in the Chrome console, hence the # VM141:. Generally, it prints the file instead of VM. So, had it been located in an index.js file, it would look like this:
Calling firstFunc:
I was called here!
secondFunc # index.js:8
Compatibility Note
The above method works for any sane browser, and IE11+. That is due to the implementation of console.trace only in IE11.
However, per OP's request, I can think of a creative way to support IE10, and that is by using the Error.prototype.stack property.
Now, of course, as MDN itself mentions it, it's a non-standard feature that should not be used in production, but neither is supporting IE6.
By creating an Error instance and then printing its stack, you can achieve a similar result.
const sumWithTrace = (num1, num2) => {
console.log(new Error().stack); // Creating a new error for its stack property
return num1 + num2;
};
sumWithTrace(1, 5); // returns 6 and prints trace in console

How to show result of console.timeEnd() in react native android app?

I have installed package and import it like this:
import 'react-native-console-time-polyfill';
and have function like this:
search = () => {
let s = this.state.file.toLowerCase();
let p = this.state.search.toLowerCase();
console.time('t');
let result = kmp.findAll(s, p);
let time = console.timeEnd('t');
alert(time);
};
Why the result in alert returned as "undefined"?
My expectation is result time for processing function is show up at alert popup. Search is a function onpress at button.
Sorry my bad english, hopefully you guys understand my question ^^
The way the library you are using is written, it only outputs the resulting time to console, it does not return it. Because of that, while you can see it in debug console, you will always receive undefined from both .time() and .timeEnd() functions. This is also the same for browsers, and you can actually test it in your Javascript console.
However the library's code seems to be short, you can actually add the functionality. If you add return delta.toFixed(3); at the end of the .timeEnd() function (21st line in the index.js) you can get the result you want.

Is there a way to capture JavaScript console output so I can reference it elsewhere?

If possible, I'd like to display JavaScript console output in a log window that I developed for my application. There's a lot of solutions for posting messages to the console, but I couldn't find any that let you capture the console output.
I'm not even sure if this is possible. Is console output stored in an object at some level of the DOM?
Thanks in advance for any hints/suggestions.
you can overwrite the console function(s) that you want to use
if(window.console && console.log){
console.log = function(){
var args = arguments;
/* process args to your app */
}
}
You can overload console.log with a function like the one below, and that function can save the messages in whatever form you'd like, as well as outputting to the console. This particular implementation is a little simplistic though as it only takes one argument, bu can google other examples pretty easily.
var myLog = [];
console.log = function (text) {
console.info(text)
myLog.push(text);
}
console.log("abc")
console.info(myLog);

angularjs $log - show line number

I use angularjs $log in chrome, but it shows the line like: angular.js:9037. I want to show the line number where I call this method. (Show my js name and the correct line). Does anyone know how to do it? Angular doesn't have this feature.
In Chrome there is a feature called Blackboxing.
You can use it to exclude / bypass (library) sources from your debug sessions or development workflow.
So if you blackbox angular the internals of the $log service get bypassed and the console prints the correct line number!
https://developer.chrome.com/devtools/docs/blackboxing
You can access it by applying a decorator to the $log service:
module.config(function logConfig($provide, $logProvider) {
$provide.decorator('$log', function ($delegate) {
var originalFns = {};
// Store the original log functions
angular.forEach($delegate, function (originalFunction, functionName) {
originalFns[functionName] = originalFunction;
});
var functionsToDecorate = ['debug', 'warn'];
// Apply the decorations
angular.forEach(functionsToDecorate, function (functionName) {
$delegate[functionName] = logDecorator(originalFns[functionName]);
});
return $delegate;
});
function logDecorator(fn) {
return function () {
var args = [].slice.call(arguments);
// Insert a separator between the existing log message(s) and what we're adding.
args.push(' - ');
// Use (instance of Error)'s stack to get the current line.
var stack = (new Error()).stack.split('\n').slice(1);
// Throw away the first item because it is the `$log.fn()` function,
// but we want the code that called `$log.fn()`.
stack.shift();
// We only want the top line, thanks.
stack = stack.slice(1, 2);
// Put it on the args stack.
args.push(stack);
// Call the original function with the new args.
fn.apply(fn, args);
};
}
});
I do this as an includable module, but I believe it could be done within the app's .config() as well.
I built this (along with some additional logic) by gluing together a number of different sources online; I'm usually really good at keeping references to them, but I guess I didn't when I built this, so unfortunately I can't reference my inspiration. If someone replies with it, I'll put it in here.
NOTE 1:
this is a slightly stripped-down version of what I actually use, so you'll have to double-check the logDecorator()s stack
pushy-shifty magic, though it should work as presented.
NOTE B:
MDN says that Error.prototype.stack is non-standard (requires IE10 and may not be supported on many mobile browsers) so you might want to look at augmenting this with something like stacktracejs to get the stack itself.
I have combined a couple of solutions from this page, as well others to build a simple demo in JSFiddle - to demonstrate use of $log service, enhancing it with decorators to add line number (line number from where $log call was made). I have also made a slightly more comprehensive solution in Plunker, demonstrating the use of $log service, enhancing it with decorators to add line number, caller file name and instance name. Hopefully, this will be useful to others.
JSFiddle URL - https://jsfiddle.net/abhatia/6qnz0frh/
This fiddle has been tested with following browsers:
IE 11 - (JSFiddle Javascript's first line's number is 72).
Firefox 46.0.1 - (JSFiddle Javascript's first line's number is 72).
Chrome 50.0.2661.94 m - (JSFiddle Javscript's first line's number is 71).
The results are good. But, please note that line number in Chrome will be off by 1, when compared to FF or IE, i.e. because JSFiddle's javascript's code first line number differs between FF/IE and Chrome, as listed above.
Plunker URL - https://embed.plnkr.co/YcfJ7V/
This plunk demonstrates the concept really well, with detailed explanation and also provides the console output with Angular's official example of default $log service, so the two could be contrasted. Plunk has also been tested with browsers listed above.
Below screenshot is the console output from the Plunk example above. There are 3 highlighted areas:
Red box shows console output using default $log service. $log functions invoked from controller.
Blue box shows console output using extended $log service. $log functions invoked from controller. You can see how the script name and line numbers are shown, as well as the controller name (used when instantiating $log).
Orange box contrasts console output from default and extend $log services.
This will become very clear when you review the Plunk code.
Here is the getLineNumber function used in JSFiddle (slightly enhanced version is used Plunker example to return caller file name):
function getLineNumber(newErr, sliceIndex1, sliceIndex2)
{
var lineNumber = -1;
var lineLocation;
var stack = newErr.stack.split('\n').slice(2);
if (navigator.userAgent.indexOf("Chrome") > -1) {
stack.shift();
}
stack = stack.slice(sliceIndex1, sliceIndex2);
var stackInString = stack + '';
var splitStack;
if (navigator.userAgent.indexOf("Chrome") > -1) {
splitStack = stackInString.split(" ");
}
else {
splitStack = stackInString.split("#");
}
lineLocation = splitStack[splitStack.length - 1];
//console.log(lineLocation);
lineNumber = lineLocation.split(":")[2];
return lineNumber;
}
The line number comes from the runtime. You can not set it in general case.
But not all is lost. In places where the line number is really important you can use a different call.
Remember to inject the $window and then:
$window.console.log("test1");
You loose some things this way like formatting, cross browsers filler code etc, but you do get line numbers correct for free without any per runtime specific code to do so.
Close to floatingLomas's answer
module.config(function($logProvider, $provide){
$provide.decorator('$log', function ($delegate) {
$delegate.info = function () {
var args = [].slice.call(arguments);
if (window.console && window.console.table)
console.trace(args[0], args[1]);
else
$delegate.log(null, args)
};
return $delegate;
});
})
Usually second # line is what you need, in this case 90618
I have used floatingLomas solution with some tweaks as it does not quite work on FF, the stack is slightly different. And phantomjs like IE does not support Error.stack and blows up.
The log location is clickable in chrome but not in ff.
app.config(function logConfig($provide, $logProvider) {
$provide.decorator('$log', function ($delegate) {
var originalFns = {};
// Store the original log functions
angular.forEach($delegate, function (originalFunction, functionName) {
originalFns[functionName] = originalFunction;
});
var functionsToDecorate = ['debug', 'warn'];
// Apply the decorations
angular.forEach(functionsToDecorate, function (functionName) {
$delegate[functionName] = logDecorator(originalFns[functionName]);
});
return $delegate;
});
function logDecorator(fn) {
return function () {
var args = [].slice.call(arguments);
// Insert a separator between the existing log message(s) and what we're adding.
args.push(' - ');
// Use (instance of Error)'s stack to get the current line.
var newErr = new Error();
// phantomjs does not support Error.stack and falls over so we will skip it
if (typeof newErr.stack !== 'undefined') {
var stack = newErr.stack.split('\n').slice(1);
if (navigator.userAgent.indexOf("Chrome") > -1) {
stack.shift();
}
stack = stack.slice(0, 1);
var stackInString = stack + '';
var splitStack;
if (navigator.userAgent.indexOf("Chrome") > -1) {
splitStack = stackInString.split(" ");
} else {
splitStack = stackInString.split("#");
}
var lineLocation = splitStack[splitStack.length - 1];
// Put it on the args stack.
args.push(lineLocation);
// Call the original function with the new args.
fn.apply(fn, args);
}
};
}
I use chrome version 65.0.3325.181
in my case,
go to menu, settings -> blackboxing
check blackbox content scripts
add blockbox pattern angular.js

Disable editing of javascript from chrome console?

So, I just noticed today that you can apparently run javascript in the chrome console. I had no idea you could do this. It's actually really cool.
In my rails app, I have an external javascript page. Some of the variables on that page I would like to be global so that all the functions in the JS file can access them. for example I have a map, and I would like the map object to be global in the javascript file because that way all my functions access the one map variable instead of creating their own, and I can break complex operations down into smaller functions.
This is all well and good I know how to do that and it's working perfectly. My problem now, can I protect the variables from outside? For example you can change the values of all the javascript class variables from the chrome console.. as well methods from for example the map are accessible and excecutable.. I have locked the map settings on one of the pages so it is not zoomable or movable, however from the console I can simply say map.setZoom(11) and the map will zoom to 11.. I can type map.dragable = true and bam u can drag the map.. I don't like this really..
It's not too terribly bad yet like the user enabling map drag and zoom isnt the worst thing in the world.. but still I'd like to disable this. Any ideas?
EDIT
Thanks all for the answers and comments. I guess I will just resort to not putting anything that can be turned malicious into my javascript, and do thing like pass my map variable to functions where necessary to slow people down.
You can use an immediately-invoked function (IIFE) expression to prevent your variables and functions from being exposed in the global scope:
var a = 10;
(function() {
var b = 20;
})();
window.a lets you view and modify a, but you cannot do that with b:
Try it out here
I'm more than sure that there's a way to edit b with Inspector, but I haven't taken the time to figure it out. Don't waste your time trying to prevent your users from modifying code that they can view.
You can't. Even if you wrap them into anonymous functions, user can get to them through debugger. As last resort he can simply intercept your traffic to his own machine and replace your JavaScript with something else.
Bottom line: JavaScript in browser is client-side. Client can do whatever he pleases with it.
Try doing something like this:
(function(){
//All of your current code
})();
One thing to still be aware of - Chrome developer tools also lets you edit the javascript (not the javascript file on the server, just currently running copy.) Go to Chrome Dev Tools->Sources and you can edit the javascript files.
You can't. Your saying you need to define your map globally, this means it's accessible for everyone.
You could define your map in a different scope and then only define the "public" things:
(function() {
var map = new Map();
window.myMap = {
goTo: function(lat, lng) {
map.goTo(lat, lng);
}
};
})();
Depending on your architecture, there are a few ways to accomplish this. Use this method to create a reusable component that has public and private properties:
var protectedScope = function () {
var protected_var = 'protected';
this.showProtected = function () {
return protected_var;
}
this.public = 'public';
};
var myObject = new protectedScope();
console.log('Public var: '+myObject.public); // outputs "public"
console.log('Protected via accessor: '+myObject.showProtected ()); // outputs "private"
console.log('Protected var: '+myObject.protected); // outputs undefined
Any variable or function declared with a var keyword will be, in effect, private. Any variable or function that uses the this.name mechanism will be "public".
Understand that this structure is not truly public or private, such concepts are not a part of the language. There are still ways to get at those variables, and one can always view source. Just be clear; this is a code organization concept rather than a security concept. Chrome has had this developer console for a while, and other major user agents are moving to include similar tools (or already have done so). There are also tools like Firebug which allow a user full access to your javascript runtime environment. This isn't a realm that the developer can control at all.
Try it here: http://jsfiddle.net/cf2kS/
More Reading
"Private Members in JavaScript" by Douglas Crockford* - http://www.crockford.com/javascript/private.html
"OOP in JS, Part 1 : Public/Private Variables and Methods" on http://phrogz.net - http://phrogz.net/JS/classes/OOPinJS.html
Javascript Object Management on MDN - https://developer.mozilla.org/en-US/docs/XUL_School/JavaScript_Object_Management
Closures on MDN - https://developer.mozilla.org/en-US/docs/JavaScript/Guide/Closures
Object.defineProperty(map, 'zoom', {value:1});
or
Object.defineProperty(map, 'zoom',{
set: function(){console.warn('Access denied!');},
get: function(){return 1;}
});
demo
or
Object.defineProperty(Object.prototype, 'protect', {
value: function(ignore){
var childObjects = [], ignore = ignore || [];
ignore.push(this);
if(this instanceof MimeType)return; //Chrome Fix //window.clientInformation.mimeTypes[0].enabledPlugin[0] !== window.clientInformation.mimeTypes[0]
for(var prop in this){
if(typeof this[prop] === "unknown")continue; //IE fix
if(this[prop] instanceof Object){
var skip = false;
for(var i in ignore)
if(ignore[i]===this[prop]){
skip = true;
break;
}
if(!skip)childObjects.push(prop);
}
var d = Object.getOwnPropertyDescriptor(this, prop);
if(!d || !d.configurable || !d.writable)continue;
var that = this;
(function(){
var temp = that[prop];
delete that[prop];
Object.defineProperty(that, prop,{
set: function(){console.warn('Access denied!');},
get: function(){return temp;}
});
})();
}
for(var i = 0;i<childObjects.length;i++)
this[childObjects[i]].protect(ignore);
}
});
this.onload=function(){this.protect();} //example
demo

Categories

Resources