学習第5話毎週学習内容


!ちょっと待って。プロトタイプコンセプトに再アクセスします。


なぜ文字で生成された文字列がinstanceofStringでfalseを吐くのか...?

instanceofの問題?

const literalString = '123'
undefined
const builtInString = new String(123)
undefined
typeof literalString
'string'
typeof builtInString
'object'
(builtInString instanceof String)
true
(literalString instanceof String)
false
Object.getPrototypeOf(literalString)
// String {'', constructor: ƒ, anchor: ƒ, big: ƒ, blink: ƒ, …}
literalString.__proto__
// String {'', constructor: ƒ, anchor: ƒ, big: ƒ, blink: ƒ, …}
literalString.constructor
// ƒ String() { [native code] }
instanceofはオブジェクトの時に正しい評価を与えますか?したがって,instanceofにおける依存値のタイプ判定に問題が生じる可能性がある.
As you can see both typeof and instanceof are insufficient to test whether a value is a boolean, a number or a string - typeof only works for primitive booleans, numbers and strings; and instanceof doesn't work for primitive booleans, numbers and strings.
非オブジェクト値=すなわち元の値=換言すると、コンストラクション関数によって生成されない値に対してfalseが放出されます.
簡単な解決策は、typeofを使用して原語値のタイプを区切り、instanceof演算子を使用してreferencetype値のタイプを区切ります.

コンストラクション関数と非コンストラクション関数の区別


すべての関数には内部メソッド[call]または[構築]があります.
これは、[construct]を有する関数を構造関数(すなわち、構造関数)として呼び出すことができることを意味する.
コンストラクション関数:関数宣言、関数式、クラス
non-constructor:メソッド、矢印関数
Fortunately there's a simple solution to this problem. The default implementation of toString (i.e. as it's natively defined on Object.prototype.toString) returns the internal [[Class]] property of both primitive values and objects:
function classOf(value) {
    return Object.prototype.toString.call(value);
}

コール関数の理解


黙示戦を同時に見る


This


どうして必要なの?


オブジェクト内部のメソッドは、そのオブジェクトのステータスを参照および変更できます.この場合、所属するオブジェクトのプロパティを参照する場合は、以前に所属するオブジェクトを指す識別子を参照できる必要があります.あるいは、インスタンスオブジェクトにPropertyとメソッドを割り当てるには、オブジェクトを参照できる必要があるため、このキーワードを使用します.

オブジェクトテキストで作成されたオブジェクト


オブジェクトのテキストで作成されたオブジェクトについては、メソッドの内部でそのオブジェクトを指す識別子を再帰的に参照できます.
//객체 리터럴은 circle 변수에 할당되기 직전에 평가된다.
const circle = {
  radius: 5,
  getDiameter(){
    return circle.radius * 2
  }
}
//즉 getDiameter 메서드 호출 시점에 
//이미 객체 리터럴의 평가가 완료 되어 객체가 생성되고 circle 식별자에 할당되었기 때문.
console.log(circle.getDiameter());
最終的にはコードの位置によって影響を及ぼします.したがって,再帰的参照方式は推奨されない.
//ReferenceError: circle is not defined
console.log(circle.getDiameter());
const circle = {
  radius: 5,
  getDiameter(){
    return circle.radius * 2
  }
}

コンストラクション関数を使用して作成されたオブジェクトの場合:


従来のメソッド作成とは異なり、コンストラクション関数の内部にメソッド、Propertyなどを追加するには、自分が作成するインスタンスを参照できる必要があります.コンストラクション関数として作成されるオブジェクトは、まず関数を定義し、new演算子とともにコンストラクション関数を呼び出す必要があります.すなわち,関数を定義する際に,将来生成するインスタンスを示す識別子がまだ分からない.
このため、JavaScriptには、所属するオブジェクトまたは作成するインスタンスを指す特殊な識別子thisが用意されています.thisは、コード内の任意の場所で参照できますが、thisが指す値(すなわち、100πthisバインド)は、関数呼び出しに基づいて動的に決定されます.
先ほどオブジェクト文字でオブジェクトを作成したコードを変更します.
=>
const circle = {
  radius: 5,
  getDiameter(){
    return this.radius * 2
  }
}
console.log(circle.getDiameter())
const circle = {
  radius: 5
}

const circle2 = {
  radius: 10
}

const getDiameter = function getDiameter(){
    return this.radius * 2
}
circle.getDiameter = getDiameter;
circle2.getDiameter = getDiameter;

// 이처럼 this는 호출 방식에 따라 바인딩 되는 값이 다르다.
// 메서드로 호출되었기 때문에 .노테이션 앞의 객체(메서드를 호출한 객체)에 this값이 바인딩 됨.
console.log(circle.getDiameter()); // 10
console.log(circle2.getDiameter()); // 20
コンストラクション関数のthisバインドの例では、コンストラクション関数の内部のthisは、コンストラクション関数が作成する(将来の)インスタンスを指します.
const Circle = function(radius){
  this.radius = radius,
  Circle.prototype.getDiameter = function(){
    return this.radius * 2;
  }
}

const circle = new Circle(5);
circle.getDiameter();

関数呼び出しとバインド


この値を動的に決定するには、関数の呼び出し方法によって4つのケースがあります.
// 1. 전역에서 this 참조
console.log(this); 
// window

// 2. 일반 함수 내부의 this
function foo(){
  console.log(this);
}
foo();
// window
// 일반함수 내부에서 this는 사용할 필요가 없다. 
// strict mode에서는 undefined가 바인딩된다.

// 3. 메서드 내부의 this
const person = {
	name: 'kim',
  getName(){
    console.log(this)
    // 메서드를 호출한 객체 person
    return this.name
  }
}
console.log(person.getName())

// 4. 생성자 함수 내부의 this
function Person(name){
  this.name = name;
  console.log(this); // 생성자 함수가 생성한 instance
  this.getName = function(){
    return this.name
  }
}
const person1 = new Person('lee')
console.log(person1.getName())

const person2 = new Person('park')
console.log(person2.getName())
/*
Person {
  name: 'lee',
  __proto__: { constructor: ƒ Person() }
}
Person {
  name: 'park',
  __proto__: { constructor: ƒ Person() }
}
'lee'
'park'*/
コンストラクション関数として呼び出される関数を通常関数として呼び出すとどうなりますか?
const Circle = function(radius){
  this.radius = radius,
  this.getDiameter = function(){
    return this.radius * 2;
  }
}

const circle = new Circle(5);
circle.getDiameter()

// 일반 함수로 호출함
const circle2 = Circle(10)
console.log(circle2) // undefined
radius // 10
getDiameter() // 20

🤔これを明示的にバインドします。どうしたんですか。


任意の関数を通常の関数として呼び出すと、内部thisは最終的にグローバルオブジェクトをバインドします.
すなわち,メソッド内のネスト関数やコールバック関数などが通常の関数として呼び出されると,グローバルオブジェクトがバインドされ,最終的にこの値が一致せず,操作が困難になる.
var value = 100;
const obj ={
  value: 20,
  foo(){
    console.log(this); // obj
    console.log(this.value); // 20
    function bar(){
      console.log(this); // window
      console.log(this.value); // 100
    }
    bar();
  }
}

obj.foo(); 

解決策。

  • は、ネストされた関数またはコールバック関数の内部で変数を参照するために、このバインディングを変数に割り当てます.
  • Function.prototype.apply、call/bindなどの方法を使用します.
  • 矢印関数を使用して、このバインドを一致させます.
  • apply/call/bind


    bind法は,メソッドthisがメソッド内部のネスト関数またはコールバック関数thisと一致しない問題を解決するために用いられる.
    const person = {
      name: 'kim',
      foo(callback){
        callback();
      }
    }
    const callback = function(){
      console.log(`Hi, I'm ${this.name}.`)
    }
    person.foo(callback); // "Hi, I'm ."
    こんな感じで下のようにでも最初はコールバックでしたbind(this); と書くどうしてだめなの?どうしてだめなの?このように待っています;bind는 함수를 호출하지 않는다. 명시적으로 호출해야한다.
    const person = {
      name: 'kim',
      foo(callback){
        callback.bind(this)();
      }
    }
    const callback = function(){
      console.log(`Hi, I'm ${this.name}.`)
    }
    person.foo(callback); // "Hi, I'm kim."
    その他の例
    const person = {
    	name: 'kim',
      getName: function(){
        return this.name
      }
    }
    const unBound = person.getName;
    console.log(unBound()); // ''
    const bounded = person.getName.bind(person)
    console.log(bounded()); // 'kim'

    実行コンテキスト


    ソースコードのタイプ


    ソースコードは4種類に分かれています.JAvascriptエンジンは、ソースコードを評価することによって「실행 컨텍스트」を生成し、ソースコードのタイプに応じて実行コンテキストを生成するプロセスと管理内容が異なります.
  • グローバルコード
  • 関数コード
  • evalコード
  • モジュールコード
  • ソースコードの評価と実行



    コンテキストを実行する役割


    コードを実行するには、スキャン、識別子、コード実行順序などを管理する必要がありますが、これらを管理するのは実行コンテキストです.すべてのコードは、実行コンテキストとして実行および管理されます.二つに分けると、
    識別子、スキャン:実行コンテキストとして렉시컬 환경が管理されます.
    コード実行順序:実行コンテキストとして스택が管理される.

    コンテキストスタックの実行


    生成された実行コンテキストはスタックデータ構造によって管理されます.これを実行コンテキストスタックと呼びます.コード実行時間が経つにつれて、実行コンテキストスタックは実行コンテキストを追加および削除します.

    リモート環境


    識別子、スキャン:実行コンテキストとして렉시컬 환경が管理されます.
    Lexical環境は実行コンテキストを構成するコンポーネントであり、識別子と識別子にバインドされた値を管理し、Scopeチェーンを介して親Scopeへの参照を許可する.

    実行コンテキストで生成および識別子を検索するプロセス

    var x = 1;
    const y = 2;
    function foo(a){
    	var x = 3;
    	const y = 4;
    
    	function bar(b){
        const z = 5;
        console.log(a+b+x+y+z);
        }
        bar(10);
      }
    foo(20);

    1.グローバルオブジェクトの作成

  • グローバルオブジェクトもプロトタイプチェーンの一員です.Object.プロトタイプを継承します.
  • 2.グローバルコード評価


  • グローバル実行コンテキストの作成
  • グローバル実行コンテキストを生成し、実行コンテキストスタックにプッシュします.

  • グローバルコレクション環境の作成
  • グローバルディレクトリ環境を生成し、グローバル実行コンテキストにバインドします.
    1.グローバル環境記録の作成
    2.これをバインド
    3.外部ディレクトリ環境を決定するための参照
  • 3.グローバルコードの実行

  • グローバルコードが順次実行されます.変数付与文が実行されます.関数が呼び出されます.
    変数付与文または関数呼び出し文を実行するには、まず識別子を決定し、どのscopeを参照する識別子を決定し、プロシージャを実行する実行コンテキストで識別子の検索を開始する必要があります.
  • 4.関数コード評価

  • 関数を実行するコンテキストの作成
  • 関数実行コンテキストは、関数集合環境が完了した後、実行コンテキストスタックにプッシュされる.つまり、トップレベルの実行コンテキストになります.
  • 関数の集合環境の作成
  • 関数作成環境レコード
  • このバインディング
  • 外部集合環境への参照を決定する:해당 함수의 정의가 평가된 시점에 실행 중이던 실행 컨텍스트의 렉시컬 환경 참조가 할당된다.関数定義を評価するとき、この情報は関数オブジェクトの内部スロット[Environment]に格納される.これはモジュール概念と密接に関連している.
  • 5.関数コードの実行


    6.ネスト関数コードの評価


    7.ネスト関数コードの実行


    スキャン
  • コンソール識別子
    スキャンチェーンで識別子を検索する場合は、常に現在実行されている実行コンテキストのコレクション環境から開始し、外部コレクション環境への参照、検索を行います.
  • 8.ネストされた関数コードを終了する


    9.外部関数コードの実行を終了する


    10.グローバルコードの実行を終了


    エンクロージャ


    モジュールモード