擬似配列を実配列に変換することについて

ちょうど問題が発生しました. 引数によって受け入れられる実際のパラメーターはリストであり、取得するのは配列のようなものなので、無限のパラメーターの合計を実現したい. 配列の合計をトラバースするとき、forEachトラバーサルを使用しましたが、エラーです。そのため、コードは次のようになります。

sum(1,2,3,4,5);
function sum () {
    
    
var total = 0;
arguments.forEach(v =>{
    
    
total += v;
})
return total()
}

コードを実行した後、次のようにエラーが報告されます
ここに画像の説明を挿入
最後に百度で長々と検索したところ、実際、これは実際の配列ではなく、配列に似た配列状または疑似配列です。

疑似配列とは何かを見てみましょう。
1. 実際のパラメーターを受け取るために使用されるメソッドの引数を見てみましょう. 実行コードは次のとおりです:

function fu() {
    
    
console.log(arguments);
}
fu(1,2,3,4,5,)

コンソールは次のように出力されます:
ここに画像の説明を挿入
ここでは、Arguments 表示にも角かっこ [1,2,3,4,5...] があることがわかりますが、背後には他のメソッドがいくつかあります。length 属性もありますが、配列は配列ではないように、配列のプッシュ、ポップ、およびその他のメソッドはありません。

2. 印刷して、getElementsByClassName などの他のものを確認することもできます。

<template>
  <div></div>
  <div></div>
  <div></div>
</template>
<script>
   var oDivs = document.getElementsByTagName('div')
   console.log(oDivs)
</script>

コンソールは次のように出力されます:
ここに画像の説明を挿入
ここでは、HTMLCollection も角かっこ [1,2,3,4,5…] を表示していることがわかりますが、背後には他のメソッドがいくつかあります。長さ属性もありますが、配列は配列ではないなど、配列のプッシュ、ポップ、およびその他のメソッドもありません。

簡単にまとめると、疑似配列には次のような特徴があります。
1. length 属性を使用すると、長さを取得できます;
2. 添字インデックスを使用すると、length 属性をトラバースしてすべての値を取得できます。
3. ただし、配列の組み込みメソッドは使用できません。

それでは、疑似配列が配列の組み込みメソッドとプロパティを使用できない理由を調べる必要がありますか?


ここに画像の説明を挿入
まず、上図の [[prototype]] から、引数疑似配列のプロトタイプが Object オブジェクトを指しており、実数配列を表示していることがわかります。array は Array 配列を指す.
上図からもわかる [[prototype]] タグ名でページ要素を取得して得られる疑似配列のプロトタイプが HTMLCollection オブジェクトを指していることがわかる.

これまでのところ、疑似配列のプロトタイプが異なることもわかります。実際、それは別のオブジェクトであり、配列の要素は配列であり、実際の配列の本質とは異なります。これが理由です。擬似配列は配列のプロパティとメソッドを使用できません。つまり、forEach や pop などの配列メソッドを使用したくない場合は、それらを実際の配列に変換して使用する必要があります。配列のさまざまな方法。

次のステップは、疑似配列を実数配列に変換する方法を調べることです。

コード実行段階は次のとおりです。
方法 1: トラバーサル: 空の配列を作成し、疑似配列をループして、走査したデータを空の配列に 1 つずつ入れます。

伪数组:
var ali = document.getElementsByTagName('li');
console.log(ali);       // [li, li, li, li]
// ali.push("hello");      // TypeError: ali.push is not a function
...........................................................................................分割线
转为真数组:
var arr = [];           // 先创建空数组
for(var i=0;i<ali.length;i++){
    
      // 循环遍历伪数组
    arr[i] = ali[i];    // 取出伪数组的数据,逐个放在真数组中
}

arr.push("hello");
console.log(arr);       // [li, li, li, li, "hello"]

方法 2: Array のスライス インターセプト メソッドを呼び出す。[].slice.call()

	const divs = document.querySelectorAll('div');
	console.log(divs instanceof Array);
	const arr = [].slice.call(divs);
	console.log(arr instanceof Array);
	// false
	// true

スライス メソッドを使用して変換を行う方法を知りたい場合は、配列のスライス メソッドの内部実装原理を知る必要があります。スライス法を簡単にシミュレートしてみましょう。

	function slice(start,end){
    
    
  		const startIndex = start || 0;
  		const endIndex = end || this.length;
  		let tempArr = [];
  		for(let i = startIndex;i < endIndex;i++){
    
    
          tempArr.push(this[i]);
  		}
  		return tempArr;
	}

疑似配列を実配列に変換するキーとなるのは this 内で、 this 内を call() メソッドで疑似配列オブジェクトにバインドし、疑似配列の各項目を引数で実配列にプッシュします。ループして、この真の配列を返します。

方法 3: スライス メソッドを使用する: Array プロトタイプ オブジェクトのスライス メソッドを使用し、apply と連携して、これをスライス内で疑似配列にポイントします。Array.prototype.slice.call()
3 つ目の方法も Array のスライスを呼び出すことによる傍受方法であり、2 つ目と 3 つ目の方法の違いを以下の概要で分析します。

伪数组:
var ali = document.getElementsByTagName('li');
console.log(ali);       // [li, li, li, li]
// ali.push("hello");      // TypeError: ali.push is not a function
..........................................................................................分割线
转为真数组:
var arr = Array.prototype.slice.apply(ali);

arr.push("hello");
console.log(arr);       // [li, li, li, li, "hello"]

方法 4: ES6 が提供する Array の from メソッドを使用する /この方法には互換性の問題がありますES6 Array.form()

伪数组:
var ali = document.getElementsByTagName('li');
console.log(ali);       // [li, li, li, li]
// ali.push("hello");      // TypeError: ali.push is not a function
........................................................................................分割线
转换为真数组:
var arr = Array.from(ali);

arr.push("hello");
console.log(arr);       // [li, li, li, li, "hello"]

方法 5: ES6 が提供する展開演算子を使用する (…)/この方法には互換性の問題があります

伪数组:
var ali = document.getElementsByTagName('li');
console.log(ali);       // [li, li, li, li]
// ali.push("hello");      // TypeError: ali.push is not a function
...........................................................................................分割线
转换为真数组:
var arr = [...ali];
arr.push("hello");
console.log(arr);       // [li, li, li, li, "hello"]

方法 6: プロトタイプのコピー: 疑似配列のプロトタイプを配列のプロトタイプとしてコピーします。しかし、このアプローチには限界があります

  • 疑似配列として、インデックスと長さを持つオブジェクトを手動で作成します
var obj = {
    
    
    0:"a",
    1:"b",
    2:"c",
    length:3
}
console.log(obj);       // {0: "a", 1: "b", 2: "c", length: 3}
// obj.push();          // TypeError: obj.push is not a function

obj.__proto__ = Array.prototype;

console.log(obj);       // ["a", "b", "c"]
obj.push("hello");
console.log(obj);       // ["a", "b", "c", "hello"]
  • 引数も適用されます
function fn(){
    
    
    var arg = arguments;
    console.log(arg);       // ["a", "b", ...]
    // arg.push("hello");   // TypeError: arg.push is not a function

    arg.__proto__ = Array.prototype;

    arg.push("hello");
    console.log(arg);       // ["a", "b", "hello", ...]
}
fn("a","b");
  • セレクターによって返される要素セットは適用されません。要素セットのプロトタイプが配列プロトタイプに変更された場合でも (図 5 を参照)、要素セット自体は読み取り専用であり、変更できないためです。
var ali = document.getElementsByTagName('li');
console.log(ali);            // [li, li, li, li]
// ali.push("hello");        // TypeError: ali.push is not a function

ali.__proto__ = Array.prototype;

// ali.push("hello");        // Index property setter is not supported

図 5
ただし、元の配列のメソッドを変更せずに使用できるという意味ではありません (上の図に注意してください。長さの属性はありません)。

ali.forEach(val => {
    
    
    console.log(val);
});

// 会发现浏览器没执行,原因是此时ali缺少length或length为0
console.log(ali.length);    // 0

アリの長さは事前に取得し、プロトタイプを変更した後に手動で設定する必要があります

var ali = document.getElementsByTagName('li');
console.log(ali);            // [li, li, li, li]
// ali.push("hello");        // TypeError: ali.push is not a function

var len = ali.length;        // 获取初始length
ali.__proto__ = Array.prototype;
ali.length = len;            // 设置给修改原型之后的数组对象

// ali.push("hello");        // Index property setter is not supported
ali.forEach(val => {
    
    
    console.log(val);        // 遍历打印数组中的值
});
console.log(ali.length);     // 4

ヒント: セレクターによって返される要素配列はコピー プロトタイプ メソッドを使用し、長さプロパティは手動で設定する必要があり、元の配列を変更するメソッドは使用できません。

要約:

  • [].slice.call() と Array.prototype.slice.call() の違いは、Array.prototype を検索する方が効率的であることです。
  • [] を介してスライス メソッドを呼び出すには、プロトタイプ チェーンを介してスライス メソッドを見つける必要があります。
  • 手動で作成された疑似配列オブジェクトを分解して代入する場合、イテレータ インターフェイスを追加する必要があります。

上記は、疑似配列を実配列に変換するための編集者の理解と解決策です. いくつかの方法が照会されます. テキストに誤りがある場合は、メッセージを残して修正してください...

おすすめ

転載: blog.csdn.net/wen15191038073/article/details/126470189