在Array.filter中使用Set.has - 不兼容的接收器

时间:2018-05-26 14:58:47

标签: javascript this

假设我有一个Set作为查找表。

const myset = new Set(["key1", "key2", "key3", "keepMe"]);

我想过滤mykeys中其他一些键(比如myset)的另一个数组。

const mykeys = ["ignoreMe", "keepMe", "ignoreMeToo", "key2"];

问题:

为什么我必须使用

const filtered = mykeys.filter(k => myset.has(k))

而不是

const filtered = mykeys.filter(myset.has)
// TypeError: Method Set.prototype.has called on incompatible receiver undefined

即,为什么我要在过滤器中创建匿名lambda函数? keys.has具有相同的签名(argument - element,return boolean)。一位朋友告诉我这与this有关。

mykeys.map(console.log)无误地工作(尽管没有多大用处)。

我遇到了这个article at MDN,我仍然不明白为什么“'myset'没有被捕获为”。我理解变通方法而不是“为什么”。任何人都可以用人性化的方式解释一些细节和参考文献吗?

更新:谢谢大家的回复。也许我不清楚我在问什么。我确实理解变通办法。

@charlietfl明白了。这是his comment,我正在寻找的东西:

  

因为filter()没有隐式this,因为set.has需要具有正确的this上下文。在匿名函数内调用它并手动添加参数会使调用自包含。

2 个答案:

答案 0 :(得分:1)

这是一个基本的设计决策,可以追溯到JavaScript语言的第一个定义。

考虑一个对象

#include <stdlib.h>

int read_int(void) {
    int c;
    int sign = 1;
    int f = 0;

    /* skip leading white space */
    while ((c = fgetc(stdin)) == ' ' || c == '\n')
        continue;

    /* handle optional sign */
    if (c == '-') {
        sign = -1;
        c = fgetc(stdin);
    } else
    if (c == '+') {
        c = fgetc(stdin);
    }

    /* convert digits */
    if (c >= '0' && c <= '9') {
        f = c - '0';
        while ((c = fgetc(stdin)) >= '0' && c <= '9')
            f = f * 10 + c - '0';
        if (c != EOF)
            ungetc(c, stdin);
    } else {
        /* no digits: fatal error */
        if (c == EOF)
            printf("Unexpected end of file\n");
        else
            printf("Sorry that input is invalid: %c\n", c);
        exit(1);
    }
    /* apply sign and return value */
    return sign * f;
}

double read_double(void) {
    char buf[80];
    int c;
    size_t pos = 0;
    double d;
    char *p;

    /* read a line of input */
    while (pos < sizeof(buf) - 1 && (c = fgetc(stdin)) != EOF && c != '\n')
        buf[pos++] = c;
    buf[pos] = '\0';

    /* use standard library function to convert the number */
    p = buf;
    d = strtod(buf, &p);

    /* if conversion failed, report fatal error */
    if (p == buf) {
        printf("Sorry this input is invalid: %s\n", buf);
        exit(1);
    }
    return d;
}

现在,当你写

var myObjet = {
  someValue: 0,
  someFunction: function() {
    return this.someValue;
  }
};

你完全得到了你所添加的内容,就像你写过

一样
var myValue = myObject.someValue;

同样,当你写

var myValue = 0;

你完全得到了你所添加的内容,就像你写过

一样
var myFunction = myObject.someValue;

...除了现在,你不再是一个物体了。所以var myFunction = (function() { return this.someValue; }); 并不意味着什么。的确,如果你试试

this

你会看到

console.log(myFunction());

就像你写的那样

undefined

在任何物体之外。

那么,console.log(this.someValue); 是什么?好吧,JavaScript决定如下:

  • 如果您撰写this,那么在执行myObject.myFunction()部分时,myFunction()this
  • 如果你只是写myObject,那么myFunction()是当前的全局对象,通常为this(并非总是如此,有许多特殊情况)。
  • 许多功能可以在另一个功能中注入window(例如thiscallapply,...)

现在,为什么要这样做?答案是这对原型来说是必要的。的确,如果你现在定义

map

您现在拥有一个基于var myDerivedObject = Object.create(myObject); myDerivedObjet.someValue = 42; 的对象,但具有不同的属性 myObject

someValue

这是因为console.log(myObject.someFunction()); // Shows 0 console.log(myDerivedObject.someFunction()); // Shows 42 myObject.someFunction()使用myObject,而this使用myDerivedObject.someFunction() myDerivedObject

如果在this的定义过程中捕获了this,我们就会在这两行中获得someFunction,但这也会使原型变得不那么有用。

答案 1 :(得分:1)

您可以使用thisArg has的{​​{1}}集和thisArg原型作为回调。

此模式不需要将Array#filter的实例绑定到原型,因为

  

如果向filter提供this参数,则会将其用作回调的undefined值。否则,值this将用作此值。 callback最终可观察到的const myset = new Set(["key1", "key2", "key3", "keepMe"]), mykeys = ["ignoreMe", "keepMe", "ignoreMeToo", "key2"], filtered = mykeys.filter(Set.prototype.has, myset); console.log(filtered);值根据Set确定。

&#13;
&#13;
$(':contains(text)')
&#13;
&#13;
&#13;