Всесторонне разобраться с управлением доступом и прокси-отражением JS-объектов

внешний интерфейс JavaScript API дизайн
Всесторонне разобраться с управлением доступом и прокси-отражением JS-объектов

В Javascript почти все операции, такие как чтение, присваивание, вызов методов и т. д., выполняются вокруг «объектов», и долгое время вопрос о том, как лучше понимать и контролировать эти операции, стал важным вопросом при разработке языка.

I. Контроль доступа к объектам JS

[1.1] Знакомые геттеры/сеттеры

Так называемый геттер/сеттер обычно определяется как:

  • Метод получения не принимает аргументов и всегда возвращает значение.
  • Сеттер всегда принимает параметр и не возвращает значение

Некоторый здравый смысл геттера/сеттера:

  • Два наиболее часто используемых метода доступа, также известные как методы доступа.
  • Используется для инкапсуляции закрытых методов-членов, чтобы изолировать прямой доступ к ним из внешнего мира.
  • Вы также можете добавить другую логику в процесс доступа, чтобы обеспечить простоту внешних вызовов.
  • Достигается гибкость во внутренней логике объекта или класса, сохраняя возможность изменения
  • Может автоматически генерироваться во многих IDE

Сначала посмотрите на общую реализацию на других языках:

Один из них — традиционный явныйgetXXX()/setXXX(v)вызов метода

//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

    }
}

Несомненно, явное именование вызовов произвольно и может быть реализовано на разных языках.

Другой - неявный геттер/сеттер

//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"
//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)
//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

Начиная со спецификации ECMAScript 5.1 (ECMA-262) в 2011 году, JavaScript также начал поддерживать геттеры/сеттеры; по форме он, естественно, такой же, как AS2/AS3, который также реализован для ECMAScript.

Синтаксис геттера:

// prop 指的是要绑定到给定函数的属性名
{get prop() { ... } }

// 还可以使用一个计算属性名的 expression 绑定到给定的函数, 注意浏览器兼容性
{get [expression]() { ... } }

🌰 Пример:

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 следует учитывать следующие проблемы:

  • Вы можете использовать числовые или строковые идентификаторы
  • не должен иметь параметров
  • не может отображаться в литерале объекта с другим получением или записью данных с теми же свойствами

Удалите геттер с помощью оператора удаления:

delete obj.latest;

Ниже показано расширенное использование, то есть значение получается только при первом вызове (ленивый геттер), и геттер преобразуется в обычное свойство данных:

get notifier() {
  delete this.notifier;
  return this.notifier = document.getElementById('myId');
},

Синтаксис сеттера:

//prop 指的是要绑定到给定函数的属性名
//val 指的是分配给prop的值
{set prop(val) { . . . }}

// 还可以使用一个计算属性名的 expression 绑定到给定的函数, 注意浏览器兼容性
{set [expression](val) { . . . }}

При использовании синтаксиса set следует учитывать следующие проблемы:

  • Идентификаторы могут быть числами или строками
  • должен иметь явный параметр
  • Вы не можете использовать набор для переменной, которая уже имеет реальное значение, и вы не можете установить несколько наборов для свойства в одном и том же объекте.

🌰 Пример:

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"

Сеттеры можно удалить с помощью операции удаления:

delete o.current;

[1.4] Точное определение членов объекта с помощью Object.defineProperty()

Вспоминая то, что упоминалось ранее, существуют две основные формы дескрипторов свойств, которые существуют в объектах: свойства данных и методы доступа. Дескрипторы должны быть в одной из двух форм, а не оба.

И вообще, свойства, добавляемые к объектам присваиванием, могут быть пройдены и перечислены методами for...in или Object.keys, а значения добавленных таким образом свойств могут быть изменены или удалены.

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

Для свойства данных или метода доступа, определенного таким образом, нет контроля над тем, можно ли его удалить, и нельзя ли ограничить его перечисление.

И использование Object.defineProperty() позволяет изменить эти настройки по умолчанию.

Также, начиная со спецификации ECMAScript 5.1, определен метод Object.defineProperty(). Используется для определения нового свойства непосредственно в объекте или изменения существующего свойства объекта и возврата объекта.

Его синтаксис:

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

вdescriptorСвойства, которые можно установить:

Атрибуты описывать применительно к
configurable Можно изменить и удалить Атрибуты данных, методы доступа
enumerable можно перечислить Атрибуты данных, методы доступа
value значение атрибута атрибут данных
writable Может быть изменен оператором присваивания атрибут данных
get геттерные методы метод доступа
set метод установки метод доступа

Важно понимать, что этот метод имеет ограниченную поддержку, начиная с IE8 (недоступно для объектов, отличных от DOM).

🌰 Пример:

var o = {};

o.a = 1;
// 等同于 :
Object.defineProperty(o, "a", {
  value : 1,
  writable : true,
  configurable : true,
  enumerable : true
});
var o = {};

var bValue;
Object.defineProperty(o, "b", {
  get : function(){ //添加存取方法
    return bValue;
  },
  set : function(newValue){
    bValue = newValue;
  },
  enumerable : true,
  configurable : true
});
var o = {};

Object.defineProperty(o, "a", {
    value : 37,
    writable : false //定义了一个“只读”的属性
});

console.log(o.a); // 37
o.a = 25; // 在严格模式下会抛出错误,非严格模式只是不起作用
console.log(o.a); // 37
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
Object.defineProperty(o, "conflict", {
  value: 0x9f91102, 
  get: function() { 
    return 0xdeadbeef; 
  } 
}); //抛出 TypeError,数据属性和存取方法不能混合设置

Связанный метод: Object.getOwnPropertyDescriptor()

Возвращает предыдущий из указанного объектасобственностьСоответствующий дескриптор свойства. (Собственные свойства относятся к свойствам, непосредственно назначенным объекту, а не к свойствам, которые ищутся в цепочке прототипов)

грамматика:

//其中 prop 对应于 Object.defineProperty() 中第三个参数 descriptor
Object.getOwnPropertyDescriptor(obj, prop)

🌰 Пример:

var o = {
    get foo() {
        return 17;
    }
};

Object.getOwnPropertyDescriptor(o, "foo");
// {
//   configurable: true,
//   enumerable: true,
//   get: /*the getter function*/,
//   set: undefined
// }

Связанные методы: Object.defineProperties()

определить непосредственно на объектенесколькоНовые свойства или изменение существующих свойств

грамматика:

//prop 和 descriptor 的定义对应于 Object.defineProperty()
Object.defineProperties(obj, {
    prop1: descriptor1,
    prop2: descriptor2,
    ...
})

🌰 Пример:

var obj = {};
Object.defineProperties(obj, {
  'property1': {
    value: true,
    writable: true
  },
  'property2': {
    value: 'Hello',
    writable: false
  }
});

Связанные методы: Object.create()

Создайте новый объект, используя указанный объект-прототип и его свойства.

грамматика:

//proto 为新创建对象的原型对象
//props 对应于 Object.defineProperties() 中的第二个参数
Object.create(proto[, props])

🌰 Пример:

// 创建一个原型为null的空对象
var o = Object.create(null);

var o2 = {};
// 以字面量方式创建的空对象就相当于:
var o2 = Object.create(Object.prototype);
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 и т. д.

🌰 Просто посмотрите на пример:

var o = {
    word: null
};

o.__defineGetter__('gimmeFive', function() { 
    return 5;
});
console.log(o.gimmeFive); // 5

o.__defineSetter__('say', function(vlu) { 
    this.word = vlu;
});
o.say = "hello";
console.log(o.word); //"hello"

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

Так же естьlookupGetter() а такжеlookupSetter() дванестандартныйа такжеУстаревшийМетоды

  • lookupGetter() возвращает функцию получения для свойства объекта

🌰 Пример:

var obj = {
    get foo() {
        return Math.random() > 0.5 ? "foo" : "bar";
    }
};

obj.__lookupGetter__("foo") 
// (function (){return Math.random() > 0.5 ? "foo" : "bar"})

Если заменить стандартным методом, то это:

Object.getOwnPropertyDescriptor(obj, "foo").get
// (function (){return Math.random() > 0.5 ? "foo" : "bar"})

И если это свойство доступа унаследовано:

Object.getOwnPropertyDescriptor(Object.getPrototypeOf(obj), "foo").get 
// function __proto__() {[native code]}
  • lookupSetter() Функция установки, которая возвращает свойство объекта

🌰 Пример:

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, используйте поддерживаемый IEonpropertychangeСобытия также могут имитировать геттеры/сеттеры.

Обратите внимание, что этот метод ограничен объектами DOM, которые были загружены в документ.

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);
}

2. Прокси и отражение в JS

На самом объекте определение контроля доступа к атрибутам один за другим иногда приводит к раздуванию кода и даже сложности в обслуживании; понимание концепции и использования прокси и отражения может эффективно улучшить эти ситуации.

[2.1] Традиционный режим прокси

В классическом шаблоне проектирования (Design Pattern) широко используется шаблон прокси (Proxy Pattern), он определяется как:

В прокси-режиме прокси-объект (Proxy) действует как интерфейс к другому целевому объекту (Real Subject). Прокси-объект находится между пользователем (Клиентом) целевого объекта и самим целевым объектом и отвечает за защиту доступа к целевому объекту.

Типичные сценарии применения:

  • Контроль доступа и кэширование целевых объектов
  • Задержка инициализации целевого объекта
  • получить доступ к удаленному объекту

🌰 Например:

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

console.log(proxy.findBook(1)); //{ id: 1, name: 'head first design pattern' }
console.log(proxy.findBook(3)); //{ id: 3, name: 'lua programming' }

Очевидно, что приведенный выше пример кода показывает использование прокси для достиженияленивая инициализацияа такжеКонтроль доступа.

Стоит упомянуть, что другой вид шаблона прокси и шаблона проектированияШаблон декоратораИх легко спутать.Разница между ними в том, что они являются упаковкой исходного целевого объекта; разница в том, что первый фокусируется наПредоставляет тот же API, что и исходный объект, с защищенным управлением доступом к нему., в то время как последний фокусируется на добавлении новых функций в исходный API.

[2.2] Прокси в ES6

В стандарте ECMAScript 2015 (6-е издание, ECMA-262) предлагается собственный прокси-объект. Пользовательское поведение для определения основных операций (таких как поиск свойств, присвоение, перечисление, вызовы функций и т. д.)

грамматика:

let p = new Proxy(target, handler);

целевой объект прокси-объектаtarget, который может быть объектом любого типа, например, объектом, массивом, функцией или даже другим прокси-объектом;let proxy=new Proxy(target,handle)После операции прокси и целевые объекты будут влиять друг на друга. который:

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Он также является объектом, и его несколько заданных свойств определяются одно за другим функцией, которая представляет собой операцию, выполняемую при выполнении соответствующего доступа к целевому объекту; наиболее распространенной операцией является определение свойств get и set геттера/ сеттер:

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, сеттер в прокси должен иметь возвращаемое значение;

И это должно быть легко понять, не только имя такое же, но объект Proxy действительно соответствует классическому режиму прокси - объект прокси инкапсулирует и защищает API целевого объекта, скрывает целевой объект и контролирует его доступ поведение.

В дополнение к определению геттеров/сеттеров более полными свойствами обработчика являются следующие:

  • "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] Отражение

Отражение объектов — это возможность языка исследовать свойства объектов и манипулировать ими во время выполнения.

В таких языках, как JAVA/AS3, отражение обычно используется для получения имени класса и списка атрибутов объекта во время выполнения, а затем его динамического построения; например, динамическое создание объекта с помощью значения в файле конфигурации XML, или извлеките swf по названию MovieClip и т.п. в файле.

JS также имеет связанные API-интерфейсы отражения, такие какObject.getOwnPropertyDescriptor(),Function.prototype.apply(),in,deleteи т. д., но эти API-интерфейсы распределены по разным пространствам имен или даже глобально зарезервированным словам и не могут этого сделать, вызывая исключения. Эти факторы затрудняют написание и сопровождение кода, включающего отражение объектов.

[2.4] Отражение в ES6

В то же время, что и прокси, в ECMAScript 2015 (6-е издание, 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() Похоже на цель [имя]
Reflect.getOwnPropertyDescriptor() Object.getOwnPropertyDescriptor()
Reflect.getPrototypeOf() Object.getPrototypeOf()
Reflect.has() в операторе
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 нет конструкторов, можно вызывать все его статические методы.
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 = 2

console.log(proxy.a);
//Get a
//VAL_2100

console.log(Reflect.get(target, "a"));
//VAL_2

Reflect.set(target, "a", 3);
console.log(Reflect.get(target, "a"));
//3

Видно, что если вы напрямую обращаетесь к значению целевого объекта в Proxy, он, скорее всего, вызовет избыточные геттеры/сеттеры; и использование соответствующих методов в Reflect может эффективно избежать этой ситуации.

Также следует отметить, что эти методы не выдают ошибку при неудаче, а возвращают false, это значительно упрощает обработку:

//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] Работа с прокси/рефлексом

🌰 Пример 1: Установить геттер/сеттер для каждого свойства объекта

//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
//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. Отслеживание вызовов методов

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!

Суммировать

  • Геттеры/сеттеры также известны как методы доступа и являются двумя наиболее часто используемыми методами доступа.
  • Исходный объект может быть защищен инкапсуляцией с помощью методов доступа, а гибкость логики может быть сохранена.
  • ES5 поддерживает неявные методы доступа get и set, которые можно удалить, удалив
  • Использование Object.defineProperty() также может устанавливать геттеры/сеттеры и т.д.
  • Исторически используется Object.prototype.define[G,S]etter() совместим с onpropertychange для достижения методов доступа
  • Традиционный контроль доступа можно улучшить с помощью прокси и отражений.
  • Прокси-объект находится между пользователем целевого объекта и самим целевым объектом и отвечает за безопасность доступа к целевому объекту.
  • Собственный прокси-объект ES6. Пользовательское поведение для определения основных операций (таких как поиск свойств, присвоение, перечисление, вызовы функций и т. д.)
  • Отражение объектов — это возможность языка исследовать свойства объектов и манипулировать ими во время выполнения.
  • ES6 представляет объект Reflect, который используется для включения нескольких методов отражения объекта.
  • Reflect имеет несколько методов, соответствующих Proxy один к одному, которые часто используются вместе.

Использованная литература:


(end)


Нажмите и удерживайте QR-код или найдите немного жизни, чтобы подписаться на нас