В JavaScript мы обычно используемtypeofСудя по типу, но при оценке значения ссылочного типа часто возникает проблема: независимо от того, на какой тип объекта ссылаются, будет возвращен «объект» (и, конечно, «функция»). Иногда нам нужно знать, является ли тип ссылочного объекта массивом или объектом-оболочкой, на этот разinstanceofВот где это пригодится.
Не много чепухи, давайте разогреемся на нескольких примерах. Если вы знаете всех учеников, пожалуйста, нажмите кнопку закрытия в правом верхнем углу, учащиеся, которые неясны, могут продолжить чтение. Пока вы осваиваете принципы, эти темы действительно легко.
const a = 'abc';
console.log(a instanceof String); // ?
const b = new String('abc');
console.log(b instanceof String); // ?
console.log(String instanceof String); // ?
console.log(Object instanceof Object); // ?
console.log(Function instanceof Function); // ?
console.log(Function instanceof Object); // ?
1. Как работает instanceof
Вот как это описано на MDNinstanceofиз:
instanceofоператор по тестированию конструкторовprototypeПоявляется ли свойство где-либо в цепочке прототипов объекта
Другими словами, еслиA instanceof B,ТакAдолжен быть объектом, иBДолжна быть допустимой функцией JavaScript. При выполнении обоих условий:
Определите, находится ли объект-прототип (B.prototype), на который указывает свойство прототипа объекта B, в цепочке прототипов объекта A.
истина, если присутствует; ложь, если отсутствует.
Давайте рассмотрим пример, чтобы проиллюстрировать шаг за шагом:
function Person() {}
const p1 = new Person();
p1 instanceof Person; // true
Шаг 1: Каждый конструктор имеетprototypeАтрибуты.
Шаг 2: Этоprototypeсвойство указывает на объект-прототип этого конструктора
Шаг 3: пройтиnewключевое слово, вы можете создать экземпляр конструктора (здесь p1), и этот экземпляр имеет__proto__Атрибуты
Шаг 4: На экземпляре__proto__Свойство также указывает на объект-прототип конструктора, так что мы можем получить полную диаграмму отношения
пятый шаг:p1 instanceof Person, отметьте B(лицо) изprototypeОбъект-прототип, на который указывает свойство, находится в цепочке прототипов объекта A(p1).
После нашей пошаговой декомпозиции мы обнаружили, что B(Person)'sprototypeОбъект-прототип, на который указывает указатель, действительно находится в цепочке прототипов A(p1), поэтому мы можем быть уверены.p1 instanceof Personдолжно быть дляtrueиз.
Если мы копнем немного глубже, то обнаружим, что не толькоp1 instanceof Personдляtrue,p1 instanceof Objectтакже дляtrue,что насчет этого?
фактически,PersonОбъект-прототип также имеет__proto__свойство, и это свойство указывает наObjectизprototypeОбъект-прототип, на который указывает свойство, мы можем вывести его на консоль:
Поскольку эта связь существует, давайте улучшим приведенную выше картинку:
пройти черезPersonПример, мы знаем конструкторObjectВверхprototypeСвойство будет указывать на свой объект-прототип:
Теперь мы должны судитьp1 instanceof ObjectПравда или ложь, помните определение выше? Давай сделаем это снова:
Определите, находится ли объект-прототип (B.prototype), на который указывает свойство прототипа объекта B, в цепочке прототипов объекта A.
истина, если присутствует; ложь, если отсутствует.
В этот момент мы обнаруживаем, что B(Object)'sprototypeОбъект-прототип, на который указывает свойство, все еще находится в цепочке прототипов A(p1), поэтому результатtrue.
Из приведенного выше примера мы можем знать, что на самом делеinstanceofПринцип очень прост, это процесс поиска цепочки прототипов, поэтому, если вы понимаете соответствующие знания цепочки прототипов, поймитеinstanceofПринцип больше не будет проблемой. Здесь мы кратко суммируем два момента иinstanceofЗнание цепочки прототипов:
- Все объекты JavaScript имеют
__proto__свойства, толькоObject.prototype.__proto__ === null; - конструктор
prototypeСвойство указывает на свой объект-прототип, в то время как экземпляр конструктора__proto__свойства также указывают на объект-прототип;
2. Как реализовать instanceof?
Прочитав описанный выше процесс, на самом деле очень легко датьinstanceofреализация:
function instance_of(left, right) {
const RP = right.prototype; // 构造函数的原型
while(true) {
if (left === null) {
return false;
}
if (left === RP) { // 一定要严格比较
return true;
}
left = left.__proto__; // 沿着原型链重新赋值
}
}
С помощью приведенного выше метода реализации давайте объясним приведенный выше пример:
function Person() {}
const p1 = new Person();
p1 instanceof Object; // 用上面的代码解释它
первое задание
left = p1
right = Object
RP = Object.prototype
первое судебное решение
left !== nullа такжеleft !== RP, продолжай искатьleftЦепочка прототипов готова к новым заданиям.
Второе назначение
left = p1.__proto__ = Person.prototype
второе решение
left !== nullа такжеleft !== RP, продолжай искатьleftЦепочка прототипов готова к новым заданиям.
третье задание
left = p1.__proto__.__proto__ = Person.prototype.__proto__
третье задание
left !== null,В настоящее времяleft === RP,вернутьtrue, функция выполняется.
3. Резюме
Сегодня мы используем пример для анализа двух точек зрения с помощью рисования и кода.instanceofПринцип реализации, собственно, идеи тоже очень прост, это не что иное, как процесс перебора цепочки прототипов. Я надеюсь, что всех больше нельзя подвергать"instanceofКаков принцип реализации? «Такие интервью даются тяжело.
Конечно, чтение — это всегда очень пассивный метод обучения, и я все же рекомендую вам практиковать его самостоятельно. В начале статьи есть несколько примеров.Заинтересованные студенты могут выбрать пример и углубить свое понимание с помощью рисования и реализации кода.Я думаю, вы поймете глубже.
Если в статье есть ошибки или неточности, прошу меня поправить.
Наконец, статья будет опубликована первой в моемGithubвверх, добро пожаловать, чтобы следовать.