GVKun编程网logo

javascript – 方法Set.prototype.add调用不兼容的接收器undefined(js无法调用)

1

在本文中,我们将为您详细介绍javascript–方法Set.prototype.add调用不兼容的接收器undefined的相关知识,并且为您解答关于js无法调用的疑问,此外,我们还会提供一些关于A

在本文中,我们将为您详细介绍javascript – 方法Set.prototype.add调用不兼容的接收器undefined的相关知识,并且为您解答关于js无法调用的疑问,此外,我们还会提供一些关于Array.prototype.find()、Array.prototype.findIndex()、Array.prototype.keys()、Array.prototype.values()和Array.prototype.entries()、Array.prototype.push.apply(a,b)和Array.prototype.slice.call(arguments)、Array.prototype.toString()和Array.prototype.toLocaleString()的有用信息。

本文目录一览:

javascript – 方法Set.prototype.add调用不兼容的接收器undefined(js无法调用)

javascript – 方法Set.prototype.add调用不兼容的接收器undefined(js无法调用)

我简直无法理解为什么会出现这个错误.

这是我在chrome控制台上测试的内容:

>    var mySet;
<-   undefined

>    mySet = new Set;
<-   Set {}

>    mySet.add('foo','bar','baz')       // Worked as expected
<-   Set {"foo"}                          // just the first argument was added

>    ['bar','baz'].forEach(mySet.add)
X->  VM1529:1 Uncaught TypeError: 
         Method Set.prototype.add called on incompatible receiver undefined(…)

提前致谢.

解决方法

在这种情况下,当您将其作为回调传递时,add方法会丢失其内部此上下文,因此您需要使用bind:
['bar','baz'].forEach(mySet.add.bind(mySet))

Array.prototype.find()、Array.prototype.findIndex()

Array.prototype.find()、Array.prototype.findIndex()

Array.prototype.find()
find () 方法返回数组中满足提供的测试函数的第一个元素的值。否则返回 undefined。
此方法是 ES6 方法。
此方法不会改变数组。
arr.find(callback[, thisArg])
callback
在数组每一项上执行的函数,接收 3 个参数:
  element
  当前遍历到的元素。
  index
  当前遍历到的索引。
  array
  数组本身。
thisArg 可选
可选,指定 callback 的 this 参数。
 
当某个元素通过 callback 的测试时,返回数组中的一个值,否则返回 undefined。
 
find 方法对数组中的每一项元素执行一次 callback 函数,直至有一个 callback 返回 true。当找到了这样一个元素后,该方法会立即返回这个元素的值,否则返回 undefined。 注意 callback 函数会为数组中的每个索引调用即从 0 到 length - 1,而不仅仅是那些被赋值的索引,这意味着对于稀疏数组来说,该方法的效率要低于那些只遍历有值的索引的方法。
在第一次调用 callback 函数时会确定元素的索引范围,因此在 find 方法开始执行之后添加到数组的新元素将不会被 callback 函数访问到。如果数组中一个尚未被 callback 函数访问到的元素的值被 callback 函数所改变,那么当 callback 函数访问到它时,它的值是将是根据它在数组中的索引所访问到的当前值。被删除的元素仍旧会被访问到。
var inventory = [
    {name: ''apples'', quantity: 2},
    {name: ''bananas'', quantity: 0},
    {name: ''cherries'', quantity: 5}
];

function findCherries(fruit) { 
    return fruit.name === ''cherries'';
}

console.log(inventory.find(findCherries)); // { name: ''cherries'', quantity: 5 }
寻找数组中的质数
function isPrime(element, index, array) {
  var start = 2;
  while (start <= Math.sqrt(element)) {
    if (element % start++ < 1) {
      return false;
    }
  }
  return element > 1;
}

console.log([4, 6, 8, 12].find(isPrime)); // undefined, not found
console.log([4, 5, 8, 12].find(isPrime)); // 5
当在回调中删除数组中的一个值时,当访问到这个位置时,其传入的值时 undefined:
// Declare array with no element at index 2, 3 and 4
var a = [0,1,,,,5,6];

// Shows all indexes, not just those that have been assigned values
a.find(function(value, index) {
  console.log(''Visited index '' + index + '' with value '' + value); 
});

// Shows all indexes, including deleted
a.find(function(value, index) {

  // Delete element 5 on first iteration
  if (index == 0) {
    console.log(''Deleting a[5] with value '' + a[5]);
    delete a[5];  // 注:这里只是将a[5]设置为undefined,可以试试用a.pop()删除最后一项,依然会遍历到被删的那一项
  }
  // Element 5 is still visited even though deleted
  console.log(''Visited index '' + index + '' with value '' + value); 
});

polyfill

 

// https://tc39.github.io/ecma262/#sec-array.prototype.find
if (!Array.prototype.find) {
    Object.defineProperty(Array.prototype, ''find'', {
      value: function(predicate) {//遍历的处理函数
       // 1. Let O be ? ToObject(this value).
        if (this == null) {//数组为null
          throw new TypeError(''"this" is null or not defined'');
        }
  
        var o = Object(this);//数组
  
        // 2. Let len be ? ToLength(? Get(O, "length")).
        var len = o.length >>> 0;//数组长度
  
        // 3. If IsCallable(predicate) is false, throw a TypeError exception.
        if (typeof predicate !== ''function'') {//第一个参数必须是函数
          throw new TypeError(''predicate must be a function'');
        }
  
        // 4. If thisArg was supplied, let T be thisArg; else let T be undefined.
        var thisArg = arguments[1];//第二个参数指定this
  
        // 5. Let k be 0.
        var k = 0;//遍历索引
  
        // 6. Repeat, while k < len
        while (k < len) {
          // a. Let Pk be ! ToString(k).
          // b. Let kValue be ? Get(O, Pk).
          // c. Let testResult be ToBoolean(? Call(predicate, T, « kValue, k, O »)).
          // d. If testResult is true, return kValue.
          var kValue = o[k];
          if (predicate.call(thisArg, kValue, k, o)) {//如果当前值经过处理函数后返回了true,就返回当前值
            return kValue;
          }
          // e. Increase k by 1.
          k++;
        }
  
        // 7. Return undefined.
        return undefined;//未找到就返回undefined
      }
    });
  }

Array.prototype.findIndex()

findIndex () 方法返回数组中满足提供的测试函数的第一个元素的索引。否则返回 - 1。

此方法是 ES6 方法。

此方法不改变原数组。

polyfill

// https://tc39.github.io/ecma262/#sec-array.prototype.findIndex
if (!Array.prototype.findIndex) {
    Object.defineProperty(Array.prototype, ''findIndex'', {
      value: function(predicate) {//第一个参数处理函数
       // 1. Let O be ? ToObject(this value).
        if (this == null) {//数组为null抛错误
          throw new TypeError(''"this" is null or not defined'');
        }
  
        var o = Object(this);//数组
  
        // 2. Let len be ? ToLength(? Get(O, "length")).
        var len = o.length >>> 0;//数组长度
  
        // 3. If IsCallable(predicate) is false, throw a TypeError exception.
        if (typeof predicate !== ''function'') {//第一个参数不是函数抛错误
          throw new TypeError(''predicate must be a function'');
        }
  
        // 4. If thisArg was supplied, let T be thisArg; else let T be undefined.
        var thisArg = arguments[1];//第二个参数是指定this值
  
        // 5. Let k be 0.
        var k = 0;//遍历索引
  
        // 6. Repeat, while k < len
        while (k < len) {
          // a. Let Pk be ! ToString(k).
          // b. Let kValue be ? Get(O, Pk).
          // c. Let testResult be ToBoolean(? Call(predicate, T, « kValue, k, O »)).
          // d. If testResult is true, return k.
          var kValue = o[k];
          if (predicate.call(thisArg, kValue, k, o)) {//如果当前值符合要求就返回当前值的索引
            return k;
          }
          // e. Increase k by 1.
          k++;
        }
  
        // 7. Return -1.
        return -1;//找不到符合要求的值就返回-1
      }
    });
  }

 

 

Array.prototype.keys()、Array.prototype.values()和Array.prototype.entries()

Array.prototype.keys()、Array.prototype.values()和Array.prototype.entries()

Array.prototype.keys()

keys() 方法返回一个包含数组中每个索引键的Array Iterator对象。

此方法是ES6方法。
此方法不会改变数组。
返回值是一个新的 Array 迭代器对象。
var arr = ["a", , "c"];
var sparseKeys = Object.keys(arr);
var denseKeys = [...arr.keys()];
console.log(sparseKeys); // [''0'', ''2'']
console.log(denseKeys);  // [0, 1, 2]

Array.prototype.values()

values() 方法返回一个新的 Array Iterator 对象,该对象包含数组每个索引的值

 

此方法是ES6方法。
此方法不会改变数组。
let arr = [''w'', ''y'', ''k'', ''o'', ''p''];
let eArr = arr.values();
// 您的浏览器必须支持 for..of 循环
// 以及 let —— 将变量作用域限定在 for 循环中
for (let letter of eArr) {
  console.log(letter);
}

另一种迭代方式

let arr = [''w'', ''y'', ''k'', ''o'', ''p''];
let eArr = arr.values();
console.log(eArr.next().value); // w
console.log(eArr.next().value); // y
console.log(eArr.next().value); // k
console.log(eArr.next().value); // o
console.log(eArr.next().value); // p

Array.prototype.entries()

entries() 方法返回一个新的Array Iterator对象,该对象包含数组中每个索引的键/值对。

此方法是ES6方法。
此方法不会改变数组。
var arr = ["a", "b", "c"];
var iterator = arr.entries();
// undefined

for (let e of iterator) {
    console.log(e);
}

// [0, "a"] 
// [1, "b"] 
// [2, "c"]

 

Array.prototype.push.apply(a,b)和Array.prototype.slice.call(arguments)

Array.prototype.push.apply(a,b)和Array.prototype.slice.call(arguments)

Array.prototype.push.apply(a,b)

时常看到在操作数组的时候有这样的写法:

var a = [1,2,3];
var b = [4,5,6];

a.push.apply(a, b);

console.log(a) //[1,2,3,4,5,6]

其实这样的写法等价于:

var a = [1,2,3];
var b = [4,5,6];

Array.prototype.push.apply(a, b);

console.log(a) //[1,2,3,4,5,6]

这样写法等价的原因是因为在实例上寻找属性的时候,现在这个实例自己身上找,如果找不到,就根据内部指针__proto__随着原型链往上找,直到找到这个属性。

在这里就是寻找push方法,两种写法最后找到的都是Array构造函数对应的prototype的原生方法push。所以说两种写法是等价的。

但是为什么要使用a.push.apply(a,b);这种写法呢?为什么不直接使用push()?

如果直接push:

var a = [1,2,3];
var b = [4,5,6];

a.push(b);

console.log(a) //[1, 2, 3, Array(3)]

这样就看出来区别了,原生push方法接受的参数是一个参数列表,它不会自动把数组扩展成参数列表,使用apply的写法可以将数组型参数扩展成参数列表,这样合并两个数组就可以直接传数组参数了。

但是合并数组为什么不直接使用Array.prototype.concat()呢?

因为concat不会改变原数组,concat会返回新数组,而上面apply这种写法直接改变数组a。

同理,Math.max和Math.min也可以使用apply这种写法来传入数组参数。

比如这样:

Math.max.apply(null,a)

这样就可以很方便的传入数组参数了。

Array.prototype.slice.call(arguments)

类似的还有这样的写法,MDN解释slice方法可以用来将一个类数组(Array-like)对象/集合转换成一个新数组。你只需将该方法绑定到这个对象上。 

所以可以使用slice将函数的参数变成一个数组,然后就可以当做数组来操作了。

Object.prototype.hasOwnProperty.call(object,prop)

类似还有这样的写法,这样写是因为js没有保护hasOwnProperty 属性名,hasOwnProperty 有可能被修改为其他方法,所以这样写可以调用到原生的Objext原型上的hasOwnProperty 方法。这样写等价于({}).hasOwnProperty.call(object,prop)

Object.prototype.toString.call()

这样的写法是为了判断一个变量是什么类型的数据:

var toString = Object.prototype.toString;

toString.call(123); //"[object Number]"
toString.call(''abcdef''); //"[object String]"
toString.call(true); //"[object Boolean]"
toString.call([1, 2, 3, 4]); //"[object Array]"
toString.call({name:''wenzi'', age:25}); //"[object Object]"
toString.call(function(){ console.log(''this is function''); }); //"[object Function]"
toString.call(undefined); //"[object Undefined]"
toString.call(null); //"[object Null]"
toString.call(new Date()); //"[object Date]"
toString.call(/^[a-zA-Z]{5,20}$/); //"[object RegExp]"
toString.call(new Error()); //"[object Error]"

使用Object.prototype.toString.call()的方式来判断一个变量的类型是最准确的方法。

Array.prototype.toString()和Array.prototype.toLocaleString()

Array.prototype.toString()和Array.prototype.toLocaleString()

Array.prototype.toString()

toString() 返回一个字符串,表示指定的数组及其元素。

Array 对象覆盖了 Object 的 toString 方法。对于数组对象,toString 方法返回一个字符串,该字符串由数组中的每个元素的 toString() 返回值经调用 join() 方法连接(由逗号隔开)组成。
当一个数组被作为文本值或者进行字符串连接操作时,将会自动调用其 toString 方法。
var monthNames = [''Jan'', ''Feb'', ''Mar'', ''Apr''];
var myVar = monthNames.toString(); // assigns "Jan,Feb,Mar,Apr" to myVar.


var i = [1, 2, 3,[1, 2, 3, [1, 2, 3]]];
i.toString()
//"1,2,3,1,2,3,1,2,3"

其实toString()就是返回了String(this)

Array.prototype.toLocaleString()

toLocaleString() 返回一个字符串表示数组中的元素。数组中的元素将使用各自的 toLocaleString 方法转成字符串,这些字符串将使用一个特定语言环境的字符串(例如一个逗号 ",")隔开。
locales 可选
带有BCP 47语言标记的字符串或字符串数组
options 可选
一个可配置属性的对象,对于数字 Number.prototype.toLocaleString(),对于日期Date.prototype.toLocaleString().
使用locales和options
数组中的元素将会使用各自的 toLocaleString 方法:

Object: Object.prototype.toLocaleString()
Number: Number.prototype.toLocaleString()
Date: Date.prototype.toLocaleString()
总是在prices数组中显示字符串和数字的货币符号:
var prices = [''¥7'', 500, 8123, 12];
prices.toLocaleString(''ja-JP'', { style: ''currency'', currency: ''JPY'' });

// "¥7,¥500,¥8,123,¥12"
Polyfill
// https://tc39.github.io/ecma402/#sup-array.prototype.tolocalestring
if (!Array.prototype.toLocaleString) {
    Object.defineProperty(Array.prototype, ''toLocaleString'', {
      value: function(locales, options) {
        // 1. Let O be ? ToObject(this value).
        if (this == null) {//空数组抛错误
          throw new TypeError(''"this" is null or not defined'');
        }
  
        var a = Object(this);//转成对象
  
        // 2. Let len be ? ToLength(? Get(A, "length")).
        var len = a.length >>> 0;//数组长度
  
        // 3. Let separator be the String value for the 
        //    list-separator String appropriate for the 
        //    host environment''s current locale (this is 
        //    derived in an implementation-defined way).
        // NOTE: In this case, we will use a comma
        var separator = '','';//分隔符是逗号
  
        // 4. If len is zero, return the empty String.
        if (len === 0) {//如果长度为0,返回空字符串
          return '''';
        }
  
        // 5. Let firstElement be ? Get(A, "0").
        var firstElement = a[0];//第一个数组元素
        // 6. If firstElement is undefined or null, then
        //  a.Let R be the empty String.
        // 7. Else,
        //  a. Let R be ? 
        //     ToString(? 
        //       Invoke(
        //        firstElement, 
        //        "toLocaleString", 
        //        « locales, options »
        //       )
        //     )
        var r = firstElement == null ? 
          '''' : firstElement.toLocaleString(locales, options);//判断第一个元素为空情况然后计算后赋值给r
  
        // 8. Let k be 1.
        var k = 1;
  
        // 9. Repeat, while k < len
        while (k < len) {//循环数组
          // a. Let S be a String value produced by 
          //   concatenating R and separator.
          var s = r + separator;//分隔符
  
          // b. Let nextElement be ? Get(A, ToString(k)).
          var nextElement = a[k];//下一个字符
  
          // c. If nextElement is undefined or null, then
          //   i. Let R be the empty String.
          // d. Else,
          //   i. Let R be ? 
          //     ToString(? 
          //       Invoke(
          //        nextElement, 
          //        "toLocaleString", 
          //        « locales, options »
          //       )
          //     )
          r = nextElement == null ? 
            '''' : nextElement.toLocaleString(locales, options);//下一个字符转换成字符串
  
          // e. Let R be a String value produced by 
          //   concatenating S and R.
          r = s + r;
  
          // f. Increase k by 1.
          k++;
        }
  
        // 10. Return R.
        return r;
      }
    });
  }

 

今天关于javascript – 方法Set.prototype.add调用不兼容的接收器undefinedjs无法调用的讲解已经结束,谢谢您的阅读,如果想了解更多关于Array.prototype.find()、Array.prototype.findIndex()、Array.prototype.keys()、Array.prototype.values()和Array.prototype.entries()、Array.prototype.push.apply(a,b)和Array.prototype.slice.call(arguments)、Array.prototype.toString()和Array.prototype.toLocaleString()的相关知识,请在本站搜索。

本文标签: