前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >全面梳理JS对象的访问控制及代理反射

全面梳理JS对象的访问控制及代理反射

作者头像
江米小枣
发布2020-06-16 11:01:56
2.2K1
发布2020-06-16 11:01:56
举报
文章被收录于专栏:云前端

在 Javascript 中,读取、赋值、调用方法等等,几乎一切操作都是围绕“对象”展开的;长久以来,如何更好的了解和控制这些操作,就成了该语言发展中的重要问题。

I. JS对象的访问控制

[1.1] 熟悉的 getter/setter

所谓 getter/setter,其定义一般为:

  • 一个 getter 方法不接受任何参数,且总是返回一个值
  • 一个 setter 总是接受一个参数,且并不会返回值

一些 getter/setter 的常识:

  • 也被称为存取方法,是访问方法(access methods)中最常用的两个
  • 用来封装私有成员方法,以隔离外界对其的直接访问
  • 也可以在存取过程中添加其他的逻辑,保证了外部调用的简洁性
  • 实现了对象或类内部逻辑的灵活性,保留了改变的可能
  • 在很多 IDE 中可以自动生成

首先看看其他语言中一般的实现方式:

一种是传统的显式 getXXX()/setXXX(v) 方法调用

代码语言:javascript
复制
//JAVA
public class People {
   private Integer _age;
   
   public Integer getAge() {
       return this._age;
   }
   public void setAge(Integer age) {
       this._age = age;
   }
   
   public static void main(String[] args) {
   
       People p = new People();
       p.setAge(18);
       System.out.println(p.getAge().toString()); //18
       
   }
}

毫无疑问,显式调用命名其实是随意的,而且各种语言都能实现

另一种是隐式(implicit)的 getter/setter

代码语言:javascript
复制
//AS2
class Login2 {
   private var _username:String;
   
   public function get userName():String {
       return this._username;
   }
   public function set userName(value:String):Void {
       this._username = value;
   }
}var lg = new Login2;
lg.userName = "tom";
trace(lg.userName); //"tom"
代码语言:javascript
复制
//C#
class People
{  
   private string _name;  
   
   public string name
   {  
       get {
           return _name;
       }  
       set {
           _name = value;
       }  
   }  
}People p = new People();
p.name = "tom";
Console.WriteLine(p.name)
代码语言:javascript
复制
//PHP
class MyClass {
 private $firstField;
 private $secondField; public function __get($property) {
   if (property_exists($this, $property)) {
     return $this->$property;
   }
 }
 public function __set($property, $value) {
   if (property_exists($this, $property)) {
     $this->$property = $value." world";
   }
 }
}$mc = new MyClass;
$mc->firstField = "hello";
echo $mc->firstField; //"hello world"

隐式存取方法需要特定语言的支持,使用起来感觉就是读取属性(var x = obj.x)或给属性赋值(obj.x = "foo"

[1.2] ES5 中的 getter 和 setter

从 2011 年的 ECMAScript 5.1 (ECMA-262) 规范开始,JavaScript 也开始支持 getter/setter;形式上,自然是和同为 ECMAScript 实现的 AS2/AS3 相同

getter 的语法:

代码语言:javascript
复制
// prop 指的是要绑定到给定函数的属性名
{get prop() { ... } }// 还可以使用一个计算属性名的 expression 绑定到给定的函数, 注意浏览器兼容性
{get [expression]() { ... } }

? 例子:

代码语言:javascript
复制
var obj = {
 log: ['example','test'],
 get latest() {
   if (this.log.length == 0) return undefined;
   return this.log[this.log.length - 1];
 }
}
console.log(obj.latest); // "test"var expr = 'foo';
var obj2 = {
 get [expr]() { return 'bar'; }
};
console.log(obj2.foo); // "bar"

使用 get 语法时应注意以下问题:

  • 可以使用数值或字符串作为标识
  • 必须不带参数
  • 不能与另一个get或具有相同属性的数据条目的对象字面量中出现

通过 delete 操作符删除 getter:

代码语言:javascript
复制
delete obj.latest;

以下展示了一种进阶的用法,即首次调用时才取值(lazy getter),并且将 getter 转为普通数据属性:

代码语言:javascript
复制
get notifier() {
 delete this.notifier;
 return this.notifier = document.getElementById('myId');
},

setter 的语法:

代码语言:javascript
复制
//prop 指的是要绑定到给定函数的属性名
//val 指的是分配给prop的值
{set prop(val) { . . . }}// 还可以使用一个计算属性名的 expression 绑定到给定的函数, 注意浏览器兼容性
{set [expression](val) { . . . }}

使用 set 语法时应注意以下问题:

  • 标识符可以是数字或字符串
  • 必须有一个明确的参数
  • 在同一个对象中,不能为一个已有真实值的变量使用 set ,也不能为一个属性设置多个 set

? 例子:

代码语言:javascript
复制
var language = {
 set current(name) {
   this.log.push(name);
 },
 log: []
}
language.current = 'EN';
console.log(language.log); // ['EN']
language.current = 'FA';
console.log(language.log); // ['EN', 'FA']var expr = "foo";
var obj = {
 baz: "bar",
 set [expr](v) { this.baz = v; }
};
console.log(obj.baz); // "bar"
obj.foo = "baz";      // run the setter
console.log(obj.baz); // "baz"

setter 可以用delete操作来移除:

代码语言:javascript
复制
delete o.current;

[1.4] 用 Object.defineProperty() 精确定义对象成员

回顾前面提到过的,对象里存在的属性描述符有两种主要形式:数据属性和存取方法。描述符必须是两种形式之一,不能同时是两者。

并且在一般情况下,通过赋值来为对象添加的属性,可以由 for...in 或 Object.keys 方法遍历枚举出来;且通过这种方式添加的属性值可以被改变,也可以被删除。

代码语言:javascript
复制
var obj = {
   _c: 99,
   get c() {
       return this._c;
   }
};
obj.a = 'foo';
obj.b = function() {
   alert("hello world!");
};console.log( Object.keys(obj) ); //["_c", "c", "a", "b"]for (var k in obj) console.log(k); //"_c", "c", "a", "b"delete obj.b;
delete obj.c;
console.log(obj.b, obj.c); //undefined, undefined

对于这样定义的数据属性或存取方法,无法控制其是否可被 delete,也无法限制其是否能被枚举

而使用 Object.defineProperty() 则允许改变这些默认设置

同样从 ECMAScript 5.1 规范开始,定义了 Object.defineProperty() 方法。用于直接在一个对象上定义一个新属性,或者修改一个对象的现有属性, 并返回这个对象

其语法为:

代码语言:javascript
复制
//obj 需要被操作的目标对象
//prop 目标对象需要定义或修改的属性的名称
//descriptor 将被定义或修改的属性的描述符
Object.defineProperty(obj, prop, descriptor)

其中 descriptor 可以设置的属性为:

属性

描述

应用于

configurable

是否能被修改及删除

数据属性、存取方法

enumerable

是否可被枚举

数据属性、存取方法

value

属性值

数据属性

writable

是否能被赋值运算符改变

数据属性

get

getter 方法

存取方法

set

setter 方法

存取方法

需要了解的是,从 IE8 开始有限支持这个方法(非 DOM 对象不可用)

? 例子:

代码语言:javascript
复制
var o = {};o.a = 1;
// 等同于 :
Object.defineProperty(o, "a", {
 value : 1,
 writable : true,
 configurable : true,
 enumerable : true
});
代码语言:javascript
复制
var o = {};var bValue;
Object.defineProperty(o, "b", {
 get : function(){ //添加存取方法
   return bValue;
 },
 set : function(newValue){
   bValue = newValue;
 },
 enumerable : true,
 configurable : true
});
代码语言:javascript
复制
var o = {};Object.defineProperty(o, "a", {
   value : 37,
   writable : false //定义了一个“只读”的属性
});console.log(o.a); // 37
o.a = 25; // 在严格模式下会抛出错误,非严格模式只是不起作用
console.log(o.a); // 37
代码语言:javascript
复制
var o = {};
Object.defineProperty(o, "a", {
   get : function(){return 1;},
   configurable : false //不可编辑、不可删除
});// throws a TypeError
Object.defineProperty(o, "a", {configurable : true});
// throws a TypeError
Object.defineProperty(o, "a", {enumerable : true});
// throws a TypeError
Object.defineProperty(o, "a", {set : function(){}});
// throws a TypeError
Object.defineProperty(o, "a", {get : function(){return 1;}});
// throws a TypeError
Object.defineProperty(o, "a", {value : 12});console.log(o.a); //1
delete o.a; // 在严格模式下会抛出TypeError,非严格模式只是不起作用
console.log(o.a); //1
代码语言:javascript
复制
Object.defineProperty(o, "conflict", {
 value: 0x9f91102,
 get: function() {
   return 0xdeadbeef;
 }
}); //抛出 TypeError,数据属性和存取方法不能混合设置

相关方法:Object.getOwnPropertyDescriptor()

返回指定对象上一个自有属性对应的属性描述符。(自有属性指的是直接赋予该对象的属性,而非从原型链上进行查找的属性)

语法:

代码语言:javascript
复制
//其中 prop 对应于 Object.defineProperty() 中第三个参数 descriptor
Object.getOwnPropertyDescriptor(obj, prop)

? 例子:

代码语言:javascript
复制
var o = {
   get foo() {
       return 17;
   }
};Object.getOwnPropertyDescriptor(o, "foo");
// {
//   configurable: true,
//   enumerable: true,
//   get: /*the getter function*/,
//   set: undefined
// }

相关方法:Object.defineProperties()

直接在一个对象上定义多个新的属性或修改现有属性

语法:

代码语言:javascript
复制
//prop 和 descriptor 的定义对应于 Object.defineProperty()
Object.defineProperties(obj, {
   prop1: descriptor1,
   prop2: descriptor2,
   ...
})

? 例子:

代码语言:javascript
复制
var obj = {};
Object.defineProperties(obj, {
 'property1': {
   value: true,
   writable: true
 },
 'property2': {
   value: 'Hello',
   writable: false
 }
});

相关方法:Object.create()

使用指定的原型对象及其属性去创建一个新的对象

语法:

代码语言:javascript
复制
//proto 为新创建对象的原型对象
//props 对应于 Object.defineProperties() 中的第二个参数
Object.create(proto[, props])

? 例子:

代码语言:javascript
复制
// 创建一个原型为null的空对象
var o = Object.create(null);var o2 = {};
// 以字面量方式创建的空对象就相当于:
var o2 = Object.create(Object.prototype);
代码语言:javascript
复制
var foo = {a:1, b:2};
var o = Object.create(foo, {
 // foo会成为所创建对象的数据属性
 foo: {
   writable:true,
   configurable:true,
   value: "hello"
 },
 // bar会成为所创建对象的访问器属性
 bar: {
   configurable: false,
   get: function() { return 10 },
   set: function(value) {
     console.log("Setting `o.bar` to", value);
   }
 }
});

[1.5] __define[G,S]etter__()

作为非标准已废弃的方法,defineGetter() 和 defineSetter() 有时会出现在一些历史代码中,并仍能运行在 Firefox/Safari/Chrome 等浏览器中

? 直接看例子:

代码语言:javascript
复制
var o = {
   word: null
};o.__defineGetter__('gimmeFive', function() {
   return 5;
});
console.log(o.gimmeFive); // 5o.__defineSetter__('say', function(vlu) {
   this.word = vlu;
});
o.say = "hello";
console.log(o.word); //"hello"

[1.6] __lookup[G,S]etter__()

同样,还有 lookupGetter() 和 lookupSetter() 两个非标准已废弃的方法

  • lookupGetter() 会返回对象上某个属性的 getter 函数

? 例子:

代码语言:javascript
复制
var obj = {
   get foo() {
       return Math.random() > 0.5 ? "foo" : "bar";
   }
};obj.__lookupGetter__("foo")
// (function (){return Math.random() > 0.5 ? "foo" : "bar"})

如果换成标准的方法,则是:

代码语言:javascript
复制
Object.getOwnPropertyDescriptor(obj, "foo").get
// (function (){return Math.random() > 0.5 ? "foo" : "bar"})

而如果那个访问器属性是继承来的:

代码语言:javascript
复制
Object.getOwnPropertyDescriptor(Object.getPrototypeOf(obj), "foo").get
// function __proto__() {[native code]}
  • lookupSetter() 会返回对象的某个属性的 setter 函数

? 例子:

代码语言:javascript
复制
var obj = {
 set foo(value) {
   this.bar = value;
 }
};obj.__lookupSetter__('foo')
// (function(value) { this.bar = value; })// 标准且推荐使用的方式。
Object.getOwnPropertyDescriptor(obj, 'foo').set;
// (function(value) { this.bar = value; })

[1.7] 用 onpropertychange 兼容古早浏览器

在某些要求兼容 IE6/IE7 等浏览器的极端情况下,利用 IE 支持的 onpropertychange 事件,也是可以模拟 getter/setter 的

要注意这种方法仅限于已加载到文档中的 DOM 对象

代码语言:javascript
复制
function addProperty(obj, name, onGet, onSet) {
   var
       oldValue = obj[name],
       getter = function () {
           return onGet.apply(obj, [oldValue]);
       },
       setter = function (newValue) {
           return oldValue = onSet.apply(obj, [newValue]);
       },
       onPropertyChange = function (event) {
           if (event.propertyName == name) {
               // 暂时移除事件监听以免循环调用
               obj.detachEvent("onpropertychange", onPropertyChange);
               // 把改变后的值传递给 setter
               var newValue = setter(obj[name]);
               // 设置 getter
               obj[name] = getter;
               obj[name].toString = getter;
               // 恢复事件监听
               obj.attachEvent("onpropertychange", onPropertyChange);
           }
       };
   // 设置 getter
   obj[name] = getter;
   obj[name].toString = getter;
   
   obj.attachEvent("onpropertychange", onPropertyChange);
}

II. JS中的代理和反射

在对象本身上,一个个属性的定义访问控制,有时会带来代码臃肿,甚至难以维护;了解代理和反射的概念和用法,可以有效改善这些状况。

[2.1] 传统的代理模式

在经典的设计模式(Design Pattern)中,代理模式(Proxy Pattern)被广泛应用;其定义为:

在代理模式中,一个代理对象(Proxy)充当着另一个目标对象(Real Subject)的接口。代理对象居于目标对象的用户(Client)和目标对象本身的中间,并负责保护对目标对象的访问。

典型的应用场景为:

  • 对目标对象的访问控制和缓存
  • 延迟目标对象的初始化
  • 访问远端对象

? 举个例子:

代码语言:javascript
复制
function Book(id, name) {
   this.id = id;
   this.name = name;
}function BookShop() {
   this.books = {};
}
BookShop.prototype = {
   addBook: function(book) {
       this.books[book.id] = book;
   },
   findBook: function(id) {
       return this.books[id];
   }
}function BookShopProxy() {
}
BookShopProxy.prototype = {
   _init: function() {
       if (this.bookshop)
           return;
       else
           this.bookshop = new BookShop;
   },
   addBook: function(book) {
       this._init();
       if (book.id in this.bookshop.books) {
           console.log('existed book!', book.id);
           return;
       } else {
           this.bookshop.addBook(book);
       }
   },
   findBook: function(id) {
       this._init();
       if (id in this.bookshop.books)
           return this.bookshop.findBook(id);
       else
           return null;
   }
}var proxy = new BookShopProxy;
proxy.addBook({id:1, name:"head first design pattern"});
proxy.addBook({id:2, name:"thinking in java"});
proxy.addBook({id:3, name:"lua programming"});
proxy.addBook({id:2, name:"thinking in java"}); //existed book! 2console.log(proxy.findBook(1)); //{ id: 1, name: 'head first design pattern' }
console.log(proxy.findBook(3)); //{ id: 3, name: 'lua programming' }

显然,以上示例代码中展示了使用代理来实现延迟初始化访问控制

值得一提的是,代理模式与设计模式中另一种装饰者模式(Decorator Pattern)容易被混淆,两者的相同之处在于都是对原始的目标对象的包装;不同之处在于,前者着眼于提供与原始对象相同的API,并将对其的访问控制保护起来,而后者则侧重于在原有API的基础上添加新的功能。

[2.2] ES6 中的 Proxy

在 ECMAScript 2015 (6th Edition, ECMA-262) 标准中,提出了原生的 Proxy 对象。用于定义基本操作的自定义行为(如属性查找,赋值,枚举,函数调用等)

语法:

代码语言:javascript
复制
let p = new Proxy(target, handler);

proxy 对象的目标对象 target,可以是任何类型的对象,如 Object、Array、Function,甚至另一个 Proxy 对象;在进行let proxy=new Proxy(target,handle)的操作后,proxy、target两个对象会相互影响。即:

代码语言:javascript
复制
let target = {
   _prop: 'foo',
   prop: 'foo'
};
let proxy = new Proxy(target, handler);
proxy._prop = 'bar';
target._attr = 'new'
console.log(target._prop) //'bar'
console.log(proxy._attr) //'new'

handler 也是一个对象,其若干规定好的属性是定义好一个个函数,表示了当执行目标对象的对应访问时所执行的操作;最常见的操作是定义 getter/setter 的 get 和 set 属性:

代码语言:javascript
复制
let handler = {
   get (target, key){
       return key in target
           ? target[key]
           : -1; //默认值
   },
   set (target, key, value) {
       if (key === 'age') { //校验
           target[key] = value > 0 && value < 100 ? value : 0
       }
       return true;
   }
};let target = {};
let proxy = new Proxy(target, handler);
proxy.age = 22 //22

可以注意到,和 ES5 中对象本身的 setter 不同的是, proxy 中的 setter 必须有返回值;

并且应该也很容易理解,不光是名字相同,Proxy 对象也的确符合经典的代理模式 -- 由代理对象对目标对象的 API 进行封装和保护,隐藏目标对象,控制对其的访问行为。

除了可以定义 getter/setter,较完整的 handler 属性如下:

  • "get": function (oTarget, sKey)
  • "set": function (oTarget, sKey, vValue)
  • "enumerate": function (oTarget, sKey)
  • "ownKeys": function (oTarget, sKey)
  • "has": function (oTarget, sKey)
  • "defineProperty": function (oTarget, sKey, oDesc)
  • "deleteProperty": function (oTarget, sKey)
  • "getOwnPropertyDescriptor": function (oTarget, sKey)
  • "getPrototypeOf(oTarget)"
  • "setPrototypeOf(oTarget, oPrototype)"
  • "apply(oTarget, thisArg, argumentsList)":
  • "construct(oTarget, argumentsList, newTarget)"
  • "isExtensible(oTarget)"
  • "preventExtensions(oTarget)"

[2.3] 反射

对象的反射(reflection)是一种在运行时(runtime)探查和操作对象属性的语言能力。

在 JAVA/AS3 等语言中,反射一般被用于在运行时获取某个对象的类名、属性列表,然后再动态构造等;比如通过 XML 配置文件中的值动态创建对象,或者根据名称提取 swf 文件中的 MovieClip 等。

JS 本来也具有相关的反射API,比如 Object.getOwnPropertyDescriptor()Function.prototype.apply()indelete等,但这些 API 分布在不同的命名空间甚至全局保留字中,并且执行失败时是以抛出异常的方式进行的。这些因素使得涉及到对象反射的代码难以书写和维护。

[2.4] ES6 中的 Reflect

和 Proxy 同时,在 ECMAScript 2015 (6th Edition, ECMA-262) 中,引入了 Reflect 对象,用来囊括对象反射的若干方法。

反射方法

相似操作

Reflect.apply()

Function.prototype.apply()

Reflect.construct()

new target(...args)

Reflect.defineProperty()

Object.defineProperty()

Reflect.deleteProperty()

delete target[name]

Reflect.enumerate()

供 for...in 操作遍历到的属性

Reflect.get()

类似于 target[name]

Reflect.getOwnPropertyDescriptor()

Object.getOwnPropertyDescriptor()

Reflect.getPrototypeOf()

Object.getPrototypeOf()

Reflect.has()

in 运算符

Reflect.isExtensible()

Object.isExtensible()

Reflect.ownKeys()

Object.getOwnPropertyNames(target).concat(Object.getOwnPropertySymbols(target))

Reflect.preventExtensions()

Object.preventExtensions()

Reflect.set()

target[name] = val

Reflect.setPrototypeOf()

Object.setPrototypeOf()

  • Reflect 与 ES5 的 Object 有点类似,包含了对象语言内部的方法,Reflect 也有和 Proxy 互相一一对应的若干种方法。
  • Proxy 相当于去修改设置对象的属性行为,而Reflect则是获取对象的这些行为(的原始版本)。两者经常搭配使用。
  • Reflect 没有构造函数,可被调用的都是其静态方法。
代码语言:javascript
复制
var target = {
   a: 1
};
var proxy = new Proxy(target, {
   get: function(tgt, key) {
       console.log("Get %s", key);
       return tgt[key] + 100;
   },
   set: function(tgt, key, val) {
       console.log("Set %s = %s", key, val);
       return tgt[key] = "VAL_" + val;
   }
});proxy.a = 2;
//Set a = 2console.log(proxy.a);
//Get a
//VAL_2100console.log(Reflect.get(target, "a"));
//VAL_2Reflect.set(target, "a", 3);
console.log(Reflect.get(target, "a"));
//3

可以看到,如果直接在 Proxy 中存取目标对象的值,很可能调用多余的 getter/setter;而搭配 Reflect 中对应的方法使用则可有效避免此情况

同时应注意到,在执行失败时,这些方法并不抛出错误,而是返回 false;这极大的简化了处理:

代码语言:javascript
复制
//In ES5
var o = {};
Object.defineProperty(o, 'a', {
 get: function() { return 1; },
 configurable: false
});
try {
   Object.defineProperty(o, 'a', { configurable: true });
} catch(e) {
   console.log("Exception");
}//In ES2015
var o = {};
Reflect.defineProperty(o, 'a', {
 get: function() { return 1; },
 configurable: false
});
if( !Reflect.defineProperty(o, 'a', { configurable: true }) ) {
   console.log("Operation Failed");
}

[2.5] 配合使用 Proxy/Reflect

? 例子1:为对象的每个属性设置 getter/setter

代码语言:javascript
复制
//in ES5
var obj = {
   x: 1,
   y: 2,
   z: 3
};function trace1() {
   var cache = {};
   Object.keys(obj).forEach(function(key) {
       cache[key] = obj[key]; //避免循环 setter
       Object.defineProperty(obj, key, {
           get: function() {
               console.log('Get ', key);
               return cache[key];
           },
           set: function(vlu) {
               console.log('Set ', key, vlu);
               cache[key] = vlu;
           }
       })
   });
}
trace1();obj.x = 5;
console.log(obj.z);
// Set  x 5
// Get  z
// 3
代码语言:javascript
复制
//in ES6
var obj2 = {
   x: 6,
   y: 7,
   z: 8
};function trace2() {
   return new Proxy(obj2, {
       get(target, key) {
           if (Reflect.has(target, key)) {
               console.log('Get ', key);
           }
           return Reflect.get(target, key);
       },
       set(target, key, vlu) {
           if (Reflect.has(target, key)) {
               console.log('Set ', key, vlu);
           }
           return Reflect.set(target, key, vlu);
       }
   });
}const proxy2 = trace2();
proxy2.x = 99;
console.log(proxy2.z);
// Set  x 99
// Get  z
// 8

? 例子2:跟踪方法调用

代码语言:javascript
复制
var obj = {
   x: 1,
   y: 2,
   say: function(word) {
       console.log("hello ", word)
   }
};var proxy = new Proxy(obj, {
   get(target, key) {
       const targetValue = Reflect.get(target, key);
       if (typeof targetValue === 'function') {
           return function (...args) {
               console.log('CALL', key, args);
               return targetValue.apply(this, args);
           }
       } else {
           console.log('Get ', key);
           return targetValue;
       }
   }
});proxy.x;
proxy.y;
proxy.say('excel!');
// Get  x
// Get  y
// CALL say [ 'excel!' ]
// hello  excel!

总结

  • getter/setter 也被称为存取方法,是访问方法中最常用的两个
  • 可以用访问方法封装保护原对象,并保留逻辑的灵活性
  • ES5 中开始支持了隐式的 get 和 set 访问方法,可以通过 delete 删除
  • 使用 使用 Object.defineProperty() 也可以设置 getter/setter 等
  • 历史上利用 Object.prototype.__define[G,S]etter__() 和 onpropertychange 实现存取方法的兼容
  • 可以利用代理和反射改善传统的访问控制
  • 代理对象居于目标对象的用户和目标对象本身的中间,并负责保护对目标对象的访问
  • ES6 原生的 Proxy 对象。用于定义基本操作的自定义行为(如属性查找,赋值,枚举,函数调用等)
  • 对象的反射是一种在运行时探查和操作对象属性的语言能力
  • ES6 引入了 Reflect 对象,用来囊括对象反射的若干方法
  • Reflect 有和 Proxy 一一对应的若干种方法,经常搭配使用

参考资料:

  • http://dealwithjs.io/es6-features-10-use-cases-for-proxy/
  • https://segmentfault.com/a/1190000008326517
  • http://2ality.com/2017/11/proxy-method-calls.html
  • https://www.zhihu.com/question/21401198
  • https://blogs.msdn.microsoft.com/ie/2010/09/07/transitioning-existing-code-to-the-es5-gettersetter-apis/
  • http://johndyer.name/native-browser-get-set-properties-in-javascript/
  • https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/
  • http://www.cnblogs.com/onlywujun/archive/2013/03/28/2985887.html
  • https://www.joezimjs.com/javascript/javascript-design-patterns-proxy/
  • https://stackoverflow.com/questions/7379732/what-is-a-javascript-proxy-pattern
  • http://www.importnew.com/9716.html
  • https://help.adobe.com/enUS/AS2LCR/Flash10.0/help.html?content=00000171.html
  • http://blog.csdn.net/chy555chy/article/details/51375664
  • http://www.runoob.com/csharp/csharp-property.html
  • http://php.net/manual/en/language.oop5.overloading.php
  • http://antimatter15.com/wp/2010/02/experiment-cross-browser-javascript-getters-and-setters/
  • https://www.52jbj.com/jbdq/512047.html
  • https://ponyfoo.com/articles/es6-reflection-in-depth
  • https://www.keithcirkel.co.uk/metaprogramming-in-es6-part-2-reflect/
  • http://2ality.com/2014/12/es6-proxies.html
  • http://qnimate.com/es6-reflect-api-tutorial/
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2017-11-23,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 云前端 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • I. JS对象的访问控制
    • [1.1] 熟悉的 getter/setter
      • [1.2] ES5 中的 getter 和 setter
        • [1.4] 用 Object.defineProperty() 精确定义对象成员
          • 相关方法:Object.getOwnPropertyDescriptor()
          • 相关方法:Object.defineProperties()
          • 相关方法:Object.create()
        • [1.5] __define[G,S]etter__()
          • [1.6] __lookup[G,S]etter__()
            • [1.7] 用 onpropertychange 兼容古早浏览器
            • II. JS中的代理和反射
              • [2.1] 传统的代理模式
                • [2.2] ES6 中的 Proxy
                  • [2.3] 反射
                    • [2.4] ES6 中的 Reflect
                      • [2.5] 配合使用 Proxy/Reflect
                        • 总结
                          • 参考资料:
                          领券
                          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档