ホームページ  >  記事  >  ウェブフロントエンド  >  ES6 の新機能: JavaScript の Reflect オブジェクト コードの詳細な説明

ES6 の新機能: JavaScript の Reflect オブジェクト コードの詳細な説明

黄舟
黄舟オリジナル
2017-03-07 14:24:121660ブラウズ

Reflect の概要:

Reflect オブジェクトは私のノード (v4.4.3) には実装されておらず、Chrome の新しいバージョンでもサポートされていません。また、ff はプロキシとリフレクトをサポートしています。ノードが Reflect をサポートするようにするには、harmonie-reflect をインストールします。

Reflect を使用したい場合は、Reflect.method() を通じて直接呼び出すことができます。 Proxy のネイティブ Object メソッドのほとんどがすでに再実装されています。

Reflect を使用する理由

Reflect を使用する必要がある理由をいくつか示します。翻訳アドレス: Reflect、大まかに翻訳すると:

1: より便利な戻り値: Reflect には、ES5 の Object メソッドと同じメソッドがいくつかあります。例: Reflect.getOwnPropertyDescriptor および Reflect.defineProperty ただし、Object.defineProperty(obj, name, desc) は正常に実行された場合は obj を返し、他の理由で発生したエラーはオブジェクトを表すために 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 に定義があるか属性名を継承しているかを判断したい場合、ES5 では次のように判断できます: name in obj または属性を削除します: delete obj[name]。使いやすく、非常に短く、非常にシンプルな Clear ですが、使用する場合はクラスにカプセル化する必要があります

Reflect を使用すると、Reflect.has(obj, name) のようにカプセル化できます。 Reflect.deleteProperty(obj, name);

3: より信頼性の高い関数実行方法: ES では、関数 f を実行し、それにパラメーター引数のセットを渡す必要がある場合、これをバインドする必要があります。次のように:

f.apply(obj, args)

ただし、f の apply は user として再定義される可能性があります。私自身が適用したため、次のように記述する方が確実です:

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: アクセサーまたはリーダーの制御: ES5 では、要素のプロパティを読み取るか、プロパティを設定したい場合は、これを行う必要があります:

var name = ... // get property name as a string
obj[name] // generic property lookup
obj[name] = value // generic property update

The Reflect.getと Reflect.set メソッドを使用すると同じことを行うことができ、追加のパラメーター レシーバーを使用すると、オブジェクトのセッターの上位コンテキストと下位コンテキストを設定し、これをゲッターできるようになります:

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)

アクセサーは独自のメソッドを使用したくない、しかしこれをラッパーにリダイレクトしたい:

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) も提供します。これは、オブジェクトのプロトタイプにアクセスして設定する新しいメソッドです: apply

Reflect.apply の使用は、実際には ES5 の Function.prototype.apply() の代用です。 Reflect.apply を実行します

最初のパラメータは次のとおりです: 実行する必要がある関数です。

2 番目のパラメータは次のとおりです: 関数を実行するために使用する必要があるコンテキストです。

3 番目のパラメータは次のとおりです: 配列または擬似です。 -array、関数を実行するためのパラメータとして使用されます。

<script>
let fn = function() {
    this.attr = [0,1,2,3];
};
let obj = {};
Reflect.apply(fn, obj, [])
console.log(obj);  
</script>


Reflect.apply のデモ:

<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 はプロキシと併用できます。 共同使用:

{
    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の最初のパラメータがコンストラクタです。 、2 番目のパラメーターはパラメーターで構成される配列または疑似配列です。基本的な使用方法は次のとおりです。

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 は、少なくともこれまでのところ、新しいコンストラクターと同じです...

Reflect を与えることができます。 .construct は 3 番目のパラメーターを渡し、3 番目のパラメーターはスーパー クラスです

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



声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。