Skip to content

Instantly share code, notes, and snippets.

@Ayms
Created June 26, 2012 12:53
Show Gist options
  • Save Ayms/2995641 to your computer and use it in GitHub Desktop.
Save Ayms/2995641 to your computer and use it in GitHub Desktop.
|wrap| suggestion in strict mode

|wrap| suggestion (was |with|'s redesign attempt, but it seems nobody want to hear again about |with| in strict mode) in strict mode which is supposed to address at least 4 subjects mentionned below.

The concern here is more to address the subject of binding variables to properties than using properties of an object passed as an argument to |wrap| (then it is somewhere the contrary of what is doing a usual |with|). Then the suggestion here is to pass nothing to |wrap| and implicitely declare in the wrap statement the |this| binding

Issue (one of...) : |wrap| is not a reserved keyword

##Suggestion

"use strict"

var a='a';

wrap () {

//wrap (a) { --> syntax error
	
	console.log(this); //undefined or outside |this| if hard binding
	
	var window=new require('WINDOW')(); //load a WINDOW module
										//can be loaded outside but then will be accessible to other windows
	var b="b";
										
	this=window; 	//disruptive assignment
					//LHS lexical this
					//|this| is now window within the |wrap| statement
	
	console.log(window.window); //window - "var window" defined above gets bound to |this|, then to window, this defines (automatically) a window property for window
								//this is not uninteresting, if not you should not forget to do manually window.window=window
	
	console.log(window.b); //"b"
	
	var c="c";
	
	console.log(window.c); //"c"
	
	console.log(c); //"c"
	
	window.d="d";
	
	console.log(d); //"d"
	
	var code=module.load(web_api_code);

	eval(code); //ThisBinding is window
	
	//code : a='A' --> console.log(a); //A
	//code : d='d' --> syntax error, code must follow strict mode, small limitation...
	//code : var e='e' --> console.log(e or window.e) //e
	//code : var c='z' --> console.log(c or window.c) //c - strict mode
	//code : console.log(this) --> window

	console.log(window.parseInt); 	//undefined
									//global object properties could be copied see below
	
	console.log(parseInt); //parseInt
	
	//copy global property

	var setTimeout_=setTimeout;

	var setTimeout=(a,b)=>{var c=a.bind(this);setTimeout_(c,b)};

	var f=function(){console.log(this)};
	
	setTimeout(f,1000);//window
	
	this=a; //syntax error, can not redefine |this|
}

##Rationale :

This is supposed to be related to at least four topics :

  • SES securization : |wrap| is used to separate initial context from new window context, if something was to be passed to |wrap| then it would be impossible to ensure separation of both contexts. You could then spend your time wondering in what context things get executed depending on where you define it, example (see Annex below too) :
var window=new WINDOW();

wrap(window) {

var a='a';

window.document.onload=function() {console.log(a)};//"a"

};

window.document.onload=function() {console.log(a)};//undefined

Of course depending on what developers are doing, both contexts (and mainly what is defined within the |wrap| statement) can communicate, if not what is defined within the |wrap| statement is not accessible. Depending on what needs to be done other security features can be added (freeze global properties, etc)

  • modules loader : unless I am wrong, I did not see in modules proposals something that can load just the code of a web API (so not a module designed to work as such) for example and that can execute in a way that it can interact with the code from where it is requested, as far as I saw and as far as it exists today, modules contexts are always separated with a possibility to import things but not to interact directly. Anyway, loading js and executing it is something that everybody know how to do

  • multiple globals : global properties are not assigned to the new virtual global (window), but again do we need it ? I am thinking since some time about what is written in the multiple globals strawman : "the presence of multiple global objects interacting with one another, but this has long been the reality on the web". Web projects defining multiple globals, OK, but interacting between each others I could not find any example up to now, except maybe the small and limited interaction between window and things such as iframe's windows. Anyway, the above proposal might fit, if you want your multiple window to interact between each other then give access to what you want of windows objects.

  • VMs : this could simplify the concepts used in VMs, in particular node.js's VM (which has some defaults like not binding things correctly in some situations)

##Annex :

Note : examples given below are simplified to try to get a better understanding.

One approach can be (node.js) :

var window=new WINDOW();

window=Object.createContext(window); //sandbox object

eval(code,window); //creates a new global, clone sandbox properties to it, execute code, clone global properties to sandbox

As mentionned above, this is a complete headheck where you spend your time wondering where things get executed, example :

window.setTimeout=setTimeout;

code='setTimeout(function(){console.log(this)},1000)';

eval(code,window); //window is expected but it does echo the global of initial context

In addition, contexts can not really communicate :

window.document.onload=function() {
        eval('var b=document.body',window);
	var web_stuff=require('console.log(b)'); //undefined
}

This could be replaced by :

wrap() {
   var window=new WINDOW();
   this=window;
   eval(code);
}

Another approach can be (cajaVM) :

var import=Object.clone(global); //clone global var

var freevar=extract_var_assignment_from_code=['a','b','c']

var scopedObject={
	a: {get:scopedGet, set:scopedSet},
    b: {get:scopedGet, set:scopedSet},
    c: {get:scopedGet, set:scopedSet}
}

Where scopedGet/Set gets/sets the (a or b or c) property of import

with(scopedObject) {
	eval(code,import)
}

This approach is not trivial to understand, you have to extract the free var and then set multiple getters/setters, so probably there is an impact on performances

This could be replaced by :

//freeze globals
wrap() {
   var import=new TameWindow();
   //copy globals into import
   this=import;
   eval(code);
}

And another one can be based on (subset of shadow which is intented for other use, but the example is interesting) :

var compiled=Function.apply(null,['document','screen',code]); //properties of the global object

//function anonymous(document, screen) {code}

var glob={document:value_of_document,screen:value_of_screen}; //the new global

compiled.apply(glob,[glob.document,glob.screen]); //execute code with |this| bound to glob and scope knowing glob's var and their values

Not easy too, requires manipulations, if code='var a="a"', a does not get bound to glob, would require freevar manipulations as above

This could be replaced by :

code='wrap() {'+code+'}';
@Ayms
Copy link
Author

Ayms commented Jun 27, 2012

Thanks, I have updated the gist

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment