0

0

ES6新特性:JavaScript中的Reflect对象代码详解

黄舟

黄舟

发布时间:2017-03-07 14:24:12

|

1820人浏览过

|

来源于php中文网

原创

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来表示对象的属性是否设置上了, 如下代码可以重构:

立即学习Java免费学习笔记(深入)”;

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;
第三个参数为: 是一个数组或者伪数组, 会作为执行函数的参数;

Reflect.apply的DEMO:

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传第三个参数 , 第三个参数为一个超类, 新元素会继承这个超类;

所以我们可以用这个实现一个特殊的的数组, 继承数组, 但是也有自己的方法;

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的方式添加值;

如果我们执行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:

如果通过直接赋值的方式, 无论是否正确赋值, 都返回设置的值, 除非我们手动确认对象的属性值是否设置成功;

Reflect.deleteProperty的使用:

Reflect.deleteProperty和Reflect.defineProperty的使用方法差不多, Reflect.deleteProperty和 delete obj.xx的操作结果是一样, 区别是使用形式不同:一个是操作符,一个是函数调用;

ImgGood
ImgGood

免费在线AI照片编辑器

下载
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;

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



热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
拼多多赚钱的5种方法 拼多多赚钱的5种方法
拼多多赚钱的5种方法 拼多多赚钱的5种方法

在拼多多上赚钱主要可以通过无货源模式一件代发、精细化运营特色店铺、参与官方高流量活动、利用拼团机制社交裂变,以及成为多多进宝推广员这5种方法实现。核心策略在于通过低成本、高效率的供应链管理与营销,利用平台社交电商红利实现盈利。

28

2026.01.26

edge浏览器怎样设置主页 edge浏览器自定义设置教程
edge浏览器怎样设置主页 edge浏览器自定义设置教程

在Edge浏览器中设置主页,请依次点击右上角“...”图标 > 设置 > 开始、主页和新建标签页。在“Microsoft Edge 启动时”选择“打开以下页面”,点击“添加新页面”并输入网址。若要使用主页按钮,需在“外观”设置中开启“显示主页按钮”并设定网址。

8

2026.01.26

苹果官方查询网站 苹果手机正品激活查询入口
苹果官方查询网站 苹果手机正品激活查询入口

苹果官方查询网站主要通过 checkcoverage.apple.com/cn/zh/ 进行,可用于查询序列号(SN)对应的保修状态、激活日期及技术支持服务。此外,查找丢失设备请使用 iCloud.com/find,购买信息与物流可访问 Apple (中国大陆) 订单状态页面。

31

2026.01.26

npd人格什么意思 npd人格有什么特征
npd人格什么意思 npd人格有什么特征

NPD(Narcissistic Personality Disorder)即自恋型人格障碍,是一种心理健康问题,特点是极度夸大自我重要性、需要过度赞美与关注,同时极度缺乏共情能力,背后常掩藏着低自尊和不安全感,影响人际关系、工作和生活,通常在青少年时期开始显现,需由专业人士诊断。

3

2026.01.26

windows安全中心怎么关闭 windows安全中心怎么执行操作
windows安全中心怎么关闭 windows安全中心怎么执行操作

关闭Windows安全中心(Windows Defender)可通过系统设置暂时关闭,或使用组策略/注册表永久关闭。最简单的方法是:进入设置 > 隐私和安全性 > Windows安全中心 > 病毒和威胁防护 > 管理设置,将实时保护等选项关闭。

5

2026.01.26

2026年春运抢票攻略大全 春运抢票攻略教你三招手【技巧】
2026年春运抢票攻略大全 春运抢票攻略教你三招手【技巧】

铁路12306提供起售时间查询、起售提醒、购票预填、候补购票及误购限时免费退票五项服务,并强调官方渠道唯一性与信息安全。

35

2026.01.26

个人所得税税率表2026 个人所得税率最新税率表
个人所得税税率表2026 个人所得税率最新税率表

以工资薪金所得为例,应纳税额 = 应纳税所得额 × 税率 - 速算扣除数。应纳税所得额 = 月度收入 - 5000 元 - 专项扣除 - 专项附加扣除 - 依法确定的其他扣除。假设某员工月工资 10000 元,专项扣除 1000 元,专项附加扣除 2000 元,当月应纳税所得额为 10000 - 5000 - 1000 - 2000 = 2000 元,对应税率为 3%,速算扣除数为 0,则当月应纳税额为 2000×3% = 60 元。

12

2026.01.26

oppo云服务官网登录入口 oppo云服务登录手机版
oppo云服务官网登录入口 oppo云服务登录手机版

oppo云服务https://cloud.oppo.com/可以在云端安全存储您的照片、视频、联系人、便签等重要数据。当您的手机数据意外丢失或者需要更换手机时,可以随时将这些存储在云端的数据快速恢复到手机中。

40

2026.01.26

抖币充值官方网站 抖币性价比充值链接地址
抖币充值官方网站 抖币性价比充值链接地址

网页端充值步骤:打开浏览器,输入https://www.douyin.com,登录账号;点击右上角头像,选择“钱包”;进入“充值中心”,操作和APP端一致。注意:切勿通过第三方链接、二维码充值,谨防受骗

7

2026.01.26

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
ECMAScript6 / ES6---十天技能课堂
ECMAScript6 / ES6---十天技能课堂

共25课时 | 2万人学习

HTML5/CSS3/JavaScript/ES6入门课程
HTML5/CSS3/JavaScript/ES6入门课程

共102课时 | 6.8万人学习

HTML+CSS基础与实战
HTML+CSS基础与实战

共132课时 | 9.7万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号