Last active
December 10, 2015 07:38
-
-
Save marcoscaceres/4402084 to your computer and use it in GitHub Desktop.
Exports a function to the global scope in a way that conforms to WebIDL.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Exports a function to the global scope in a way that conforms to Web IDL. | |
* | |
* These objects are indistiguishable from host objects. That is, you can create | |
* objects like the ones that are exposed by the browser, like window.Event, | |
* window.Node, etc. | |
* | |
* Copyright (c) 2012 Marcos Caceres / François REMY | |
* Licensed under the MIT license. | |
* | |
**/ | |
// emulate Function.name if needed | |
if(Function.name != "Function") { | |
Object.defineProperty(Function.prototype, "name", { | |
get: function() { | |
try { | |
var name = (""+this).match(/function(.*?)\(/)[1].replace(/\s+$|^\s+/g, ""); | |
Object.defineProperty(this, "name", {value:name,writable:false}); | |
return name; | |
} catch (ex) { | |
return "anonymous"; | |
} | |
} | |
}); | |
} | |
function DOMConstructor(privateConstructor, prototypeDefinition, constructorDefinition) { | |
var name = privateConstructor.name || 'DOMObject'; | |
//emulate native code toString() | |
var toStringMaker = function toStringMaker(name) { | |
return function toString() { | |
return 'function ' + name + '() { [native code] }'; | |
}; | |
}; | |
// create the prototype hierarchy | |
var prototypeConstructor = eval('(function '+name+'Prototype() {})'); | |
prototypeConstructor.prototype.toString=function() { if(this instanceof privateConstructor) { return '[object '+name+']'; } else { return '[object '+name+'Prototype]'; } } | |
privateConstructor.prototype=new prototypeConstructor(); | |
// add the "instance" properties | |
if(prototypeDefinition) { | |
Object.defineProperties(privateConstructor.prototype, prototypeDefinition); | |
} | |
// create the public contructor | |
var publicConstructor = eval('(function ' + name + '(){return new privateConstructor()})'); | |
// the new constructor should have the same prototype | |
try { | |
Object.defineProperty(publicConstructor, 'prototype', { | |
writable: false, | |
enumerable: false, | |
configurable: false, | |
value: privateConstructor.prototype | |
}); | |
} catch(ex) { | |
publicConstructor.prototype=privateConstructor.prototype; | |
} | |
// add the "static" properties | |
if(constructorDefinition) { | |
Object.defineProperties(publicConstructor, constructorDefinition); | |
} | |
// the functions should not leak their implementation (via toString) | |
privateConstructor.toString = publicConstructor.toString = toStringMaker(name); | |
privateConstructor.prototype.constructor=publicConstructor; | |
for (var i in privateConstructor.prototype) { | |
if (privateConstructor.prototype.hasOwnProperty(i)) { | |
var f = privateConstructor.prototype[i]; | |
if(typeof f == "function") { | |
if(!f.hasOwnProperty("toString")) { | |
f.toString = toStringMaker(i); | |
} | |
} | |
} | |
} | |
return publicConstructor; | |
} | |
</script> | |
</head> | |
<body> | |
<script> | |
(function(){ | |
var fooInstance; | |
// your secret constructor | |
var Foo = new DOMConstructor(function Foo(){ this.date=new Date(); }, { | |
test: { | |
value: function test(){ | |
if (!(this instanceof Foo)) { | |
throw new TypeError("Illegal invocation"); | |
} | |
console.log("test") | |
} | |
} | |
},{ | |
CONSTANT: { | |
value: true, | |
writable: false, | |
configurable: false | |
} | |
}); | |
//Add it to the window object | |
window.Foo=Foo; | |
}()); | |
//proof | |
console.log(window.Foo); | |
//check instance prototype chain | |
var fooInstance = new Foo(); | |
fooInstance.test(); | |
Foo.prototype.test2=function(){console.log('test2')}; | |
fooInstance.test2(); | |
//Following all throw | |
if(!window.setImmediate) { window.setImmediate=function(f) { setTimeout(f, 0); }; } | |
setImmediate(function() { console.log(Foo() instanceof Foo); }); | |
setImmediate(function() { console.log(new Foo() instanceof Foo); }); | |
setImmediate(function() { console.log(new Foo().constructor==Foo); }); | |
setImmediate(function() { console.log(fooInstance=="[object Foo]"); }); | |
setImmediate(function() { console.log(Foo.prototype=="[object FooPrototype]"); }); | |
setImmediate(function() { try { Foo.prototype.test(); console.log(false); } catch (ex) { console.log(true); } }); | |
setImmediate(function() { console.log(Foo.CONSTANT==true); }); | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment