NeilFraser / JS-Interpreter

A sandboxed JavaScript interpreter in JavaScript.
Apache License 2.0
1.98k stars 353 forks source link

this.constructor() requires a proto #175

Closed NAllred91 closed 4 years ago

NAllred91 commented 4 years ago

I'm not sure I completely understand what is wrong here, but I have a some code you can run through the demo and in your browser console to see the difference.

var testClass = function(arg1) {this.arg1 = arg1}
testClass.prototype.someMethod = function() {}
testClass.prototype.getNewInstance = function() {
 return new this.constructor('will this be arg1?')
}

alert(new testClass().getNewInstance().someMethod)
alert(new testClass().getNewInstance().arg1)

In JS-Interpreter, it seems that this.constructor is expected to be called with a proto. If you pass in this to the constructor the new instance has the properties from the prototype, but then you can't pass in the arguments to the constructor.

var testClass = function(arg1) {this.arg1 = arg1}
testClass.prototype.someMethod = function() {}
testClass.prototype.getNewInstance = function() {
 return new this.constructor(this, 'will this be arg1?')
}

alert(typeof new testClass().getNewInstance().someMethod)   //  This now works!
alert(new testClass().getNewInstance().arg1)   //  This still does not work.
cpcallen commented 4 years ago

I'm about 90% sure that the problem is that .createFunctionBase_ sets <func>.prototype, but not <func>.prototype.consructor (which should of course be set to <func>).

For native functions this oversight is corrected in .createNativeFunction, but nowhere does it appear that it is done for user functions.

NAllred91 commented 4 years ago

Yea, the comment for createNativeFunction points out that some functions can't be called as constructors. I'm unsure if the user can write a function in es5 that can't be called as a constructor though?

I know arrow functions can't be called as constructors, but I'm not sure if there is a way to write a function that can't be called as a constructor is es5?

cpcallen commented 4 years ago

createNativeFunction can be called with the boolean to make the function not a constructor, but maybe that logic should be moved into createFunctionBase_ and have the boolean passed through?

In that case, I think createFunction could always call createFunctionBase_ with the boolean set to true?

There are a few options but that is probably the most straight forward.

I'm unsure if the user can write a function in es5 that can't be called as a constructor though?

I am not aware of any mechanism by which a user could do that in ES5 (and I am fairly familiar with the spec).

NAllred91 commented 4 years ago

Yep! this seems to fix the issue I've been running into!

Let me know if you'd like me to make a pull request.

NeilFraser commented 4 years ago

I think this should fix it.