So what I am trying to do is as take a javascript code as input from user and return him the result. Right now I am executing the code submitted by user just using eval (with some safety checks). But I understand this is highly unreliable. So what I want to achieve is run this in sandbox environment safely and return the result to user.
E.g
Input:
var a =[1,2,3];
a.map(n => n*2);
Output:
[2,4,6]
I tried using vm in node but I don't really understand how to get the final result from it.
I tried using vm in node but I don't really understand how to get the final result from it.
Many vm module functions, like vm.runInNewContext(), will return the result of the last statement in the string, similar to eval().
var vm = require('vm');
var script = 'var a = [1, 2, 3]; a.map(n => n * 2);';
var sandbox = {};
var result = vm.runInNewContext(script, sandbox);
console.log(sandbox); // { a: [1, 2, 3] }
console.log(result); // [2, 4, 6]
An example of capturing the result is given in the description for vm.runInThisContext()
Related
Original code in JS:
// applying crossover
for (let i = cxpoint1; i < cxpoint2; i++) {
let temp1 = ind1[i]
let temp2 = ind2[i]
ind1[i] = temp2
ind1[p1[temp2]] = temp1
ind2[i] = temp1
ind2[p2[temp1]] = temp2
return [ind1, ind2]
New to JS and wondering what is happening on this line:
ind1[p1[temp2]] = temp1
Trying to understand so I can make an equivalent function in Python.
I understand the assignment, however obviously in Python you cannot use double brackets as shown on the line above. If someone could tell me the concept, I should be able to apply it to my situation.
Thanks in advance.
To fully understand the code one would need to know how the arrays p1 and p2 look like, but I assume they are integer-arrays. You select an integer from that array in the inner statement that then is the index for the outer statement.
It works exactly the same in python:
ind1 = [1, 2, 3, 4, 5]
p1 = [3, 1, 2]
print(ind1[p1[0]])
# -> 4
In this example the inner statement resolves to 3 (first element in the p1-list) and the outer statement then resolves to 4 (fourth element in the ind1-list.
There's nothing magical going on here.
ind1[p1[temp2]]
p1[temp2] resolves to some value, let's call it a. So the expression then becomes ind1[a].
var nums = [1,2,3,5,6,3];
nums = nums.join('')
// I want to replace all occurrences of 3 in nums with an empty string.
// this code works
nums.slice(0).replace(/3/g,''); => [1,2,5,6];
// this code doesn't work, because I replaced 3 with a variable
nums.slice(0).replace(/nums[2]/g, ''); => [1,2,3,5,6,3];
whenever I use an actual character, it works but when I replace it with a variable like (nums[2]), it doesn't work and just returns the same array. is there something I'm missing?
I will shorten up your code a little bit so it doesn't cause too much confusion to you.
Also, you can avoid the slice method since strings by default are immutable and what that means is that every time you execute the replace method or any other string method it will return a brand new string.
var numbersArray = [1, 2, 3, 5, 6, 3];
var numbersString = numbersArray.join(''); // => '1235653'
var numbersWithoutThrees = numbersString.replace(/3/g, ''); // => '1256'
Great so far! The replace method accepts as an argument a RegExp or a string.
For example: numbersString.replace(/3/g, ''); we're using the /3/g RegExp that means find all the '3' occurrences due to the g flag, since there is a '3' is going to be replace for the empty string'' defined in the second parameter in the repace.
But what about the /numbersString[2]/g? Let's check it out:
var result = numbersString.replace(/numbersString[2]/g, ''); // => '123563'
It seems is not replacing anything and that's because there's no 'numbersString[2]' string inside '123563'.
If we want to replace the third element (numberSring[2]) you can do it by replacing the element in that position in the numbersArray and generating a new string by using join once again.
numbersArray[2] = ''; // => [1, 2, "", 5, 6, 3]
numbersString = numbersArray.join(''); // => '12563'
And there it's the result you now don't have that third element on your numbersString variable.
I hope that helps!
Is it possible to emulate the code below, in JavaScript?
var ref = new Reference();
var arr = [1, 2, ref];
ref.overwrite(3);
console.log(arr); // output: [1,2,3]
This code places a ref inside an array, then overwrites it, completely replacing its occurrence by 3. We could do something similar by storing the parent object and the index:
var arr = [1, 2, null];
var ref = {object: arr, index: 2};
ref.object[ref.index] = 3;
console.log(arr); // output: [1, 2, 3]
But this is not the same thing, since ref must keep track of all the parent objects where it is used. I'm interested in using ref as a placeholder, storing it in multiple places and then replacing all occurrences by something else, without keeping track of where it was used. We could also "almost" do this as such:
var ref = {value: null};
var arr = [1, 2, ref];
ref.value = 3;
console.log(arr); // output: [1, 2, {value: 3}]
But this doesn't completely get rid of the wrapping object.
No, JavaScript does not have references or pointers as values. You always need some wrapper object (which you can mutate however you want, but not replace), it's not possible to create a custom primitive value.
There is no way to really do what you want to do, but depending on how you are using it, you can fake it. You can use valueOf to return what you want. Example here shows using it to sum up an array of numbers and than altering it and running it again.
const sum = arr => arr.reduce((t, i) => t + i, 0)
function MyRef(n) {
this.number = n;
this.overWrite = n => this.number = n
}
MyRef.prototype.valueOf = function() {
return this.number;
};
const ref = new MyRef(100);
const myArray = [1, 2, ref]
console.log(sum(myArray))
ref.overWrite(3)
console.log(sum(myArray))
In the simple test code below I push the number 10 into an array and then splice 'hello world' into the array on the 2nd index. It works as expected.
"use strict";
let myArray = [1, 2, 3, 4, 5];
myArray.push(10);
myArray.splice(2, 0, 'hello world');
console.log(myArray);
However is it possible to do this on one line? I tried chaining in the example below and it throws an error. I can't find anyone talking about this online.
"use strict";
let myArray = [1, 2, 3, 4, 5];
myArray.push(10).splice(2, 0, 'hello world');
console.log(myArray);
Yes, it is possible to do it in one line.
"use strict";
let myArray = [1, 2, 3, 4, 5];
myArray.push(10); myArray.splice(2, 0, 'hello world');
console.log(myArray);
But why do you want to do that in one line? If your concern is readability I would stick with two lines. If you want it more functional, then use a functional library
edit
I agree with what every one else said about chainability. I'm just trying to make another point
These built-in methods are not designed to be part of a fluent interface, as they don't return the array that they're operating on (push() returns the new length, splice() returns the sub-array that was removed). You could add your own methods that are similar but are fluent.
Array.prototype.mypush = function(...args) {
this.push(...args);
return this;
};
Array.prototype.mysplice = function(...args) {
this.splice(...args);
return this;
}
let myArray = [1, 2, 3, 4, 5];
myArray.mypush(10).mysplice(2, 0, 'hello world');
console.log(myArray);
If you're using a modern JavaScript browser the push part is a little easier, using the array spread syntax. Since everyone else is using chaining (which requires altering the built-in Array object, which I don't like), I'll use something different:
"use strict";
let myArray = [1, 2, 3, 4, 5];
function notSplice(array, start, end, ...items) {
array.splice.apply(array, [start, end, ...items]);
return array;
}
myArray = notSplice([...myArray, 10], 2, 0, 'hello world');
console.log(myArray);
You could take the methods and parameters in an array and iterate with a function, which take the array as this value.
"use strict";
function arrayFn([k, ...a]) { this[k](...a); }
let myArray = [1, 2, 3, 4, 5];
[
['push', 10],
['splice', 2, 0, 'hello world']
].forEach(arrayFn, myArray);
console.log(myArray);
Chaining works by calling a method of the return value of the previous method call. For example:
myArray.filter(...).map(...).join(', ').trim()
// is equivalent to
const filteredArray = filtered.map(...)
const mappedArray = filteredArray.map(...) // filteredArray is an array, we can use map.
const aString = mappedArray.join(', ') // mappedArray is an array, we can use join
const trimmedString = aString.trim() // aString is a string, we can use trim
But in your case, it doesn't work because push returns a number (the length of the array plus the new item). There is no splice method for numbers.
myArray.push(...).splice(...)
// is equivalent to doing
const result1 = myArray.push(...)
const result2 = result1.splice(...) // But result1 isn't an array.
This is only possible if the methods you want to chain all return an Array, push returns the length of the array:
console.log([1,2].push(3)) // 3, not an array
console.log([1,2].map(x => x+1)) // [2,3], an array
I'm using Angular.js and trying to clear an array which is first instantiated and held on my module:
angular.module(myApp)
.controller('myCtrl', function ($rootScope){
var vm = this;
vm.myArr = ["Clear", "Me"]
vm.clearer = function(arr) {
arr = [];
};
vm.copier = function(arrToOverwrite, arrToCopy) {
arrToOverWrite = angular.copy(arrToCopy);
};
And I call this method from my HTML file:
(controller myCtrl is aliased as ctrl)
<input type="button" ng-click="ctrl.clearer(ctrl.myArr)" value="clear">
However, in the JS, it is underlining the arr, saying the value is never used. And, say I have something that always displays the value of myArr in the HTML, it is unaffected by the changes. I thought since JS is pass by reference, if myArr is passed as the reference in the clearer method, if it gets updated there, that it would then be updated with that value everywhere?
How would I go about this? I need to use the clearer method in other places on other arrays that may be held "in memory" here in the JS file at other times.
When you call the function you assign the arr param with a reference to ctrl.myArr. With the expression arr = [] you assign arr to reference an empty array, but ctrl.myArr still points to the original array.
In this case you need to mutate the array directly, by changing the length to 0, for example:
var array = [1, 2, 3];
var clearer = function(arr) {
arr.length = 0;
};
clearer(array);
console.log(array);
If you need to remove certain items, or add new items, you can use Array#splice or angular.copy() to overwrite the array with another:
var array = [1, 2, 3, 4, 5, 6, 7];
var replacement = [9, 10, 11];
function copier(arrToOverwrite, arrToCopy) {
arrToOverwrite.splice(0, arrToOverwrite.length, ...arrToCopy); // or angular.copy(arrToCopy, arrToOverwrite)
};
copier(array, replacement);
console.log(array);