JavaScript高級知識技術


オブジェクト
Jsは全部でnumber、string、boolean、null、undefined、objectの6つの主要なタイプを持っています.objectを除いて他の5つのタイプは基本タイプです.それら自体は対象ではありません.しかし、nullは、異なるオブジェクトが下の層ではバイナリとして表されており、jsではバイナリの上位3桁が0であるとobjectタイプと判定され、nullの2値はすべて0であるため、typeof演算子を使用してobjectに戻り、後続のJsバージョンは前の埋められた穴に対応するため、このバグを修復しませんでした."I'm a string"自体は字面量であり、可変ではない値であり、この字面量の上でいくつかの操作を実行する場合、例えば、長さを取得し、ある文字にアクセスするなど、Stringタイプに変換する必要があり、必要な時にはjsが自動的にこの変換を完了してくれます.つまり、new String('I'm a string')で表示されるオブジェクトを作成する必要はありません.同様の像を42.359.toFixed(2)で使うと、エンジンは自動的にNumberオブジェクトに数字を変換します.nullおよびundefinedには、文字形式のみの対応する構成形態がない.逆に、Dateは構造のみであり、文字形式はない.Object、Array、FunctionおよびRegExp(正規表現)の場合、文字形式または構造形式のいずれを使っても対象であり、字面量ではない.
Arayタイプ
配列のタイプには、より構造的な値記憶機構がありますが、配列もオブジェクトですので、配列に属性を追加することもできます.
var myArray = ["foo", 42, "bar"];
myArray.baz = "baz";
myArray.length; // 3
myArray.baz; // "baz"
配列タイプのlength属性は、読み取り専用ではなく、つまり値を変更することができるのが特徴です.この属性を設定することで、配列の最後から新しい項目を削除または追加することができます.
var colors = ["red", "blue", "green"];
colors.length = 2;
console.info(colors[2]); // undefined
colors.length = 4;
console.info(colors[4]); // undefined
//        
colors[colors.length] = "black";
配列には、every()、filter()、forEach()、map()、some()のような便利な反復方法があります.これらの方法は、配列に含まれる値を変更しません.これらの方法に導入された関数は、3つのパラメータを受信します.配列項目の値、この項目は、数セット内の位置、および配列オブジェクト自体です.
Functionタイプ
ECMAScriptでは、各関数はFunctionクラスの例であり、他の参照タイプと同様に属性と方法を有する.関数時のオブジェクトなので、関数名は実際に関数オブジェクトを指すポインタでもあり、関数とは結合されません.
関数の内部には2つの特殊なオブジェクトがあり、thisおよびargumentsがある.argumentsオブジェクトはcalleeおよびcaller属性を有する.callerは、呼び出されたfunctionオブジェクトを指し、直接にグローバル環境で呼び出されるとnullに戻る.calleeは現在の実行関数を指すために使用されていますので、階乗関数は以下のように実現できます.
function factorial(num) {
     
    if (num <= 1) {
     
        return 1;
    } else {
     
        return num * arguments.callee(num-1);
    }
}
各関数は、2つの非継承的な方法を含み、apply()およびcall()は、いずれも特定の機能領域で関数を呼び出すものであり、実際には関数体内thisオブジェクトを設定する値に等しい.まず、apply()方法は、2つのパラメータを受信し、1つは機能の作用領域であり、もう1つはパラメータ配列であり、2番目のパラメータはArrayの例であっても良いし、argumentsオブジェクトであっても良い.call()方法は、apply()方法の機能と同じであり、それらの違いは、単に受信パラメータの方式が異なるだけであり、call()方法を使用する場合は、1つずつ列挙しなければならない.
window.color = "red";
var o = {
     color: "blue"};
function sayColor() {
     
    console.info(this.color);
}
sayColor(); // red
sayColor.call(this); // red
sayColor.call(window); // red
sayColor.call(o); // blue
sayColor.apply(o); // blue
厳密なモードで環境オブジェクトを指定せずに関数を呼び出すと、this値は、特定のオブジェクトに関数を追加するか、またはwindowまたはapply()を呼び出すか、call()に変換されないことに留意されたい.
安全のタイプチェック
Jsに内蔵されているタイプチェック機構は、Safari(第5版前)のように完全に信頼できるものではなく、正規表現にtypeofを適用するとfunctionに戻ります.instanceofのように、複数のグローバルスコープ(frameを含む)が存在する場合にも、信頼できない結果が返ってくる.前文のJsが最初に埋めた穴もタイプチェックのミスを招きます.toString()方式を使用してセキュリティタイプ検査の目的に達することができ、任意の値でObject元のtoString()メソッドを呼び出すと、[object NativeConstructorName]フォーマットの文字列が返され、次に配列をチェックする例がある.
Object.prototype.toString.call([]); // "[object Array]"
function isArray(val) {
     
    return Object.prototype.toString.call(val) == "[object Array]";
}

スコープの安全な構造関数
構造関数とは、newオペレータを使用して呼び出された関数であり、newオペレータを使用して呼び出されたとき、構造関数内で使用されるthisオブジェクトは、新たに作成されたオブジェクトのインスタンス、例えば、次のようなコンストラクタを指す.
function Person(name, age) {
     
    this.name = name;
    this.age = age;
}
今の問題はnew操作機を使わないということですか?何が起こるか
let person = Person('name', 23);
console.info(window.name); // name
console.info(window.age); // 23
ここでは、大域的な作用領域が汚染されているのは、newオペレータを使用してコンストラクタを呼び出していないからであり、このときは普通の関数として呼び出され、thiswindowオブジェクトに解析されるからである.構造関数を、最初にthisが正しいタイプかどうかを確認する例に変更する必要があります.そうでない場合は、新しいインスタンスを作成して返します.
function Person(name, age) {
     
    if (this instanceof Person) {
     
        this.name = name;
        this.age = age;
    } else {
     
        return new Person(name, age);
    }
}
アドバンストタイマー
ほとんどの人は、setTimeout()setInterval()を使用して、タイミングタスクを簡単に作成することができることを知っています.Jsもマルチスレッドのように見えます.実際にタイマーは計画コードだけで、将来のある時間に実行しますが、実行タイミングは保証されません.ページのライフサイクルでは、他のコードがJavaScriptプロセスを制御している可能性があります.
ここでは、setInterval()関数は、タイマーの他のコード例がない場合にのみ、Jsは、タイマーコードをキューに追加することができます.このようにして、タイマーコードはコードが再度キューに追加される前に実行が完了していない可能性があり、タイマーコードが連続して何回も実行される問題を回避することができます.しかし、これはまた、(1)間隔によってはスキップされます.(2)複数のタイマのコード実行間の間隔は、予想よりも小さいかもしれない.
あるclickイベントハンドラがsetInterval()を使用して200 ms間隔の重複タイマを設定したと仮定する.このイベントハンドラが300 ms以上の時間で完了すると、タイマーコードもほぼ時間がかかり、スキップして連続運転タイマーコードを切る場合があります.setInterval()の重複タイマーのこの2つの欠点を回避するために、コードは下記のパターンのチェーンsetTimeout()を使用してもいいです.
setTimeout(function() {
     
    //    
    setTimeout(arguements.callee, interval);
}, interval)
メッセージキューとイベントループ
左のスタックには、図のように同期タスクが格納されています.変数や関数の初期化、イベントのバインディングなど、すぐに実行でき、時間がかかりません.
[外部チェーン写真の転送に失敗しました.ソースステーションは盗難防止チェーン機構があるかもしれません.画像を保存して直接アップロードすることを提案します.(file://D:/workspace/blog/post-mages/15791033039.png).
右側のヒープは宣言の変数、オブジェクトを格納するために使用されます.次の列はメッセージキューです.ある非同期タスクに応答すると、キューに押し込まれます.ユーザのクリックイベント、ブラウザの受信サービスの応答、およびsetTimeoutで実行されるイベントのように、各非同期タスクは、コールバック関数に関連しています.JSエンジンスレッドは、スタック内の同期タスクを実行するために使用され、すべての同期タスクが実行された後、スタックはクリアされ、メッセージキューの中の処理待ちタスクを読み出し、関連するコールバック関数をスタックに押し込み、新しい同期タスクを実行するために単一スレッドが開始される.
例を見てください.下記のコードを実行して、実行後、5秒以内に2回クリックして、しばらくの間(>5s)後、さらに2回クリックして、過程全体の出力結果は何ですか?
setTimeout(function(){
     
    for(var i = 0; i < 100000000; i++){
     }
    console.log('timer a');
}, 0)
for(var j = 0; j < 5; j++){
     
    console.log(j);
}
setTimeout(function(){
     
    console.log('timer b');
}, 0)
function waitFiveSeconds(){
     
    var now = (new Date()).getTime();
    while(((new Date()).getTime() - now) < 5000){
     }
    console.log('finished waiting');
}
document.addEventListener('click', function(){
     
    console.log('click');
})
console.log('click begin');
waitFiveSeconds();
まず、同期タスクを実行します.waitFiveSecondsは時間のかかる動作であり、5 sまで継続的に実行される.そして、Jsエンジンスレッドが実行されると、'timer a'に対応するタイマーによって生成されるコールバック、'timer b'に対応するタイマーによって生成されるコールバック、および2回のclickに対応するコールバックが、相次いでメッセージキューに入れられる.Jsエンジンスレッドが空きましたら、イベントが実行可能かどうかを確認してから、他の非同期タスクを処理します.最後に、5 s後の2回のclickイベントはメッセージキューに入れられます.この時Jsエンジンスレッドが空きましたので、直ちに実行されました.このため、以下の出力順序が発生します.
0
1
2
3
4
click begin
finished waiting
click
click
timer a
timer b
click
click