JavaScript 中反射的概念是什么?

Vas*_*nyk 12 javascript ecmascript-6

任何人都可以用人类语言和简单的示例解释它(反射和内置 Reflect 对象)如何在 JS 中工作。

维基百科:“在计算机科学中,反射是计算机程序在运行时检查、内省和修改其自身结构和行为的能力”。

Shr*_*dha 17

什么是反射?

\n\n
    \n
  • 对象可以查看自身,列出并更改其属性和方法。
  • \n
  • 因此 JavaScript 对象能够查看自己的属性和方法。
  • \n
  • 反射意味着检查程序及其数据的结构。
  • \n
  • 程序的语言是编程语言PL,进行检查的语言是元编程语言MPL。PL和MPL可以是同一种语言。
  • \n
  • Javascript 允许我们通过不同的方式检查它自己的程序。
  • \n
\n\n

1. 迭代对象的成员

\n\n
    \n
  • 例子:
  • \n
\n\n
var person = {\n    fname: "Default",\n    lname: "Default",\n    getFullName: function(){\n        return this.fname + " " + this.lname;\n    }\n}\n\nvar john = {\n    fname: "John",\n    lname: "Doe"\n}\n\njohn.__proto__ = person;\n\n//Reflection : Iterate over the members of an object\nfor(var prop in john){\n    console.log(prop + " : " + john[prop]);\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

输出:\n在此输入图像描述

\n\n

注意:检查对象的属性时,JavaScript\xe2\x80\x99s 默认包含继承的属性。

\n\n
    \n
  • 为了迭代对象的所有直接成员、自有成员或非继承成员,我们可以使用 hasOwnProperty()。
  • \n
  • hasOwnProperty ()方法返回一个布尔值,指示对象是否将指定属性作为其自己的属性(而不是继承它)。
  • \n
  • 句法 :
  • \n
\n\n
obj.hasOwnProperty(prop)\n
Run Code Online (Sandbox Code Playgroud)\n\n
    \n
  • 例子 :
  • \n
\n\n
var person = {\n    fname: "Default",\n    lname: "Default",\n    getFullName: function(){\n        return this.fname + " " + this.lname;\n    }\n}\n\nvar john = {\n    fname: "John",\n    lname: "Doe"\n}\n\njohn.__proto__ = person;\n\n//Reflection : Iterate over the direct or own members of an object\nfor(var prop in john){\n    if(john.hasOwnProperty(prop)){\n           console.log(prop + " : " + john[prop]);\n       }\n}\n\n
Run Code Online (Sandbox Code Playgroud)\n\n

输出:\n在此输入图像描述

\n\n
    \n
  • Object.getOwnPropertyNames()方法返回直接在给定对象中找到的所有属性(包括不可枚举属性,使用 Symbol 的属性除外)的数组。
  • \n
\n\n
var person = {\n    fname: "Default",\n    lname: "Default",\n    getFullName: function(){\n        return this.fname + " " + this.lname;\n    }\n}\n\nvar john = {\n    fname: "John",\n    lname: "Doe"\n}\n\njohn.__proto__ = person;\n\n//Reflection : Iterate over the direct or own members of an object using Object.getOwnPropertyNames()\nconsole.log(Object.getOwnPropertyNames(john));//["fname", "lname"]\n
Run Code Online (Sandbox Code Playgroud)\n\n
    \n
  • Object.getOwnPropertyDescriptor()方法返回给定对象的自有属性(即直接存在于对象上而不是在对象原型链中的属性描述符)的属性描述符。
  • \n
\n\n
//Reflection : Getting the property descriptor for an own property of object\nconsole.log(Object.getOwnPropertyDescriptor(person, \'getFullName\'));//{writable: true, enumerable: true, configurable: true, value: \xc6\x92}\n
Run Code Online (Sandbox Code Playgroud)\n\n
    \n
  • 这里:

    \n\n
      \n
    1. value :与属性关联的值(仅限数据描述符)。
    2. \n
    3. writable :当且仅当与属性关联的值可以更改时才为 true(仅限数据描述符)。
    4. \n
    5. configurable : true 当且仅当该属性描述符的类型可以更改并且该属性可以从相应的对象中删除时。
    6. \n
    7. enumerable :当且仅当该属性在相应对象的属性枚举期间出现时才为 true。
    8. \n
  • \n
  • 静态方法Object.defineProperty()直接在对象上定义新属性,或修改对象上的现有属性,然后返回该对象。

  • \n
  • 句法 :
  • \n
\n\n
Object.defineProperty(obj, prop, descriptor)\n
Run Code Online (Sandbox Code Playgroud)\n\n
    \n
  • 默认情况下,使用 Object.defineProperty() 添加的值是不可变的。
  • \n
\n\n

2. 检查对象的所有属性\n- 如果我们想要区分对象的属性和方法,我们可以使用运算符 typeof,它返回一个标识所分析元素类型的字符串。

\n\n
//Reflection : To examine all the properties of an object\nfor(var prop in person){\n    if(typeof person[prop] != \'function\'){\n        console.log(prop + " : " + john[prop]);\n       }\n}\n//OUTPUT:\n//fname : John\n//lname : Doe\n
Run Code Online (Sandbox Code Playgroud)\n\n

3. 检查对象的所有方法

\n\n
//Reflection : To examine all methods of an object\nfor(var prop in person){\n    if(typeof person[prop] == \'function\'){\n        console.log(prop + " : " + john[prop]);\n       }\n}\n//OUTPUT:\n//getFullName : function(){\n//        return this.fname + " " + this.lname;\n//    }\n
Run Code Online (Sandbox Code Playgroud)\n\n

JavaScript 在 ES5 中已经具有反射特性,尽管规范或社区都没有将它们命名为反射。Array.isArray、Object.getOwnPropertyDescriptor 和 Objects.keys 等方法的行为与反射所展示的功能非常相似。ES6 中内置的 Reflect 现在包含此类中的方法。

\n


小智 13

反射是元编程的一部分。

元编程是一种编程技术,其中计算机程序能够将程序视为其数据。这意味着一个程序可以被设计为读取、生成、分析或转换其他程序,甚至在运行时修改自身。

所以反射的概念是,就像我们在镜子中看到自己的倒影一样:我们可以看到没有它就看不到的东西,例如:我们的头发、我们的嘴唇、舌头等。

简而言之,如果一个方法或一个类调用这个反射东西,它可以看到其知识之外的对象,例如:实例变量、该类具有的方法列表以及其他属性,哪个类调用了该方法。

当我们进行元编程时,这很有用。作为方法或类应该意识到他们(甚至作者)知识之外的事情。

具体示例:假设水和杯子。如果你想对水物理进行编程以适应杯子,有很多方法。假设您与其他 100 名开发人员一起工作,并且不知道他们会设计出什么样的容器(有人最终可能会设计出一个湖泊甚至河流),并且您选择了元编程风格。你有班级水和班级杯子。您的水类别必须了解杯子的属性,例如:最大体积、重量、曲线,甚至最大/最小温度。

结果:每当有人调用类水时,您都不必将这些信息作为参数插入,因为可能很难跟踪它们的数量是否在增长。

(我不确定这是否是一个足够好的示例和解释,所以如果您突然想到,请评论一个更好的示例和解释)