Принцип typeof и instanceof

JavaScript

содержание

  • Типы данных JavaScript
  • typeof
  • Цепочка прототипов JavaScript
  • instanceof

Типы данных JavaScript

JavaScript имеет восемь встроенных типов

  • ноль ноль)
  • неопределенный
  • логический
  • количество
  • нить
  • объект
  • Символ (символ, новое в ES6)
  • Большое целое число (BigInt, представлено в ES2020)

За исключением объектов, все остальные вместе называются «примитивными типами».

typeof null // 'object'
typeof undefined; // "undefined"
typeof false; // "boolean"
typeof 1; // "number"
typeof '1'; // "string"
typeof {}; // "object" 
typeof []; // "object" 
typeof new Date(); // "object"

typeof Symbol(); // "Symbol"
typeof 123n // 'bigint'

Тип здесь относится к значению, переменная не имеет типа, и переменная может содержать значение любого типа в любое время. Переменные в JavaScript являются «слабо типизированными», теперь переменной можно присвоить строковый тип, а затем присвоить числовой тип.

typeofявляется оператором, а не функцией, которая проверяет тип данных данной переменной.

SymbolЭто вид, представленный в ES6.原始数据Тип, представляющий уникальное значение. BigInt (большое целое число) — это новый тип данных, представленный ES2020, который используется для решения проблемы, связанной с тем, что числа в JavaScript могут достигать только 53 двоичных битов (все числа в JavaScript хранятся как 64-битные числа с плавающей запятой, а целые числа больше этот диапазон не может быть точно представлен (в обычной разработке id данных обычно представляется строкой).Чтобы отличить его от типа Number, к данным типа BigInt необходимо добавлять суффикс n.1234обычное целое число,1234nдляBigInt. Узнать больше можно посмотреть«Вводный курс по ES6»

typeof nullзачем возвращаться'object', что будет объяснено позже из основного механизма хранения данных JavaScript.

Другая ситуация

function foo() {};
typeof foo; // 'function'

В этом случае,functionСлишкомJavaScriptодин из内置类型. Однако, глядя на спецификацию, оказывается, что на самом делеobject«Подтип» . В частности, функция — это «вызываемый объект», который имеет внутреннее свойство[[call]], что делает его вызываемым.typeofМожет использоваться для отличия функций от других объектов.

но использоватьtypeofНевозможно определить, к какому типу относится объект. всеtypeofОбъекты, возвращаемое значение которых равно "object" (такие как массивы, обычные числа и т. д.), содержат внутреннее свойство[[class]](Мы можем рассматривать это как внутреннюю классификацию). Это свойство не может быть напрямую доступно для общегоObject.prototype.toString(...)проверить.

Object.prototype.toString.call(new Date); // "[object Date]"
Object.prototype.toString.call([]); // "[object Array]"
Object.prototype.toString.call(/reg/ig); // "[object RegExp]"

instanceofОператоры также часто используются для определения типов объектов. Использование: Операнд слева являетсяobject, правый операнд — это имя класса объекта или конструктора; returntrueилиfalse.

[] instanceof Array; // true
[] instanceof Object; // true
[] instanceof RegExp; // false
new Date instanceof Date; // true

instanceofВнутренний механизм: обнаружение конструктораprototypeСвойство появляется в цепочке прототипов экземпляра объекта. Следующее описание объяснит эту часть.

тип принципа

typeofпринцип:Различные объекты представлены как двоичные внизу, а первые (младшие) три бита двоичного кода в Javascript хранят информацию об их типе..

  • 000: Объект
  • 010: число с плавающей запятой
  • 100: Строка
  • 110: логическое значение
  • 1: целое число

typeof null - это "объект", причина в том, что разные объекты представлены как двоичные внизу. В Javascript, если первые (младшие) три бита двоичного кода равны 0, он будет оцениваться как тип объекта, а двоичный представление null равно 0, естественно. Первые три бита также равны 0, поэтому выполнение typeof вернет «object». В качестве неуместного примера, предполагая, что все объекты Javascript являются 16-битными, то есть существует 16 последовательностей 0 или 1, предположение выглядит следующим образом:

Array: 1000100010001000
null:  0000000000000000

typeof []  // "object"
typeof null // "object"

Потому что первые три цифры Array и null равны 000. Почему первые три бита массива не равны 100? Потому что «передний» в двоичном формате обычно представляет младший порядок, например, двоичный 00000011 соответствует 3 в десятичном, а его первые три бита равны 011.

instanceof

Чтобы в корне понять, нам нужно начать с двух аспектов:

  • Как этот оператор определен в спецификации языка
  • Механизм прототипного наследования JavaScript

С точки зрения непрофессионала,instanceofИспользуется для сравнения, является ли объект экземпляром конструктора. Обратите внимание, что оператор instanceof можно использовать только для объектов, а не для значений примитивных типов.

  1. судить实例Принадлежит ли это某种类型
function Foo() {};
Foo.prototype.message = ...;
const a = new Foo();
  1. Также возможно определить, является ли экземпляр экземпляром своего супертипа или типа-предка.
function Car(make, model, year) {
  this.make = make;
  this.model = model;
  this.year = year;
}
const auto = new Car('Honda', 'Accord', 1998);

console.log(auto instanceof Car);
// expected output: true

console.log(auto instanceof Object);
// expected output: true

Цепочка прототипов JavaScript

понять архетип

Каждая функция, которую мы создаем, имеет[prototype]) свойство, которое является указателем на объект, назначение которого состоит в том, чтобы содержать свойства и методы, которые могут совместно использоваться всеми экземплярами определенного типа. тогда прототип должен вызвать构造函数объект, созданный实例из的原型对象. Преимущество использования объекта-прототипа заключается в том, что все экземпляры объекта могут совместно использовать содержащиеся в нем свойства и методы.

function Person() {};
Person.prototype.name = 'kangkang';
Person.prototype.sayName = function() {
    console.log(this.name);
}

const person1 = new Person();
person1.sayName(); // 'kangkang'

const person2 = new Person();
person2.sayName(); // 'kangkang'

console.log(person1.sayName === person2.sayName);
// true

Отношение конструктора, прототипа и экземпляра

  • каждый构造函数Имеется原型对象
  • 原型对象содержит указатель на构造函数из指针
  • а также实例содержит указатель на原型对象из指针

Тогда, если мы позволим原型对象равный另一个类型из实例, какой будет результат? Очевидно, в это время原型对象будет содержать указатель на另一个原型из指针, Соответственно,另一个原型также содержит указатель на另一个构造函数из指针. если另一个原型Опять таки另一个类型из实例, то указанная выше связь все еще устанавливается, и такой прогрессивный слой представляет собой цепочку экземпляров и прототипов. Это основная концепция так называемой цепочки прототипов.

Вышеприведенный абзац немного сбивает с толку, если вы не поняли, то можете остановиться здесь и прочитать три статьи, а затем совместить собственно сцены в процессе написания кода и его использования.

[[prototype]]механизм

[[prototype]]Механизм заключается в том, что существует внутренняя ссылка с объектом, которая ссылается на другие объекты. Обычно эта ссылка делает:Если требуемое свойство или ссылка на метод не найдены для объекта, механизм продолжает[[ptototype]]Поиск осуществляется по ассоциированному объекту, аналогично, если в последнем искомая ссылка не найдена, он продолжит поиск своего [[прототипа]], и так далее. Эта цепочка объектов называется «цепочкой прототипов».

Но где же «конец» [[прототипа]]?

Все обычные цепочки [[prototype]] в конечном итоге выполняют встроенныйObject.prototype. Поскольку все «обычные» (встроенные, а не специфичные для хоста расширения) объекты «происходят из» (или устанавливают вершину цепочки [[prototype]] в) этоObject.prototypeобъект, поэтому он содержит много общих функций в JavaScript. Например.toString()а также.valueOf()так далее.

Object.ptototypeявляется вершиной цепочки прототипов js, ее__proto__даnull(имеет свойство __proto__, но значение равно null, поскольку это вершина цепочки прототипов);

Почему он разработан таким образом?

Главное экономить память, если свойства и методы определены на прототипе, то все объекты экземпляра можно расшарить.

__proto__

Большинство (не все) браузеров также поддерживают нестандартный способ доступа к внутренним[[prototype]]Атрибуты.

function Foo() {};
const a = new Foo();

a.__proto__ === Foo.prototype; // true

это странно.__proto__Свойство "волшебным образом" ссылается на внутренний[[prototype]]объект. Если вы хотите искать напрямую (или даже напрямую через .proto.proto... для обхода цепочки прототипов этот метод очень полезен.

а также.construtorТакой же,__proto__на самом деле не существует в объекте, который вы используете (в данном случае этоa). На самом деле, это и другие часто используемые функции (.toString()、.isPrototypeOf(...)и т. д. такие же, как и во встроенномObject.prototypeсередина. (Они неисчислимы;

также,.__proto__очень похоже на недвижимость, но на самом деле это больше похоже наgetter/setter..__proto__Реализация примерно такая

Object.defineProperty(Object.prototype, "__proto__", {
    get: function() {
        return Object.getPrototypeOf(this);
    },
    // ES6中的Object.setPrototypeOf
    set: function(o) {
        Object.setPrototypeOf(this, o);
        return o;
    }
})

Итак, доступ (получение значения)a.__proto__когда на самом деле звонюa.__proto__()(调用getter函数). несмотря на то чтоgetterфункция существует вObject.prototypeобъект, но это относится к объектуa, так иobject.getPrototypeOf(a)Тот же результат.

.__proto__Является устанавливаемым свойством, в предыдущем коде используется ES6.Object.setPrototypeOf(...)Задавать. Однако в целом вам не нужно изменять объект.[[prototype]].

Сеть прототипов

JavaScript原型链

    1. function FooЭто метод, такой как встроенный массив, строка или пользовательский метод.
    1. function Objectто естьObject
    1. function Functionто естьFunction
    1. Вышеупомянутые три на самом деле являются функциями, поэтому их__proto__обеFunction.prototype
    1. запомнитьString, Array, Number,Object, FunctionНа самом деле это функции
function Foo() {};

console.log(Object instanceof Object); // true
console.log(Function instanceof Function); // true
console.log(Function instanceof Object); // true

console.log(Foo instanceof Foo); // false
console.log(Foo instanceof Object); // true
console.log(Foo instanceof Function); // true

Вы можете вывести на консоль, вы можете визуально увидеть вывод каждого шага и объединить спецификацию instanceof с цепочкой прототипов js, чтобы углубить свое понимание.

оглядыватьсяinstanceof.

instanceofсинтаксис:

object instanceof constructor
// 等同于
constructor.prototype.isPrototypeOf(object)
  • объект: объект для обнаружения
  • конструктор: конструктор

instanceofреализация кода.

function instanceof(L, R) { //L是表达式左边,R是表达式右边
    const O = R.prototype;
    L = L.__proto__;
    while(true) {
        if (L === null)
            return false;
        if (L === O) // 这里重点:当 L 严格等于 0 时,返回 true 
            return true;
        L = L.__proto__;
    }
}

instanceofПринцип: обнаружениеconstructor.prototypeСуществует ли он в цепочке прототипов объекта параметра.instanceofВ процессе поиска он будет проходитьobjectцепочка прототипов, пока не найдетconstructorизprototype, если поиск не удался, он вернетfalse,скажи нам,objectнетconstructorпример.

Эту часть цепочки прототипов очень сложно понять, я в основном забываю ее после прочтения в течение нескольких дней, поэтому мне приходится перечитывать ее несколько раз, чтобы понять, и потратить некоторое время, чтобы понять и понять эту часть. Посмотрев на связанные вещи, это очень просто и легко понять. Эта часть является ядром JavaScript. Потребовалось несколько дней, чтобы перечитать и разобраться, в дальнейшем будет намного проще разбираться во многих проблемах. Если вы обнаружите, что какая-либо часть моего утверждения выше неверна, не забудьте указать мне на это и поучиться друг у друга. Рекомендуется обратить внимание на эту часть《JavaScript高级程序设计(第3版)》第六章эта часть《你不知道的JavaScript(上卷)》第五章Пояснение к этой части.

Symbol.hasInstance

объектSymbol.hasInstanceСвойство, указывающее на внутренний метод. когда другие объекты используютinstanceofоператор, этот метод вызывается при оценке того, является ли он экземпляром объекта. Например,foo instanceof FooВнутри языка фактический вызовFoo[Symbol.hasInstance](foo).

class MyClass {
  [Symbol.hasInstance](foo) {
    return foo instanceof Array;
  }
}

[1, 2, 3] instanceof new MyClass() // true

Суммировать

Прочитав его, вы можете связать в уме вышеизложенное; посмотрите, сможете ли вы сразу же придумать следующие вопросы.

  • JavaScriptКакие существуют типы данных, какие операции используются для определения типа данных, каково возвращаемое значение и каков принцип?
  • typeof nullЗачем”object“
  • что原型,где это[[prototype]]"Конец", почему так задумано
  • JavaScriptЧто является ядром цепочки прототипов
  • instanceofкаков принцип
  • Symbol.hasInstanceчто еще (или реализовать самостоятельноinstanceof)

разное

Недавно был запущен 100-дневный расширенный план, в основном для того, чтобы углубиться в принципы, лежащие в основе каждой точки знаний. Добро пожаловать в общедоступный аккаунт WeChat «Звезда Мусимы». Давайте учиться вместе и пробиться в течение 100 дней.

牧码的星星