什么是JavaScript中的接收器?

时间:2016-06-01 08:37:37

标签: javascript

我正在阅读You Don't Know JS: ES6 & Beyond。我发现了一些混淆的措辞,如

  

我们将一个get(..)处理程序声明为处理程序对象上的命名方法(代理(...)的第二个参数),它接收对目标对象(obj)的引用,即键属性名称(&# 34; a"),以及self / receiver / proxy(pobj)。

我的问题是接收器的意思是什么,它的名字来自哪里?

好像我有一个带有成员函数的对象跳转:

var a = { jump: function(){console.log('jump!')} };

如果我运行a.jump();,那么a就是接收者。

是这样的吗?如果我错了,请纠正我。 非常感谢!

对于阅读同一本书的人 ,当您来到Proxy First, Proxy Last部分时,您可以在代码中添加一行以更清晰关于获取陷阱中的上下文的图片。

var handlers = {
        get(target,key,context) {
            console.log(greeter === context); //true, this line added
            return function() {
                context.speak(key + "!");
            };
        }
    },
    catchall = new Proxy( {}, handlers ),
    greeter = {
        speak(who = "someone") {
            console.log( "hello", who );
        }
    };

// setup `greeter` to fall back to `catchall`
Object.setPrototypeOf( greeter, catchall );

greeter.speak();                // hello someone
greeter.speak( "world" );       // hello world

greeter.everyone();             // hello everyone!

正如您所看到的,由于作者,上下文的get陷阱的第三个参数的命名,接收器可以根据词法代码 - greeter.everyone();而变化。有关更好的理解,请参阅下面的Oriol非常详细的答案。谢谢你们!

2 个答案:

答案 0 :(得分:9)

接收器是发生属性查找的对象。

是的,如果你使用a.jumpa就是接收者。

只有在发生属性查找时才能执行任意代码时,该概念才有意义。基本上,这意味着:

  • 访问者属性。

    您可以使用getter或setter中的this来访问接收器。接收器通常是您定义属性的对象,或者是从其继承的另一个对象。

    var target = {
      get getReceiver() { return this; }
    };
    target.getReceiver; // target
    var inherits = Object.create(target);
    inherits.getReceiver; // inherits
    

    内置示例是__proto__,定义为Object.prototype的属性,但希望在其他对象(接收方)上获取或设置。

  • 代理对象

    代理对象允许您定义getset陷阱,当您尝试获取或设置代理的任何属性时,这些陷阱会运行一个函数。接收器作为该函数的参数提供。接收器通常是Proxy对象本身,或者是从它继承的对象。

    var proxy = new Proxy({}, {
      get: function(target, property, receiver) {
        return receiver;
      }
    });
    proxy.getReceiver; // proxy
    var inherits = Object.create(proxy);
    inherits.getReceiver; // inherits
    

注意,您可以使用Reflect.getReflect.set来指定任意接收器:

Reflect.get(target, "getReceiver", arbitraryValue); // arbitraryValue ¹
Reflect.get(proxy, "getReceiver", arbitraryValue); // arbitraryValue

¹如果在非严格模式下定义了getter,它将是Object(arbitraryValue)

名称“receiver”来自规范,请参阅Object Internal Methods and Internal Slots

  
      
  • [[Get]]( propertyKey Receiver )→任何

         

    从此对象返回其键为 propertyKey 的属性的值。如果必须执行任何ECMAScript代码来检索   属性值, Receiver 用作值时   评估代码。

  •   
  • [[Set]]( propertyKey value Receiver )→ Boolean

         

    将键为 propertyKey 的属性的值设置为value。如果必须执行任何ECMAScript代码来设置属性值,   在评估代码时, Receiver 用作 this 值。如果设置了属性值,则返回 true ;如果设置属性值,则返回 false   无法设定。

  •   

答案 1 :(得分:2)

我花了一些时间试图弄清楚与Reflect.get一起使用时,该“接收器”将被用作什么,并且可能毫无疑问,它们都和MDN explains一样:

receiver 可选
如果遇到吸气剂,则为目标调用提供this的值。与Proxy一起使用时,它可以是从target继承的对象。

据我估计,基本上Reflect.get中它起着决定性的作用是用于访问 getter 属性。例如,以下调用将返回2,而不返回undefined

const obj = { get foo() { return this.bar; } };
Reflect.get(obj, "foo", { bar: 2 });

使用get foo()...作为“接收者”来调用实际的getter({ bar: 2 })。如果没有Reflect.get的第三个参数,接收者自然就隐含为对象本身,并且由于它没有bar属性,因此返回undefined。如果它定义了bar属性,那么事情实际上会简单得多:

const obj = { bar: 1, get foo() { return this.bar } };
obj.foo; /// evaluates to 1
Reflect.get(obj, "foo"); /// evaluates to 1, equivalent to above
Reflect.get(obj, "foo", { bar: "soap" }) /// evaluates to, guess what, "soap"

我认为没有什么比这更多的了,反正没有Reflect.get