cari
Rumahhujung hadapan webtutorial jsES6新特性:JavaScript中的Reflect对象代码详解

Reflect介绍:

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的原因, 译文地址: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 update

Reflect.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.setPrototypeOf(obj, newProto), 这个是新的方法去访问和设置对象的原型:

Reflect.apply的使用

Reflect.apply其实就是ES5中的 Function.prototype.apply() 替身, 执行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(&#39;harmony-reflect&#39;);

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)!



Kenyataan
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn
es6怎么判断是否为数组es6怎么判断是否为数组Apr 25, 2022 pm 06:43 PM

在es6中,可以利用“Array.isArray()”方法判断对象是否为数组,若判断的对象是数组,返回的结果是true,若判断对象不是数组,返回的结果是false,语法为“Array.isArray(需要检测的js对象)”。

es6中遍历跟迭代的区别是什么es6中遍历跟迭代的区别是什么Apr 26, 2022 pm 02:57 PM

es6中遍历跟迭代的区别是:遍历强调的是要把整个数据依次全部取出来,是访问数据结构的所有元素;而迭代虽然也是依次取出数据,但是并不保证取多少,也不保证把所有的数据取完,是遍历的一种形式。

es6中怎么判断两个对象是否相等es6中怎么判断两个对象是否相等Apr 19, 2022 pm 03:34 PM

在es6中,可用Object对象的is()方法来判断两个对象是否相等,该方法检测两个变量的值是否为同一个值,判断两个对象的引用地址是否一致,语法“Object.is(对象1,对象2)”;该方法会返回布尔值,若返回true则表示两个对象相等。

es6怎么将数字转为字符串es6怎么将数字转为字符串Apr 19, 2022 pm 06:38 PM

转换方法:1、利用“+”给数字拼接一个空字符,语法“数字+""”;2、使用String(),可把对象的值转换为字符串,语法“String(数字对象)”;3、用toString(),可返回数字的字符串表示,语法“数字.toString()”。

sort排序是es6中的吗sort排序是es6中的吗Apr 25, 2022 pm 03:30 PM

sort排序是es6中的;sort排序是es6中用于对数组的元素进行排序的方法,该方法默认不传参,按照字符编码顺序进行排序,排序顺序可以是字母或数字,并按升序或降序,语法为“array.sort(callback(a,b))”。

es6中assign的用法是什么es6中assign的用法是什么May 05, 2022 pm 02:25 PM

在es6中,assign用于对象的合并,可以将源对象的所有可枚举属性复制到目标对象;若目标对象与源对象有同名属性,或多个源对象有同名属性,则后面的属性会覆盖前面的属性,语法为“Object.assign(...)”

es6怎么改变数组数据es6怎么改变数组数据Apr 26, 2022 am 10:08 AM

改变方法:1、利用splice()方法修改,该方法可以直接修改原数组的内容,语法为“数组.splice(开始位置,修改个数,修改后的值)”;2、利用下标访问数组元素,并重新赋值来修改数组数据,语法为“数组[下标值]=修改后的值;”。

import as在es6中的用法是什么import as在es6中的用法是什么Apr 25, 2022 pm 05:19 PM

在es6中,import as用于将若干export导出的内容组合成一个对象返回;ES6的模块化分为导出与导入两个模块,该方法能够将所有的导出内容包裹到指定对象中,语法为“import * as 对象 from ...”。

See all articles

Alat AI Hot

Undresser.AI Undress

Undresser.AI Undress

Apl berkuasa AI untuk mencipta foto bogel yang realistik

AI Clothes Remover

AI Clothes Remover

Alat AI dalam talian untuk mengeluarkan pakaian daripada foto.

Undress AI Tool

Undress AI Tool

Gambar buka pakaian secara percuma

Clothoff.io

Clothoff.io

Penyingkiran pakaian AI

AI Hentai Generator

AI Hentai Generator

Menjana ai hentai secara percuma.

Artikel Panas

R.E.P.O. Kristal tenaga dijelaskan dan apa yang mereka lakukan (kristal kuning)
3 minggu yang laluBy尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. Tetapan grafik terbaik
3 minggu yang laluBy尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. Cara Memperbaiki Audio Jika anda tidak dapat mendengar sesiapa
3 minggu yang laluBy尊渡假赌尊渡假赌尊渡假赌
WWE 2K25: Cara Membuka Segala -galanya Di Myrise
3 minggu yang laluBy尊渡假赌尊渡假赌尊渡假赌

Alat panas

SublimeText3 versi Inggeris

SublimeText3 versi Inggeris

Disyorkan: Versi Win, menyokong gesaan kod!

SublimeText3 versi Cina

SublimeText3 versi Cina

Versi Cina, sangat mudah digunakan

Versi Mac WebStorm

Versi Mac WebStorm

Alat pembangunan JavaScript yang berguna

SublimeText3 versi Mac

SublimeText3 versi Mac

Perisian penyuntingan kod peringkat Tuhan (SublimeText3)

SublimeText3 Linux versi baharu

SublimeText3 Linux versi baharu

SublimeText3 Linux versi terkini