предисловие
Недавно я оглядывался назад на основы js, и я просто что-то не понял в суждении о типах данных, или я не понял принципов typeof и instanceof, поэтому я был готов это изучить🤭
Если дело касается прототипов, вы можете прочитать эту статью 🤭
Говоря о прототипах JavaScript
тип данных
Последний стандарт ECMAScript определяет 8 типов данных:
Может быть, все относительно незнакомы с примитивным типом данных BigInt, его предложение решает некоторые проблемы, такие как больше, чем253 - 1
целое число. Первоначально это было доступно в JavascriptNumber
Максимальное число для представления.BigIntМожет представлять произвольно крупные целые числа.
Разобравшись с типом данных, давайте посмотрим, как определить тип данных.
Определить тип данных
typeof
typeofОператор возвращает строку, представляющую тип неоцененного операнда.
Подводя итог возможным возвращаемым значениям:
- "undefined"
- "object"
- "boolean"
- "number"
- "bigint"
- "string"
- "symbol"
- "function"
Дополнительная информация:
typeof null === 'object';
Можно сказать, что это ошибка в дизайне JavaScript. Спецификация MDN объясняет это так:
В исходной реализации JavaScript значение в JavaScript было представлено тегом, представляющим тип и фактическое значение данных. Метка типа объекта равна 0. из-заnull
Представитель — это пустой указатель (большинство платформ — 0x00), поэтому тег типа NULL равен 0,typeof null
также вернуться"object"
.
Когда typeof оценивает данные типа объекта, он не может точно сказать нам, какой это тип Object, а при оценке null он также предоставляет указанную выше дополнительную информацию. Чтобы определить, какой это объект, нам нужно использовать оператор instanceof, о котором мы поговорим позже.
Давайте поговорим о принципе typeof, говоря о котором, мы должны рассмотреть, как JavaScript хранит данные, или, для переменной, каков стандарт взвешивания ее типов данных?
После ознакомления с соответствующей информацией, на самом деле, это ошибка, оставшаяся от истории.В начальной версии javascript использовалась 32-битная система, ради производительности информация о типе переменной хранится в младших битах:
- 000: Объект
- 010: число с плавающей запятой
- 100: Строка
- 110: логическое значение
- 1: целое число
но дляundefined
а такжеnull
Другими словами, хранение информации этих двух значений немного особенное.
null
: Указатель NULL, соответствующий машинному коду, обычно все нули.
undefined
: представлено целыми числами −2^30!
так,typeof
в сужденииnull
Проблема возникает, когдаnull
Все машинные коды равны 0, поэтому они напрямую рассматриваются как объекты.
Так что, кажется, немного разобрался с мехом (●'◡'●)
instanceof
instanceof операторДля обнаружения конструктораprototype
Появляется ли свойство в цепочке прототипов экземпляра объекта.
грамматика
object instanceof constructor
object 某个实例对象
construtor 某个构造函数
// 定义构造函数
function C(){}
function D(){}
var o = new C();
o instanceof C; // true,因为 Object.getPrototypeOf(o) === C.prototype
o instanceof D; // false,因为 D.prototype 不在 o 的原型链上
o instanceof Object; // true,因为 Object.prototype.isPrototypeOf(o) 返回 true
C.prototype instanceof Object // true,同上
C.prototype = {};
var o2 = new C();
o2 instanceof C; // true
o instanceof C; // false,C.prototype 指向了一个空对象,这个空对象不在 o 的原型链上.
D.prototype = new C(); // 继承
var o3 = new D();
o3 instanceof D; // true
o3 instanceof C; // true 因为 C.prototype 现在在 o3 的原型链上
Обратите внимание, что если выражениеobj instanceof Foo
вернутьtrue
, это не означает, что выражение всегда будет возвращатьtrue
,потому чтоFoo.prototype
Значение атрибута может измениться, и измененное значение может не существовать вobj
на цепочке прототипов , то значение исходного выражения становитсяfalse
. В другом случае изменится и значение исходного выражения, то есть изменение объектаobj
В случае с цепочкой прототипов, хотя в текущей спецификации ES мы можем только прочитать прототип объекта и не можем его изменить, с помощью нестандартных__proto__
Достижимы псевдосвойства. такие как выполнениеobj.__proto__ = {}
Позже,obj instanceof Foo
вернусьfalse
.
Принципиальный анализ
Чтобы понять принцип instanceof, нам нужно понять его с двух сторон:
- как операторы определены в спецификации языка
- Механизм прототипного наследования JavaScript
Здесь я напрямую перевожу определение спецификации в код JavaScript следующим образом:
function my_instance_of(leftVaule, rightVaule) {
if(typeof leftVaule !== 'object' || leftVaule === null) return false;
let rightProto = rightVaule.prototype,
leftProto = leftVaule.__proto__;
while (true) {
if (leftProto === null) {
return false;
}
if (leftProto === rightProto) {
return true;
}
leftProto = leftProto.__proto__
}
}
Как видно из приведенного выше кода, основной принцип instanceof таков:
Пока прототип справа и слева может прототип цепь, то есть вернуть истину. Следовательно, InstanceOF во время запроса будет проходить переменную цепи прототипов слева, пока вы не найдете правильные прототипы переменных, если это не удается, он возвращает false, сообщите нам переменную слева, не является переменным переменными.
Далее рассмотрим интересные примеры:
function Foo() {}
console.log(Object instanceof Object)
console.log(Function instanceof Function)
console.log(Function instanceof Object)
console.log(Foo instanceof Object)
console.log(Foo instanceof Function)
console.log(Foo instanceof Foo)
Принцип прототипного наследования в JavaScript
Что касается принципа прототипного наследования, я просто использую картинку, чтобы представить
Эта диаграмма очень важна.Для тех, кто не понимает цепочку прототипов, вы можете прочитать эту статью:
Говоря о прототипах JavaScript
Возьмите пример для анализа интересного экземпляра примера
Object instanceof Object
由图可知,Object 的 prototype 属性是 Object.prototype, 而由于 Object 本身是一个函数,由 Function 所创建,所以 Object.__proto__ 的值是 Function.prototype,而 Function.prototype 的 __proto__ 属性是 Object.prototype,所以我们可以判断出,Object instanceof Object 的结果是 true 。用代码简单的表示一下
leftValue = Object.__proto__ = Function.prototype;
rightValue = Object.prototype;
// 第一次判断
leftValue != rightValue
leftValue = Function.prototype.__proto__ = Object.prototype
// 第二次判断
leftValue === rightValue
// 返回 true
Остальные интересные примеры, такие как Function instanceof Object, можно реализовать вручную 🤭
Object.prototype.toString
Описание в спецификации ES5
Известно, что Object.prototype.toString в конечном итоге вернет строку в форме [объект, класс], а класс относится к обнаруженному типу данных, который является ключом к нашему суждению о типе данных.
var toString=Object.prototype.toString;
console.log(toString.call(und)); // [object Undefined]
console.log(toString.call(nul)); // [object Null]
console.log(toString.call(boo)); // [object Boolean]
console.log(toString.call(num)); // [object Number]
console.log(toString.call(str)); // [object String]
console.log(toString.call(obj)); // [object Object]
console.log(toString.call(arr)); // [object Array]
console.log(toString.call(fun)); // [object Function]
console.log(toString.call(date)); // [object Date]
console.log(toString.call(reg)); // [object RegExp]
console.log(toString.call(err)); // [object Error]
console.log(toString.call(arg)); // [object Arguments]
Окончательный метод определения типа данных
/**
* @desc 数据类型检测
* @param obj 待检测的数据
* @return {String} 类型字符串
*/
let type = (obj) => typeof obj !== 'object' ? typeof obj : Object.prototype.toString.call(obj).slice(8,-1).toLowerCase();
Индивидуальное определение типов данных
/**
* @desc 是否是 Undefined 类型检测
* @param obj 待检测的数据
* @return {Boolean} 布尔值
*/
let isUndefined = obj => obj === void 0
/**
* @desc 是否是 Null 类型检测
* @param obj 待检测的数据
* @return {Boolean} 布尔值
*/
let isNull = obj => obj === Null
/**
* @desc 是否是 Boolean 类型检测
* @param obj 待检测的数据
* @return {Boolean} 布尔值
*/
let isBoolean = obj => typeof(obj) === 'boolean'
/**
* @desc 是否是 Number 类型检测
* @param obj 待检测的数据
* @return {Boolean} 布尔值
*/
let isNumber = obj => typeof(obj) === 'number'
/**
* @desc 是否是 String 类型检测
* @param obj 待检测的数据
* @return {Boolean} 布尔值
*/
let isString = obj => typeof(obj) === 'string'
/**
* @desc 是否是 Object 类型检测
* @param obj 待检测的数据
* @return {Boolean} 布尔值
*/
let isObject = obj => Object.prototype.toString.call(obj) === '[object Object]'
/**
* @desc 是否是 Array 类型检测
* @param obj 待检测的数据
* @return {Boolean} 布尔值
*/
let isArray = obj => Object.prototype.toString.call(obj) === '[object Array]'
/**
* @desc 是否是 Function 类型检测
* @param obj 待检测的数据
* @return {Boolean} 布尔值
*/
let isFunction = obj => typeof obj === 'function'
/**
* @desc 是否是 Date 类型检测
* @param obj 待检测的数据
* @return {Boolean} 布尔值
*/
let isDate = obj => Object.prototype.toString.call(obj) === '[object Date]'
/**
* @desc 是否是 RegExp 类型检测
* @param obj 待检测的数据
* @return {Boolean} 布尔值
*/
let isRegExp = obj => Object.prototype.toString.call(obj) === '[object RegExp]'
/**
* @desc 是否是 Error 类型检测
* @param obj 待检测的数据
* @return {Boolean} 布尔值
*/
let isError = obj => Object.prototype.toString.call(obj) === '[object Error]'
/**
* @desc 是否是 Arguments 类型检测
* @param obj 待检测的数据
* @return {Boolean} 布尔值
*/
let isArguments = obj => Object.prototype.toString.call(obj) === '[object Arguments]'
В заключение
- Можно использовать typeof для оценки базового типа данных.Следует отметить, что проблема, когда typeof оценивает нулевой тип
- При оценке объекта рассмотрите возможность использования instanceof, но когда instanceof оценивает массив, он может быть оценен как объект с помощью instanceof
- Чтобы точно определить тип экземпляра объекта, используйте метод Object.prototype.toString.call().
Ссылаться на
Как движок v8 узнает тип данных js?