41766


こんにちは。

次のところで紹介されている、  
Array.find についてなのですが

Array.prototype.find() - JavaScript | MDN  
<https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/find>

ほとんどのところはわかるのですが

[code]

    var list = Object(this);
    var length = list.length >>> 0;
    
[/code]

このように書かれたところがわかりません。  
thisは、配列がくると思うのですが、  
それをObjectにキャストして、length をビット演算で求める...？？  
これは何をしているのでしょうか？

Arraylikeオブジェクトに対してArray.find.call するための仕組み？  
うーん、それにしてもビット演算する理由がさっぱりです。

JSの高いレベルをお持ちの方、教えてください。  
あるいは参考ページなど示していただければ助かります。

よろしくおねがいします。


CC BY-SA 3.0
2018-02-16T02:33:52.277
41762
2018-02-16T06:04:42.950
21047
question
javascript
MDNのArray.prototype.findのPolyfilについて


おそらくですが、0埋め右シフト演算子で0ビットシフトしている処理は length
をループ終端として使うため、符号なし整数であることを保証したいのだと思います。

※参照先のコードでその処理が必要であるかはわかりません。

[code]

    >> console.log(1 << 31)
    -2147483648 debugger eval code:1:1
    undefined
    >> console.log((1 << 31) >> 0)
    -2147483648 debugger eval code:1:1
    undefined
    >> console.log((1 << 31) >>> 0)
    2147483648
    
[/code]


CC BY-SA 3.0
2018-02-16T03:00:56.727
41764
2018-02-16T03:00:56.727
27410
41762
answer


[ページの英語版](https://developer.mozilla.org/en-
US/docs/Web/JavaScript/Reference/Global_Objects/Array/find#Polyfill)にあるコードにはちゃんとコメントが書いてあるのですが、結論からいうと[言語仕様](https://tc39.github.io/ecma262/#sec-
array.prototype.find)に（なるべく）マッチした実装をする（ひとつの）書き方としてこのようにしています。

函数`Array.prototype.find`は言語仕様で次のように定義されています:

> ### 22.1.3.8 Array.prototype.find(predicate [, thisArg ])
>
> When the find method is called, the following steps are taken:
>
>   1. Let O be ? ToObject(this value).
>   2. Let len be ? ToLength(? Get(O, "length")).  
>  ...(略)
>

質問にあるコードの第一行目は言語仕様でいう1.の手続きを実装するものです。抽象演算[`ToObject`](https://tc39.github.io/ecma262/#sec-
toobject)はオブジェクトを規則（Table
12）に従ってObject型のオブジェクトに変換します。この処理はObject型にするというより、nullやundefinedで” _Throw a
TypeError exception._
”するためのチェック処理だと考えていいでしょう。ただし、これは内部的な関数なので「ふつうの」JSでは呼び出せません。これに適合する互換コードとして、

[code]

    // 1. Let O be ? ToObject(this value).
    if (this == null) {
      throw new TypeError('"this" is null or not defined');
    }
    var o = Object(this);
    
[/code]

なるコードを用いています（より明示的に書けば`if (typeof this === 'undefined' || this === null)
{`ですね）。

言語仕様における2.の手続きは、1.で得たオブジェクトの`length`プロパティを抽象演算[`ToLength`](https://tc39.github.io/ecma262/#sec-
tolength)演算で数値化しています。

> ### 7.1.15 ToLength(argument)
>
>   1. Let len be ? ToInteger(argument).
>   2. If len ≤ +0, return +0.
>   3. Return min(len, 253-1).
>

ここではさらに抽象演算`ToInteger,min`などを呼び出していますが、要約すると「配列の要素数」として扱うために非負整数の値に変換するものです。他方、演算子[`>>>`;
Unsigned Right Shift Operator](https://tc39.github.io/ecma262/#sec-unsigned-
right-shift-operator)は、

> The result is an unsigned 32-bit integer.

とあるように、数値を符号なし32bit整数に”変換”します。これは厳密には等価ではないですが[*1]、bitwiseな処理なのでたぶん最適化されていて高速なことが期待でき（これは言語仕様とは関係ありません）、様々な箇所で数値の整数化として頻繁に用いられるものです。この演算子を用いて抽象演算`ToLength`を代替しているのが次のコードです:

[code]

    // 2. Let len be ? ToLength(? Get(O, "length")).
    var len = o.length >>> 0;
    
[/code]

このように、言語仕様と比較して実装がどうであるかというのは、動作を保証する意味において重要です。たとえば、`length`プロパティが負であっても浮動小数点数であってもあるいは
_Number型でなくても_ [*2]その値で`for (let i = 0; i < obj.length; i++)
{`とするコードを書いたとして、通常の利用ではたいして問題になりません。しかし、「これ」を「`Array.prototype.find`」にpolyfillとして代入するのは避けるべきであるというのが、Javascriptプログラマの一般的な慣習かと思われます。

* * *

[*1]: `console.assert(Math.pow(2,30) >>> 0 ===
Math.pow(2,30));`ですが`console.assert(Math.pow(2,50) >>> 0 !==
Math.pow(2,50));`です。  
ただし、[array index](https://tc39.github.io/ecma262/#array-index)が+0 ≤ i <
232-1と規定されていることから、配列の長さを扱うだけであれば問題はありません。

[*2]:
一般的には`Array`型オブジェクトの`length`プロパティに負の値は許容されませんが、`Array.prototype`の函数は意図して`Array`型以外にも使えるよう一般化されて実装されていることが知られています。


CC BY-SA 3.0
2018-02-16T04:09:27.177
41766
2018-02-16T06:04:42.950
2018-02-16T06:04:42.950
41762
answer