好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

ES6+ Reflect(一)

ES6+ Reflect(一)

1. 前言

任何一门语言在走向成熟的过程都是趋向精细化和规范化,在 API 设计之初满足当时的需求场景。随着前端的飞速发展,软件复杂度的提升,很多 API 在使用过程中存在很多使用别扭的情况,不符合软件开发的规范。上一节我们学习了 Proxy,Proxy 的设计目的是为了取代 Object.defineProperty,优化 性能 ,使得数据劫持的过程更加规范。

本节我们将学习 ES6 新的全局对象 —— Reflect(反射),首先我们要了解一下,为什么会新 添加 这么 一个 全局对象?Reflect 上的一些 函数 基本上都可以在 Object 上找到,找不到的,也是可以通过对对象命令式的操作去实现的;那么为什么还要新 添加 一个 呢?本节我们将学习 Reflect 的相关知识。

2. 基础知识

Reflect 是 一个 内置的对象,它提供了 拦截 JavaScript 操作的 方法 。这些 方法 与 Proxy 中的 handlers 方法 相同。与大多数全局对象不同 Reflect 并非 一个 构造 函数 ,所以不能通过 new 运算符对其进行 调用 ,或者将 Reflect 对象作为 一个 函数 来 调用 。 Reflect 的所有 属性 和 方法 都是静态的(类似 JSON 或者 Math 等对象)。

2.1 基本 用法

Reflect 可以检查对象上是否存在特定 属性 ,可以使用 Reflect.has() 方法 检测。

  let  key  =  Symbol .  for  (  'a'  )  ; 
 const  obj  =   { 
  name :   'imooc'  , 
  lession :   'ES6 Wiki'  , 
   [ key ]  :  
 } 

console .  log  ( Reflect .  has  ( obj ,   'name'  )  )  ; 	 // true 
console .  log  ( Reflect .  has  ( obj ,   'age'  )  )  ; 		 // false 
 

可以使用 Reflect.get() 方法 获取 对象上的 属性 值。

 console .  log  ( Reflect .  get  ( obj ,   'name'  )  )  ; 	 // imooc 
 

可以使用 Reflect.set() 方法 为对象 添加 一个 新的 属性 。

  const  res  =  Reflect .  set  ( obj ,   'age'  ,   )  ; 
console .  log  ( res )  ; 		 // true 
console .  log  ( obj )  ; 		 // {name: "imooc", lession: "ES6 Wiki", age: 7} 
 

使用 Reflect.ownKeys() 方法 获取 对象上的自有 属性 。

 console .  log  ( Object .  keys  ( obj )  )  ; 	 // ["name", "lession"] 

console .  log  ( Reflect .  ownKeys  ( obj )  )  ; 	 // ["name", "lession", Symbol(a)] 
 

上面的 代码 可以看出,使用 Object.keys() 获取 不到 属性 是 Symbol 的值。

2.2 返回值

Reflect 对象上的 方法 并不是专门为对象设计的,而是在语言层面的,它可以拿到语言内部的 方法 ,和 Proxy 的结合可以实现元编程。并且每个操作都是有返回值的,上节我们使用 Proxy 简单地实现了 Vue3 的响应式。但是在 Vue3 源码中 获取 和设置对象上的 属性 使用的是 Reflect,Reflect 会返回 一个 状态表示 获取 和设置的成功与否。

  // const res = target[key]; // 上节 代码  
 const  res  =  Reflect .  get  ( target ,  key )  ; 	 //  获取 target上 属性 key的值 

 // target[key] = value;	// 上节 代码  
 const  result  =  Reflect .  set  ( target ,  key ,  value )  ; 	 // 设置目标对象key 属性 的值 
 

上面的两段 代码 是 Vue3 中的源码,因为在源码中需要知道 获取 或赋值的结果,因为可能 获取 失败。在 ES5 中如果想要监听劫持 属性 操作的结果需要使用 try...catch 的方式。

  try   { 
  Object .  defineProperty  ( obj ,  prop ,  descriptor )  ; 
   // success 
 }   catch   (  e  )   { 
   // failure 
 } 
 

Reflect 在操作对象时是有返回结果的,而 Object.defineProperty 是没有返回结果的,如果失败则会抛出异常,所以需要使用 try...catch 来捕获异常。

2.3 使用 函数 代替命令式

Object 中操作数据时,有一些是命令式的操作,如: delete obj.a 、 name in obj ,Reflect 则将一些命令式的操作如 delete , in 等使用 函数 来替代,这样做的目的是为了让 代码 更加好维护,更容易向下兼容;也避免出现更多的保留字。

  // ES5 
 'assign'   in  Object  // true 
 // ES6 
Reflect .  has  ( Object ,   'assign'  )   // true 

 delete  obj . name ; 	 // ES5 
Reflect .  deleteProperty  ( obj ,   'name'  )  ; 	 // ES6 
 

3. 静态 方法

Reflect 的出现是为了取代 Object 中一些属于语言层面的 API,这些 API 在 Object 上也是可以找到的,并且它们的 功能 基本是相同的。上面我们也提到了 Reflect 和 Proxy 中 handlers 的 方法 是一一对应的,在很多场景中它门都是配套使用的。这里我们就来学习一下 Reflect 提供的静态 方法 :

3.1 Reflect.get()

Reflect.get() 方法 是从对象中读取 属性 的值,类似 ES5 中 属性 访问器语法: obj[key] ,但是它是通过 调用 函数 来获得返回结果的。

语法:

 Reflect .  get  ( target ,  propertyKey [  ,  receiver ]  ) 
 

target:需要取值的目标对象; propertyKey:需要 获取 的值的键值; receiver:如果 target 对象中指定了 getter,receiver 则为 getter 调用 时的 this 值。

如果目标值 target 类型不是 Object ,则抛出 一个 TypeError 。

  // Object 
 var  obj  =   {  a :   ,  b :    }  ; 
Reflect .  get  ( obj ,   "a"  )  ;   // 1 

 // Array 
Reflect .  get  (  [  "a"  ,   "b"  ,   "c"  ]  ,   )  ;   // "one" 
 

第三个参数 receiver 是 this 所在的上下文,不传时指的是当前对象,如果传如 一个 人对象则 this 指向该对象。下面我们来看个实例:

  let  obj  =   { 
  name :   'imooc'  , 
  lesson :   'ES5 Wiki'  , 
   get   info  (  )   { 
    console .  log  (   `这是    ${  this  . lesson }   `   )  ; 
     return  
   } 
 }  ; 
Reflect .  get  ( obj ,   'info'  )  ; 	 // 这是 ES5 Wiki 
Reflect .  get  ( obj ,   'info'  ,   { lesson :   'ES6 Wiki'  }  )  ; 	 // 这是 ES5 Wiki 
 

3.2 Reflect.set()

Reflect.set() 是在 一个 对象上设置 一个 属性 ,类似 ES5 中 属性 设置语法: obj[key] = value ,它也是通过 调用 函数 的方式来对对象设置 属性 的。

语法:

 Reflect .  set  ( target ,  propertyKey ,  value [  ,  receiver ]  ) 
 

target:表示要操作的目标对象; propertyKey:表示要设置的 属性 名; value:表示设置的 属性 值; receiver:表示的是 一个 this 值,如果我们在设置值的时候遇到 setter 函数 ,那么这个 receiver 值表示的就是 setter 函数 中的 this 值。

这个 函数 会返回 一个 Boolean 值,表示在目标对象上设置 属性 是否成功。

  // Object 
 var  obj  =   {  }  ; 
Reflect .  set  ( obj ,   "name"  ,   "imooc"  )  ;   // true 
console .  log  ( obj . name )  ;   // "imooc" 

 // Array 
 var  arr  =   [  "a"  ,   "b"  ,   "c"  ]  ; 
Reflect .  set  ( arr ,   ,   "C"  )  ;   // true 
console .  log  ( arr )  ;   // ["a", "b", "C"] 
 

使用可以截断数组:

  var  arr  =   [  "a"  ,   "b"  ,   "c"  ]  ; 
Reflect .  set  ( arr ,   "length"  ,   )  ;   // true 
console .  log  ( arr )  ; 	 // ["a", "b"] 
 

当有 receiver 参数时,如果 receiver 对象中有 propertyKey 属性 ,则会使用 receiver 对象中的值。

 Reflect .  set  ( obj ,   'lession'  ,   'ES5 Wiki'  ,   { lession :   'ES6 Wiki'  ,  age :   }  )  ; 
console .  log  ( obj )  ; 	 // {name: "imooc", lesson: "ES5 Wiki"} 
 

3.3 Reflect.delete property()

Reflect.delete property() 方法 允许 删除 对象的 属性 。它类似 ES5 中的 delete 操作符,但它也是 一个 函数 ,通过 调用 函数 来实现。

语法:

 Reflect .  deleteProperty  ( target ,  propertyKey ) 
 

target:表示要操作的目标对象; propertyKey:表示要 删除 的 属性 。

这个 函数 的返回值是 一个 Boolean 值,如果成功的话,返回 true;失败的话返回 false。我们来看下面的实例:

  var  obj  =   { 
    name :   'imooc'  , 
    lession :   'ES6 Wiki' 
 }  ; 

 var  r1  =  Reflect .  deleteProperty  ( obj ,   'name'  )  ; 
console .  log  ( r1 )  ;   // true 
console .  log  ( obj )  ;   // {lession: "ES6 Wiki"} 

 var  r2  =  Reflect .  deleteProperty  ( Object .  freeze  ( obj )  ,   'lession'  )  ; 
console .  log  ( r2 )  ;   // false 
 

上面的例子中使用 Object.freeze() 方法 来冻结 obj 对象使之不能被 修改 。

3.4 Reflect.has()

Reflect.has() 方法 可以检查 一个 对象上是否含有特定的 属性 ,这个 方法 相当于 ES5 的 in 操作符。

语法:

 Reflect .  has  ( target ,  propertyKey ) 
 

target:表示要操作的目标对象; propertyKey: 属性 名,表示需要检查目标对象是否存在此 属性 。

这个 函数 的返回结果是 一个 Boolean 值,如果存在就返回 true,不存在就返回 false。当然如果目标对象 (target) 不是 一个 对象,那么就会抛出 一个 异常。

 Reflect .  has  (  { x :   }  ,   "x"  )  ;   // true 
Reflect .  has  (  { x :   }  ,   "y"  )  ;   // false 

 // 如果该 属性 存在于原型链中,也返回true  
Reflect .  has  (  { x :   }  ,   "toString"  )  ; 	 // true 
 

这 方法 也可检查构造 函数 的 属性 。

  function   A  ( name )   { 
     this  . name  =  name  ||   'imooc'  ; 
 } 
 // 在原型上 添加  方法  
A . prototype .  getName   =   function  (  )   { 
     return   this  . name ; 
 }  ; 

 var  a  =   new   A  (  )  ; 

console .  log  (  'name'   in  a )  ;   // true 
console .  log  (  'getName'   in  a )  ;   // true 

 let  r1  =  Reflect .  has  ( a ,   'name'  )  ; 
 let  r2  =  Reflect .  has  ( a ,   'getName'  )  ; 
console .  log  ( r1 ,  r2 )  ;   // true true 
 

3.5 Reflect.ownKeys()

Reflect.ownKeys() 返回 一个 由目标对象自身的 属性 键组成的数组。

语法:

 Reflect .  ownKeys  ( target ) 
 

target:表示目标对象

如果这个目标对象不是 一个 对象那么这个 函数 就会抛出 一个 异常。这个数组的值等于 Object.g eto wnPropertyNames(target).concat(Object.g eto wnPropertySymbols(target)) 我们来看下面的实例:

  let  a  =  Symbol .  for  (  'a'  )  ; 
 let  b  =  Symbol .  for  (  'b'  )  ; 

 let  obj  =   { 
     [ a ]  :   , 
     [ b ]  :   , 
    key1 :   , 
    key2 :  
 }  ; 

 let  arr1  =  Object .  g eto wnPropertyNames  ( obj )  ; 
console .  log  ( arr1 )  ;   // [ 'key1', 'key2' ] 
 let  arr2  =  Object .  g eto wnPropertySymbols  ( obj )  ; 
console .  log  ( arr2 )  ;   // [ Symbol(a), Symbol(b) ] 
 let  arr3  =  Reflect .  ownKeys  ( obj )  ; 
console .  log  ( arr3 )  ;   // [ 'key1', 'key2', Symbol(a), Symbol(b) ] 
 

4. 小结

本节主要学习了 ES6 新增的全局对象 Reflect ,它的目的是为了分离 Object 中属于语言部分的 内容 ,每个使用 Reflect 下的 方法 操作的对象都要返回值。 Reflect 对象和 Proxy 下的 方法 是一一对应的,二者配合可以实现很多 功能 。Vue3 中的数据响应就是使用的它们。

查看更多关于ES6+ Reflect(一)的详细内容...

  阅读:42次

上一篇

下一篇

第1节:ES6+ 简介    第2节:ES6 环境配置    第3节:ES6+ let    第4节:ES6+ const    第5节:ES6+ 展开语法    第6节:ES6+ 剩余参数    第7节:ES6+ 解构赋值    第8节:ES6+ 模版字符串    第9节:ES6+ 箭头函数    第10节:ES6+ 数值扩展    第11节:ES6+ isFinite()&isNaN()    第12节:ES6+ Number 对象的方法    第13节:ES6+ Math 对象的扩展    第14节:ES6+ includes()    第15节:ES6+ 字符串的扩展    第16节:ES6+ startsWith()    第17节:ES6+ endsWith()    第18节:ES6+ repeat()    第19节:ES6+ padStart()    第20节:ES6+ padEnd()    第21节:ES6+ trim()    第22节:ES6+ Array.from()    第23节:ES6+ of()    第24节:ES6+ find()和findIndex()    第25节:ES6+ copyWithin()    第26节:ES6+ fill()    第27节:ES6+ isArray()    第28节:ES6+ 对象的扩展    第29节:ES6+ flat()    第30节:ES6+ 可选链操作符    第31节:ES6+ Object.is()    第32节:ES6+ Object.assign()    第33节:ES6+ Object.keys()    第34节:ES6+ Object.values()    第35节:ES6+ Object.entries()    第36节:ES6+ 数据结构扩展    第37节:ES6+ Set    第38节:ES6+ WeakSet    第39节:ES6+ Map    第40节:ES6+ WeakMap    第41节:ES6+ Symbol    第42节:ES6+ for...of    第43节:ES6+ 迭代协议    第44节:ES6+ 实现一个简版的 Promise    第45节:ES6+ Promise 基础    第46节:ES6+ Promise 进阶    第47节:ES6+ Generator 基础    第48节:ES6+ Generator 函数应用    第49节:ES6+ async/await    第50节:ES6+ Class 前置知识    第51节:ES6+ Class    第52节:ES6+ Proxy    第53节:ES6+ Reflect(一)    第54节:ES6+ Reflect(二)    第55节:ES6+ 模块化(一)    第56节:ES6+ 模块化(二)    第57节:ES6实战1-实现Vue3 reactive 源码    第58节:ES6实战2-实现 Vue3 effect 源码    第59节:ES6 实战2-封装请求    第60节:ES6+ 实战3-代码整洁之道    第61节:ES6 Map原理分析    第62节:ES6module语法加载importexport    第63节:ES6的循环与可迭代对象示例详解