Reflect這個物件在我的node(v4.4.3)中還沒有實作, babel(6.7.7)也沒有實作,新版本的chrome是支援的, ff比較早就支持Proxy和Reflect了,要讓node支援Reflect可以安裝harmony-reflect ;
Reflect不是建構函數, 要使用的時候直接透過Reflect.method()調用, Reflect有的方法和Proxy差不多, 而且多數Reflect方法原生的Object已經重新實作了。
這裡列舉幾個為什麼要使用Reflect的原因, 譯文位址:Reflect , 大概翻譯了一遍:
##1:更有用的回傳值: Reflect有一些方法和ES5中Object方法一樣樣的, 例如: Reflect.getOwnPropertyDescriptor和Reflect.defineProperty, 不過, Object.defineProperty(obj, name, desc)執行成功會回傳obj, 以及其它原因導致的錯誤, Reflect .defineProperty只會回傳false或true來表示物件的屬性是否設定上了, 如下程式碼可以重構:try { Object.defineProperty(obj, name, desc); // property defined successfully } catch (e) { // possible failure (and might accidentally catch the wrong exception) }重構成這樣:
if (Reflect.defineProperty(obj, name, desc)) { // success } else { // failure }其餘的方法, 例如Relect.set , Reflect.deleteProperty, Reflect.preventExtensions, Reflect.setPrototypeOf, 都可以進行重構;2:函數操作, 如果要判斷一個obj有定義或者繼承了屬性name, 在ES5中這樣判斷:name in obj ; 或刪除一個屬性:delete obj[name], 雖然這些很好用, 很簡短, 很明確, 但是要使用的時候也要封裝成一個類別;有了Reflect, 它幫你封裝好了, Reflect.has(obj, name), Reflect.deleteProperty(obj, name);3:更可靠的函數式執行方式: 在ES中, 要執行一個函數f,並給它一個參數args, 還要綁定this的話, 要這麼寫:
f.apply(obj, args)但是f的apply可能被重新定義成用戶自己的apply了,所以還是這樣寫比較可靠:
Function.prototype.apply.call(f, obj, args)上面這段程式碼太長了, 而且不好懂, 有了Reflect, 我們可以更短更簡潔明了:
Reflect.apply(f, obj, args)4:可變參數形式的建構子: 想像一下, 你要透過不確定長度的參數實例化一個建構函數, 在ES5中, 我們可以使用擴展符號, 可以這麼寫:
var obj = new F(...args)不過在ES5中, 不支援擴充符啊, 所以, 我們只能用F.apply,或F.call的方式傳不同的參數, 可惜F是一個構造函數, 這個就坑爹了, 不過有了Reflect, 我們在ES5中能夠這麼寫:
var obj = Reflect.construct(F, args)5:控制存取器或讀取器的this: 在ES5中,想要讀取一個元素的屬性或設定屬性要這樣:
var name = ... // get property name as a string obj[name] // generic property lookup obj[name] = value // generic property updateReflect.get和Reflect.set方法允許我們做同樣的事情, 而且他增加了一個額外的參數reciver, 允許我們設定物件的setter和getter的上下this:
var name = ... // get property name as a string Reflect.get(obj, name, wrapper) // if obj[name] is an accessor, it gets run with `this === wrapper` Reflect.set(obj, name, value, wrapper)存取器中不想使用自己的方法,而是想要重定向this到wrapper:
var obj = { set foo(value) { return this.bar(); }, bar: function() { alert(1); } }; var wrapper = { bar : function() { console.log("wrapper"); } } Reflect.set(obj, "foo", "value", wrapper);6:避免直接存取__proto__ : ES5提供了 Object.getPrototypeOf(obj),去存取物件的原型,ES6提供也提供了
#Reflect.getPrototypeOf(obj) 和 Reflect##Reflect.getPrototypeOf(obj)
和 Reflect##Reflect.getPrototypeOf(obj)
和 Reflect
.setPrototypeOf(obj, newProto), 這個是新的方法去存取和設定物件的原型:
Reflect.apply的使用
第一個參數為: 需要執行的函數;
第二個參數為: 需要執行函數的上下文this;第三個參數為: 是一個陣列或偽數組, 會作為執行函數的參數;<script>
let fn = function() {
this.attr = [0,1,2,3];
};
let obj = {};
Reflect.apply(fn, obj, [])
console.log(obj);
</script>
#Reflect.apply的DEMO:
###################################################
<script> Reflect.apply(Math.floor, undefined, [1.75]); // 输出:1; Reflect.apply(String.fromCharCode, undefined, [104, 101, 108, 108, 111]); // 输出:"hello" Reflect.apply(RegExp.prototype.exec, /ab/, ["confabulation"]).index; //输出: 4 Reflect.apply("".charAt, "ponies", [3]); // 输出:"i" </script>######Reflect可以與Proxy聯合使用:######
{ var Fn = function(){ }; Fn.prototype.run = function() { console.log( "runs out" ); }; var ProxyFn = new Proxy(Fn, { construct (target ,arugments) { console.log("proxy constructor"); var obj = new target(...arugments); //Reflect.apply的使用方法; Reflect.apply(target.prototype.run, obj, arugments); return obj; } }); new ProxyFn (); //会先输出: "proxy constructor" ; 再输出: runs out }######Reflect.construct()的使用:#########Reflect.construct其實就是實例化建構函數,透過傳參形式的實現, 執行的方式不同, 效果其實一樣, construct的第一個參數為建構函數, 第二個參數由參數組成的數組或偽數組, 基本的使用方法為:# ##
var Fn = function(arg) { this.args = [arg] }; console.log( new Fn(1), Reflect.construct(Fn,[1]) ); // 输出是一样的 var d = Reflect.construct(Date, [1776, 6, 4]); d instanceof Date; // true d.getFullYear(); // 1776 //所以Reflect.consturct和new 构###所以Reflect.consturct和new 建構子是一樣, 至少到目前為止..######我們可以給Reflect.construct傳第三個參數, 第三個參數為一個超類,新元素會繼承這個超類別;###
<script> function someConstructor() {} var result = Reflect.construct(Array, [], someConstructor); Reflect.getPrototypeOf(result); // someConstructor.prototype Array.isArray(result); // true //or var Fn = function() { this.attr = [1]; }; var Person = function() { }; Person.prototype.run = function() { }; console.log( Reflect.construct(Fn, [], Person) ); </script>############所以我們可以用這個實作一個特殊的數組, 繼承數組, 但是也有自己的方法;###
var Fn = function() { Array.apply(this, arguments); this.shot = ()=> { console.log("heheda"); }; }; var arr = Reflect.construct(Fn, [])# #####Reflect.defineProperty的使用;#########Reflect.defineProperty傳回的是布林值, 透過直接賦值的方式把屬性和屬性值加給物件回傳的是一整個物件,如果新增失敗會拋錯;###
var obj = {}; obj.x = 10; console.log(obj.x) //输出:10;###使用Reflect.defineProperty的方式新增值;###
<script> var obj = {}; if( Reflect.defineProperty(obj, "x", {value : 7 }) ) { console.log("added success"); }else{ console.log("添加失败"); }; </script>
如果我们执行preventExtensions, 通过Object.defindProperty定义新属性报错了, 但是通过Reflect.defineProperty没有报错, 返回了一个false的值:
var obj = {}; Object.preventExtensions(obj); Object.defineProperty(obj, "x" , { value: 101, writable: false, enumerable: false, configurable: false });// 直接抛错了; console.log( Reflect.defineProperty(obj, "x", {value:101}) ) //返回false:
如果通过直接赋值的方式, 无论是否正确赋值, 都返回设置的值, 除非我们手动确认对象的属性值是否设置成功;
<script> var obj = {}; Object.preventExtensions(obj); console.log( obj.aa = 1 ); //输出:1; console.log(obj.aa) //输出:undefined; </script>
Reflect.deleteProperty的使用:
Reflect.deleteProperty和Reflect.defineProperty的使用方法差不多, Reflect.deleteProperty和 delete obj.xx的操作结果是一样, 区别是使用形式不同:一个是操作符,一个是函数调用;
Reflect.deleteProperty(Object.freeze({foo: 1}), "foo"); // false delete Object.freeze({foo: 1}).foo; //输出:false;
Reflect.get()方法的使用
这个方法的有两个必须的参数: 第一个为obj目标对象, 第二个为属性名对象, 第三个是可选的,是作为读取器的上下文(this);
var obj = {}; obj.foo = 1; console.log( obj.foo ); //输出:1; console.log( Reflect.get(obj, "foo") ) //输出:1;
如果Reflect.get有第三个参数的话, 第三个参数会作为读取器的上下文:
var Reflect = require('harmony-reflect'); var obj = { "foo" : 1, get bar() { return this.foo; } }; var foo = {}; foo.foo = "heheda"; console.log(Reflect.get(obj, "bar", foo));
Reflect.getOwnPropertyDescritptor()方法的使用:
通过Reflect.getOwnPropertyDescritptor获取属性描述:
Reflect.getOwnPropertyDescriptor({x: "hello"}, "x"); //也可以这样获取: Object.getOwnPropertyDescriptor({x:"1"},"x"); //这两个的区别是一个会包装对象, 一个不会: Reflect.getOwnPropertyDescriptor("hello",0); //抛出异常 Object.getOwnPropertyDescriptor("hello",0); //输出: {value: "h", writable: false, enumerable: true, configurable: false}
Reflect.getPrototypeOf()方法的使用:
Reflect.getPrototypeOf和Object.getPrototypeOf是一样的, 他们都是返回一个对象的原型
Reflect.getPrototypeOf({}); // 输出:Object.prototype Reflect.getPrototypeOf(Object.prototype); // 输出:null Reflect.getPrototypeOf(Object.create(null)); // 输出: null
Reflect.has的使用
Reflect.has这个方法有点像操作符:in , 比如这样: xx in obj;
<script> Reflect.has({x:0}, "x") //输出: true; Reflect.has({y:0}, "y") //输出:true ; var obj = {x:0}; console.log( "x" in obj); var proxy = new Proxy(obj, { has : function(target, args) { console.log("执行has方法"); return Reflect.has(target,...args); } }); console.log( "x" in proxy); //输出:true; console.log(Reflect.has(proxy, "x")) //输出:true; </script>
这个demo的obj相当于变成了一个方法了, 没他什么用 , 只是利用了他的has方法:
obj = new Proxy({}, { has(t, k) { return k.startsWith("door"); } }); Reflect.has(obj, "doorbell"); // true Reflect.has(obj, "dormitory"); // false
Reflect.isExtensible()的使用
// 现在这个元素是可以扩展的; var empty = {}; Reflect.isExtensible(empty); // === true // 使用preventExtensions方法, 让这个对象无法扩展新属性; Reflect.preventExtensions(empty); Reflect.isExtensible(empty); // === false // 这个对象无法扩展新属性, 可写的属性依然可以改动 var sealed = Object.seal({}); Reflect.isExtensible(sealed); // === false // 这个对象完全被冻结了 var frozen = Object.freeze({}); Reflect.isExtensible(frozen); // === false
Reflect.isExtensible和Object.isExtensible的区别是, 如果参数不对,一个会抛错, 另一个只是返回true或者false:
Reflect.isExtensible(1); // 抛错了: 1 is not an object Object.isExtensible(1); // 返回false;
Reflect.ownKeys()方法的使用:
Reflect.ownKeys, Object可没有ownKeys方法, Reflect.ownKeysz他的作用是返回对象的keys;
console.log(Reflect.ownKeys({"a":0,"b":1,"c":2,"d":3})); //输出 :["a", "b", "c", "d"] console.log(Reflect.ownKeys([])); // ["length"] var sym = Symbol.for("comet"); var sym2 = Symbol.for("meteor"); var obj = {[sym]: 0, "str": 0, "773": 0, "0": 0, [sym2]: 0, "-1": 0, "8": 0, "second str": 0}; Reflect.ownKeys(obj); //输出:/ [ "0", "8", "773", "str", "-1", "second str", Symbol(comet), Symbol(meteor) ]
Reflect.ownKeys的排序是根据: 先显示数字, 数字根据大小排序,然后是 字符串根据插入的顺序排序, 最后是symbol类型的key也根据插入插入顺序排序;
出现这中排序是因为,你给一个对象属性赋值时候, 对象的key的排序规则就是先数字, 在字符串, 最后是symbol类型的数据;
Reflect.preventExtensions()的使用方法:
Object也有preventExtensions方法, 和Reflect.preventExtensions()有一点区别, 如果Reflect.preventExtensions参数不是对象会抛错;
var empty = {}; Reflect.isExtensible(empty); // === true // 执行preventExtensions后的对象可以修改; Reflect.preventExtensions(empty); Reflect.isExtensible(empty); // === false Reflect.preventExtensions(1); // TypeError: 1 is not an object Object.preventExtensions(1); //不会抛错, 会返回:1
Reflect.set()
Reflect.set方法和get是差不多的;
var obj = {}; Reflect.set(obj, "prop", "value"); // 输出:true console.log( obj.prop ); // 输出:"value" var arr = ["duck", "duck", "duck"]; Reflect.set(arr, 2, "goose"); // true console.log( arr[2] ); // "goose" Reflect.set(arr, "length", 1); // true console.log( arr );// ["duck"];
Reflect.set(obj)相当于 Reflect.set(obj, undefined, undefined);
var obj = {}; Reflect.set(obj); // 输出:true //以上的代码相当于 Reflect.set(obj, undefined, undefined); Reflect.getOwnPropertyDescriptor(obj, "undefined"); // { value: undefined, writable: true, enumerable: true, configurable: true }
Reflect.set也可以有第四个参数, 这个参数会作为stter的this;
var obj = { value : 10, set key( value ) { console.log("setter"); this.value = value; }, get key() { return this.value; } }; Reflect.set(obj,"key","heheda", obj); console.log(obj);
Reflect.setPrototypeOf()
Reflect.setPrototypeOf()方法和Object.setPrototypeOf差不多一样样的, 会给对象设置原型, 就是更改对象的__proto__属性了…;
Reflect.setPrototypeOf({}, Object.prototype); // 输出true // 给该对象数组[[Prototype]] 为null. Reflect.setPrototypeOf({}, null); // true // 此时的obj.__proto__为undefine //把对象冻结以后重新设置[[prototype]] Reflect.setPrototypeOf(Object.freeze({}), null); // false // 如果原型链循环依赖的话就会返回false. var target = {}; var proto = Object.create(target); Reflect.setPrototypeOf(target, proto); // false
以上就是ES6新特性:JavaScript中的Reflect对象代码详解的内容,更多相关内容请关注PHP中文网(www.php.cn)!