@@ -865,3 +865,95 @@ getPlayers()
865
865
:: forEach (x => console .log (x));
866
866
` ` `
867
867
868
+ ## Realm API
869
+
870
+ [Realm API](https://github.com/tc39/proposal-realms) 提供沙箱功能(sandbox),允许隔离代码,防止那些被隔离的代码拿到全局对象。
871
+
872
+ 以前,经常使用` < iframe> ` 作为沙箱。
873
+
874
+ ` ` ` javascript
875
+ const globalOne = window ;
876
+ let iframe = document .createElement (' iframe' );
877
+ document .body .appendChild (iframe);
878
+ const globalTwo = iframe .contentWindow ;
879
+ ` ` `
880
+
881
+ 上面代码中,` < iframe> ` 的全局对象是独立的(` iframe .contentWindow ` )。Realm API 可以取代这个功能。
882
+
883
+ ` ` ` javascript
884
+ const globalOne = window ;
885
+ const globalTwo = new Realm ().global ;
886
+ ` ` `
887
+
888
+ 上面代码中,` Realm API ` 单独提供了一个全局对象` new Realm ().global ` 。
889
+
890
+ Realm API 提供一个` Realm ()` 构造函数,用来生成一个 Realm 对象。该对象的` global ` 属性指向一个新的顶层对象,这个顶层对象跟原始的顶层对象类似。
891
+
892
+ ` ` ` javascript
893
+ const globalOne = window ;
894
+ const globalTwo = new Realm ().global ;
895
+
896
+ globalOne .evaluate (' 1 + 2' ) // 3
897
+ globalTwo .evaluate (' 1 + 2' ) // 3
898
+ ` ` `
899
+
900
+ 上面代码中,Realm 生成的顶层对象的` evaluate ()` 方法,可以运行代码。
901
+
902
+ 下面的代码可以证明,Realm 顶层对象与原始对层对象是两个对象。
903
+
904
+ ` ` ` javascript
905
+ let a1 = globalOne .evaluate (' [1,2,3]' );
906
+ let a2 = globalTwo .evaluate (' [1,2,3]' );
907
+ a1 .prototype === a2 .prototype ; // false
908
+ a1 instanceof globalTwo .Array ; // false
909
+ a2 instanceof globalOne .Array ; // false
910
+ ` ` `
911
+
912
+ 上面代码中,Realm 沙箱里面的数组的原型对象,跟原始环境里面的数组是不一样的。
913
+
914
+ Realm 沙箱里面只能运行 ECMAScript 语法提供的 API,不能运行宿主环境提供的 API。
915
+
916
+ ` ` ` javascript
917
+ globalTwo .evaluate (' console.log(1)' )
918
+ // throw an error: console is undefined
919
+ ` ` `
920
+
921
+ 上面代码中,Realm 沙箱里面没有` console ` 对象,导致报错。因为` console ` 不是语法标准,是宿主环境提供的。
922
+
923
+ 如果要解决这个问题,可以使用下面的代码。
924
+
925
+ ` ` ` javascript
926
+ globalTwo .console = globalOne .console ;
927
+ ` ` `
928
+
929
+ ` Realm ()` 构造函数可以接受一个参数对象,该参数对象的` intrinsics` 属性可以指定 Realm 沙箱继承原始顶层对象的方法。
930
+
931
+ ` ` ` javascript
932
+ const r1 = new Realm ();
933
+ r1 .global === this ;
934
+ r1 .global .JSON === JSON ; // false
935
+
936
+ const r2 = new Realm ({ intrinsics: ' inherit' });
937
+ r2 .global === this ; // false
938
+ r2 .global .JSON === JSON ; // true
939
+ ` ` `
940
+
941
+ 上面代码中,正常情况下,沙箱的` JSON ` 方法不同于原始的` JSON ` 对象。但是,` Realm ()` 构造函数接受` { intrinsics: ' inherit' }` 作为参数以后,就会继承原始顶层对象的方法。
942
+
943
+ 用户可以自己定义` Realm` 的子类,用来定制自己的沙箱。
944
+
945
+ ` ` ` javascript
946
+ class FakeWindow extends Realm {
947
+ init () {
948
+ super .init ();
949
+ let global = this .global ;
950
+
951
+ global .document = new FakeDocument (... );
952
+ global .alert = new Proxy (fakeAlert, { ... });
953
+ // ...
954
+ }
955
+ }
956
+ ` ` `
957
+
958
+ 上面代码中,` FakeWindow` 模拟了一个假的顶层对象` window ` 。
959
+
0 commit comments