Skip to content
This repository was archived by the owner on Sep 8, 2024. It is now read-only.

Commit 383e948

Browse files
authored
Upload project files
Upload project files
1 parent c513e94 commit 383e948

File tree

11 files changed

+553
-193
lines changed

11 files changed

+553
-193
lines changed

LICENSE

Lines changed: 181 additions & 191 deletions
Large diffs are not rendered by default.

README.md

Lines changed: 47 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,47 @@
1-
# es6-proxy-polyfill
2-
Proxy polyfill based on ES3 supports IE8, Node.js, etc.
1+
<div align="right">[ <a href="README_zh.md">中文</a> ]</div>
2+
3+
# ES6 Proxy Polyfill
4+
This is a polyfill for the `Proxy` constructor based on **ES3** supports **IE8** , Node.js, etc.
5+
6+
Refer to <a href="https://tc39.github.io/ecma262/#sec-proxy-target-handler" target="_blank">ECMAScript</a>, and this has no external dependencies.
7+
8+
Due to the limitations of ES3, the polyfill supports just a limited number of proxy 'traps':
9+
* apply
10+
* construct
11+
12+
13+
#### Installation
14+
15+
1. Use NPM: `npm install es6-proxy-polyfill`
16+
2. Download directly: <a href="src/es6-proxy-polyfill.js" target="_blank">Development Version</a>, <a href="dist/es6-proxy-polyfill.js" target="_blank">Production Version</a>
17+
18+
19+
#### Usage
20+
21+
1. Browser:
22+
```
23+
<script src="path/to/es6-proxy-polyfill.js" type="text/javascript"></script>
24+
<script type="text/javascript">
25+
var target = function(){/* code */};
26+
var handler = {/* code */};
27+
var proxy = new Proxy(target, handler);
28+
</script>
29+
```
30+
2. Node.js:
31+
```
32+
require('es6-proxy-polyfill');
33+
34+
var target = function(){/* code */};
35+
var handler = {/* code */};
36+
var proxy = new Proxy(target, handler);
37+
```
38+
39+
40+
#### Notice
41+
42+
1. In ES6, the access to `Proxy` object's properties will be passed to target. In order to simulate this feature, polyfill will try to copy properties from target by using `Object.assign` method, so it's better to load an `Object.assign` polyfill first;
43+
```
44+
<script src="path/to/babel-polyfill.js" type="text/javascript"></script>
45+
<script src="path/to/es6-proxy-polyfill.js" type="text/javascript"></script>
46+
```
47+
2. The code has been tested on Node.js 0.10.48 and IE8, and it may work in other environments too.

README_zh.md

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
<div align="right">[ <a href="README.md">English</a> ]</div>
2+
3+
# ES6 Proxy Polyfill
4+
这是一个基于 **ES3**`Proxy`构造器polyfill,支持 **IE8** 和 Node.js 等。
5+
6+
参照 <a href="https://tc39.github.io/ecma262/#sec-proxy-target-handler" target="_blank">ECMAScript</a> 标准编写,无外部依赖。
7+
8+
由于ES3的限制,该polyfill只支持有限的'traps'代理:
9+
* apply
10+
* construct
11+
12+
13+
#### 安装
14+
15+
1. 使用NPM:`npm install es6-proxy-polyfill`
16+
2. 直接下载:<a href="src/es6-proxy-polyfill.js" target="_blank">开发版本</a>,<a href="dist/es6-proxy-polyfill.js" target="_blank">生产版本</a>
17+
18+
19+
#### 用法
20+
21+
1. 浏览器:
22+
```
23+
<script src="path/to/es6-proxy-polyfill.js" type="text/javascript"></script>
24+
<script type="text/javascript">
25+
var target = function(){/* code */};
26+
var handler = {/* code */};
27+
var proxy = new Proxy(target, handler);
28+
</script>
29+
```
30+
2. Node.js:
31+
```
32+
require('es6-proxy-polyfill');
33+
34+
var target = function(){/* code */};
35+
var handler = {/* code */};
36+
var proxy = new Proxy(target, handler);
37+
```
38+
39+
40+
#### 注意
41+
42+
1. 在ES6中,对`Proxy`对象属性的访问将会被传递给目标对象。为了模拟这个特性,polyfill会尝试使用`Object.assign`方法从目标对象复制属性,因此最好先加载一个`Object.assign`的polyfill;
43+
```
44+
<script src="path/to/babel-polyfill.js" type="text/javascript"></script>
45+
<script src="path/to/es6-proxy-polyfill.js" type="text/javascript"></script>
46+
```
47+
2. 代码已经在Node.js 0.10.48 和 IE8 测试过,而且它也应该能够运行在其他环境下。

dist/es6-proxy-polyfill.js

Lines changed: 8 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/es6-proxy-polyfill.js.map

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
{
2+
"name": "es6-proxy-polyfill",
3+
"version": "1.0.0",
4+
"description": "Proxy polyfill based on ES3 supports IE8, Node.js, etc.",
5+
"main": "src/es6-proxy-polyfill.js",
6+
"scripts": {
7+
"build": "uglifyjs src/es6-proxy-polyfill.js -c -m reserved=[Proxy] --ie8 --comments --source-map -o dist/es6-proxy-polyfill.js"
8+
},
9+
"keywords": [
10+
"proxy-polyfill",
11+
"proxy",
12+
"polyfill",
13+
"ie8",
14+
"es6"
15+
],
16+
"author": "[email protected]",
17+
"license": "Apache-2.0",
18+
"repository": {
19+
"type": "git",
20+
"url": "git+https://github.com/ambit-tsai/es6-proxy-polyfill.git"
21+
},
22+
"devDependencies": {
23+
"uglify-js": "^3.4.8"
24+
}
25+
}

src/es6-proxy-polyfill.js

Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
/**
2+
* ES6 Proxy Polyfill
3+
* @version 1.0.0
4+
* @author Ambit Tsai <[email protected]>
5+
* @license Apache-2.0
6+
* @see {@link https://github.com/ambit-tsai/es6-proxy-polyfill}
7+
*/
8+
;(function(global){
9+
if(global.Proxy) return; // return if Proxy already exist
10+
11+
var noop = function(){},
12+
assign = Object.assign || noop,
13+
getProto = Object.getPrototypeOf || noop,
14+
setProto = Object.setPrototypeOf || noop;
15+
16+
/**
17+
* Throw a type error
18+
* @param {String} message
19+
*/
20+
function throwTypeError(message){
21+
throw new TypeError(message);
22+
}
23+
24+
/**
25+
* The internal member constructor
26+
* @constructor
27+
* @param {Function} target
28+
* @param {Object} handler
29+
*/
30+
function InternalMember(target, handler){
31+
this.target = target; // [[ProxyTarget]]
32+
this.handler = handler; // [[ProxyHandler]]
33+
}
34+
35+
/**
36+
* The [[Call]] internal method
37+
* @param {Object} thisArg
38+
* @param {Object} argsList
39+
*/
40+
InternalMember.prototype.$call = function(thisArg, argsList){
41+
var target = this.target,
42+
handler = this.handler;
43+
if(!handler){
44+
throwTypeError("Cannot perform 'call' on a proxy that has been revoked");
45+
}
46+
if(handler.apply == null){
47+
return target.apply(thisArg, argsList);
48+
}else if(typeof handler.apply === 'function'){
49+
return handler.apply(target, thisArg, argsList);
50+
}else{
51+
throwTypeError('Proxy handler\'s apply trap must be a function');
52+
}
53+
};
54+
55+
/**
56+
* The [[Construct]] internal method
57+
* @param {Object} thisArg
58+
* @param {Object} argsList
59+
* @returns {Object}
60+
*/
61+
InternalMember.prototype.$construct = function(thisArg, argsList){
62+
var target = this.target,
63+
handler = this.handler,
64+
obj;
65+
if(!handler){
66+
throwTypeError("Cannot perform 'construct' on a proxy that has been revoked");
67+
}
68+
if(handler.construct == null){
69+
obj = target.apply(thisArg, argsList);
70+
if(obj instanceof Object){
71+
return obj;
72+
}else{
73+
return thisArg;
74+
}
75+
}else if(typeof handler.construct === 'function'){
76+
obj = handler.construct(target, argsList);
77+
if(obj instanceof Object){
78+
return obj;
79+
}else{
80+
throwTypeError('Proxy handler\'s construct trap must return an object');
81+
}
82+
}else{
83+
throwTypeError('Proxy handler\'s construct trap must be a function');
84+
}
85+
};
86+
87+
/**
88+
* Create a Proxy object
89+
* @param {Function} target
90+
* @param {Object} handler
91+
* @returns {Function}
92+
*/
93+
function createProxy(target, handler){
94+
// Check the type of arguments
95+
if(typeof target !== 'function'){
96+
throwTypeError('Proxy polyfill only support function target');
97+
}else if( !(handler instanceof Object) ){
98+
throwTypeError('Cannot create proxy with a non-object handler');
99+
}
100+
101+
// The internal member
102+
var member = new InternalMember(target, handler);
103+
104+
// The Proxy object
105+
function P(){
106+
return this instanceof P?
107+
member.$construct(this, arguments):
108+
member.$call(this, arguments);
109+
}
110+
111+
assign(P, target); // copy target's properties
112+
P.prototype = target.prototype; // copy target's prototype
113+
setProto(P, getProto(target)); // copy target's [[Prototype]]
114+
115+
return P;
116+
}
117+
118+
/**
119+
* The Proxy constructor
120+
* @constructor
121+
* @param {Function} target
122+
* @param {Object} handler
123+
* @returns {Function}
124+
*/
125+
function Proxy(target, handler){
126+
if(this instanceof Proxy){
127+
return createProxy(target, handler);
128+
}else{
129+
throwTypeError("Constructor Proxy requires 'new'");
130+
}
131+
}
132+
133+
// Prevent function declaration from being translated into function expression by UglifyJS.
134+
// Function expression called by 'new' will cause an inconsistent result between old IE and
135+
// others when runing the code - `this instanceof P`.
136+
Proxy.revocable;
137+
138+
global.Proxy = Proxy;
139+
}(typeof window==='object'? window: global));

test/browser/trap-apply.html

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<meta http-equiv="content-type" content="text/html;charset=utf-8">
5+
<title>trap-apply</title>
6+
</head>
7+
<body>
8+
<script src="../../dist/es6-proxy-polyfill.js" type="text/javascript"></script>
9+
<script type="text/javascript">
10+
var person = {
11+
name: "Ambit_Tsai",
12+
sayHello: function(){
13+
document.write(">"+this.name+": Hey man!<br>");
14+
}
15+
};
16+
17+
person.sayHello = new Proxy(person.sayHello, {
18+
apply: function(func, ctx, args){
19+
document.write("Trigger 'apply' trap<br>");
20+
func.apply(ctx, args);
21+
}
22+
});
23+
24+
document.write("Call 'sayHello' method<br>");
25+
person.sayHello();
26+
</script>
27+
</body>
28+
</html>

test/browser/trap-construct.html

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<meta http-equiv="content-type" content="text/html;charset=utf-8">
5+
<title>trap-construct</title>
6+
</head>
7+
<body>
8+
<script src="../../dist/es6-proxy-polyfill.js" type="text/javascript"></script>
9+
<script type="text/javascript">
10+
function Person(name){
11+
document.write("Set this.name to '"+name+"'<br>");
12+
this.name = name;
13+
}
14+
Person.prototype.sayHello = function(){
15+
document.write(">"+this.name+": Hey man!<br>");
16+
};
17+
Person.className = "Person";
18+
19+
var NewPerson = new Proxy(Person, {
20+
construct: function(Target, args){
21+
document.write("Trigger 'construct' trap<br>");
22+
return new Target(args[0]);
23+
}
24+
});
25+
26+
document.write("NewPerson's className: '"+NewPerson.className+"' (need 'Object.assign')<br>");
27+
28+
document.write("Create a NewPerson object<br>");
29+
var person = new NewPerson("Ambit_Tsai");
30+
31+
document.write("Call 'sayHello' method<br>");
32+
person.sayHello();
33+
</script>
34+
</body>
35+
</html>

test/nodejs/trap-apply.js

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
require('../../src/es6-proxy-polyfill');
2+
3+
var person = {
4+
name: "Ambit_Tsai",
5+
sayHello: function(){
6+
console.log(">"+this.name+": Hey man!");
7+
}
8+
};
9+
person.sayHello = new Proxy(person.sayHello, {
10+
apply: function(func, ctx, args){
11+
console.log("Trigger 'apply' trap");
12+
func.apply(ctx, args);
13+
}
14+
});
15+
16+
console.log("Call 'sayHello' method");
17+
person.sayHello();

0 commit comments

Comments
 (0)