Before reading will look
The topic of this quick essay is basic data types and type detection.
Before reading this article, in order to save you time, you can first through the following introduction to understand the mouse interview quick questions series, if you feel that the series is not suitable for you or what is wrong, welcome to leave me a message.
Ratty’s interview quiz series is a series specifically aimed at various interview essays.
Want to do the original intention of this series, is that the mouse son himself is also a 22 session of fresh students, but also understand that many students around in the interview will be not clear on some knowledge points or simply read the full text recitation. In order to help consolidate his knowledge, and to help the students who are looking for jobs to do a little help, the rat decided to use his own understanding to chew the test points to everyone.
Who is this collection for?
- Those of you who are still at school, because ratty is also a student, you may use the words to get closer to your classmates.
- The seniors who have graduated but are looking for a job have limited abilities. I hope a little understanding can help the seniors to deepen their impression.
- Just want to be a memo of the bosses (if any), thank you for your love.
Finally, because the rat son ability is limited, many places may be controversial, hope you can put forward in time!
Q1: Talk about basic data types
Subject analysis
First, how many basic data types are there? Five? Seven!
The five most common basic data types are string, number, Boolean, undefined, and NULL
And the new symbol after ES6
ES10 draft proposed BigInt
But this question is usually just a primer, so it’s OK to answer that much, but to prevent the interviewer from digging too deep, let’s take a closer look at each of the basic data types.
Deepen the understanding
This section focuses on symbol and BigInt, and the remaining five will be covered in Q2.
Symbol introduces and generates issues
Here is a description of MDN
Symbol is a primitive data type. The Symbol() function returns a value of type Symbol, which has static properties and static methods. Its static properties expose several built-in member objects; Its static method exposes the global symbol registry and is similar to the built-in object class, but it is incomplete as a constructor because it does not support the syntax “new Symbol()”. Each Symbol value returned from Symbol() is unique. A symbol value can be used as an identifier for an object property. This is the only purpose of this data type. For further parsing, see Glossary Entry for Symbol.
We can use symbol as an object’s property name to avoid overwriting the object’s property, since each call to symbol () yields a unique value that is not repeated.
In addition, Symbol provides two functions, symbol.for (key) and symbol.keyfor (SYM), for registration and retrieval in the global Symbol registry, respectively.
Let’s do some simple code examples:
var sym1 = Symbol(a);var sym2 = Symbol('foo');
var sym3 = Symbol('foo');
console.log(sym1 === sym2); // false
console.log(sym2 === sym3); // false Has different values even if the input parameters are the same
var sym4 = Symbol.for('foo'); // Register in the global registry with key value foo
var sym5 = Symbol.for('foo'); // Repeat registration
console.log(sym2 === sym4); // false The values of each parameter are not equal
console.log(sym4 === sym5); // Duplicate registration returns the registered value
// Retrieve the key from the global registry according to symbol
var key2 = Symbol.keyFor(sym2)
var key5 = Symbol.keyFor(sym5);
console.log(key2); // undefined
console.log(key5); // foo
Copy the code
Derived question: What is the use of symbol?
-
Used as a constant
const CASE_1 = Symbol(a);const CASE_2 = Symbol(a);let type = CASE_1; switch( type) { case CASE_1: break case CASE_2: break default:}Copy the code
The good thing is, you’re guaranteed to never contaminate any of the other constants.
-
Used as an object property name
const FUNC = Symbol(a)let obj = { [FUNC]:function(){}}Copy the code
The advantage is that you can prevent the original object properties from being overwritten.
But it’s worth a topic is, named after the symbol attributes only through Object. GetOwnPropertySymbols () and Reflect ownKeys () to get to.
-
Used as a private property/method of the class
// In the file a.js const PASSWORD = Symbol(a)class Login { constructor(username, password) { this.username = username this[PASSWORD] = password } checkPassword(pwd) { return this[PASSWORD] === pwd } } export default Login Copy the code
// In the file b.js import Login from './a' const login = new Login('admin'.'123456') login.checkPassword('123456') // true login.PASSWORD // Cannot be accessed login[PASSWORD] // Cannot be accessed login["PASSWORD"] // Cannot be accessed Copy the code
-
In particular, in the case of window nesting (such as iframe), it can be used to share passed values
/ / outer let gs1 = Symbol.for('global_symbol_1') // Register a global Symbol / / in the iframe let gs2 = Symbol.for('global_symbol_1') // Get the global Symbol gs1 === gs2 // true Copy the code
BigInt
BigInt is designed to support a larger range of integer values than the Number data type supports
Because BigInt is only a draft of ES10, many environments do not support it, so the following questions will not be considered, you can understand as the forefront.
Q2: Talk about using typeof to do type detection
Subject analysis
This problem is not many pits, directly on the code snippet to see the results.
var num = 1;
var str = '1';
var bool = true;
var a = undefined;
var b = null;
var symbol = Symbol(a);console.log(typeof(num)); //"number"
console.log(typeof(str)); //"string"
console.log(typeof(bool)); //"boolean"
console.log(typeof(a)); //"undefined"
console.log(typeof(b)); //"object"
console.log(typeof(symbol));//"symbol"
Copy the code
The only less intuitive thing here is null, which returns ** “object” **. In this regard, MDN is interpreted as
// This has been the case since JavaScript was invented typeof null= = ='object'; Copy the code
In the original implementation of JavaScript, values in JavaScript were represented by a tag representing the type and the actual data value. The type tag of the object is 0. Since null represents a null pointer (0x00 on most platforms), the type tag of null is 0, and typeof NULL therefore returns “object”. (Source) There was a proposed fix to ECMAScript (via opt-in), but it was rejected. This proposal results in Typeof NULL === ‘null’.
Deepen the understanding
This is just a personal understanding. For the sake of memory, I think of null semantically as representing an empty object, so typeof null===’object’ is an easy thing to understand.
Q3: How do I detect reference types
Subject analysis
Generally Q1~Q3 is the three questions are thrown out together, reference type of course refers to the stack memory with a pointer to the object stored in the heap memory (of course, js does not explicitly use the concept of pointer, generally mentioned similar concepts will use reference that reference).
Everything originates from Object (unless you use object.create (null) to create an Object whose prototype is null).
For reference types, the most common method is to use instanceof. To determine the prototype chain, the left side is usually the instance object, and the right side is usually the constructor. If the prototype of the constructor is on the prototype chain of the instance object, then return true.
In addition, we can also use the Object. The prototype, the toString (), this function can also be detected many built-in objects, of course, we need to use the call to explicitly bound this point.
// Built-in Date object
console.log(new Date instanceof Date); // true
console.log(new Date instanceof Object); // true
console.log(Object.prototype.toString.call(new Date));//"[object Date]"
// Built-in Function object
console.log(new Function instanceof Function); // true
console.log(new Function instanceof Object); // true
console.log(Object.prototype.toString.call(new Function));//"[object Function]"
// Built-in Array objects
console.log([] instanceof Array); // true
console.log([] instanceof Object); // true
console.log(Object.prototype.toString.call([]));//"[object Array]"
// Normal Object
console.log({} instanceof Object); // true
console.log(Object.prototype.toString.call({}));//"[object Object]"
Copy the code
Deepen the understanding
In particular, there are two special objects we need to look at when we do type checking: function. prototype (); array. prototype ();
What makes function.prototype special is that it can be checked with typeof.
console.log(typeof function(){});// "function"
Copy the code
Array.prototype also uses array.isarray (), which we’ll talk about in detail in the next section.
console.log(Array.isArray([]));// true
Copy the code
The vernacular summary version
For reference types, we most commonly used instanceof test, it is a kind of detection method based on the prototype chain, at the same time, we can also use the Object. The prototype. The toString () function to detect, some special objects such as function, it can use typeof to determine, Return function. For arrays, I prefer to use array.isarray (). (See meal 2 below for specific reasons)
Extra meal 1: Instanceof implementation
How to implement Instanceof is one of the most popular questions in the interview, and its implementation is very simple. Let’s recall the description of Instanceof in MDN to find the idea.
The instanceof operator detects whether the constructor’s prototype property is present on the prototype chain of an instance object.
The idea is clear, just follow the prototype chain, and let’s do it iteratively (recursively, of course).
function myInstanceof(object,constructor) {
const prototype = constructor.prototype;
let proto = object.__proto__;
while(true) {
if(proto === null) return false;
if(proto === prototype) return true; proto = proto.__proto__; }}Copy the code
Extra meal 2: detection array of various methods and pros and cons
There are three ways to detect an array, and I’ll list all three below.
console.log([] instanceof Array); //true
console.log(Object.prototype.toString.call([])); // "[object Array]"
console.log(Array.isArray([])); //true
Copy the code
To conclude, the best practice is array.isarray (), but do you know the pitfalls of the first two methods?
Instanceof detects Array pits
If a page is nested with an iframe (array instanceof array), it returns false. If a page is nested with an iframe (array instanceof array), it returns false. Not surprisingly, comparing the parent window with the array prototype object of the iframe shows that although they have the same “content”, they are in different memory Spaces, so they are not exactly equal. So this Array is not that Array.
The other pit, which is less mentioned and which I stumbled upon, is not strictly a pit either. The behavior of instanceof can be overwritten.
**Symbol. HasInstance ** Is used to determine whether an object is an instance of a constructor. So you can use it to customize the behavior of the instanceof operator on a class.
Let’s take a look at the example provided on MDN
class Array1 {
static [Symbol.hasInstance](instance) {
return Array.isArray(instance); }}console.log([] instanceof Array1);
// expected output: true
Copy the code
As a static method, we can override the behavior of Symbol. HasInstance so that our Array1 class behaves like an array in the face of Instanceof checks, even though it has no corresponding array prototype object on its prototype chain.
Let’s see if we can override the Symbol. HasInstance rule to trick instanceof.
console.log(Array[Symbol.hasInstance]([])); //true
Array[Symbol.hasInstance] = function(){return false} // What happens when you force a change
console.log(Array[Symbol.hasInstance]([])); // The true change did not succeed
Copy the code
Although we can’t modify the behavior of the Array directly, we can fake an object ourselves to trick Instanceof, so I’ll just put it down as a pit so you can get a sense of it.
Object. The prototype. ToString pit
The pit is very simple to explain, if only because it is at risk of being rewritten.
console.log(Object.prototype.toString.call([])); // "[object Array]"
Object.prototype.toString = function() {return "Rewrite"};
console.log(Object.prototype.toString.call([])); // "rewrite"
Copy the code
Adds 3: when the Object. The prototype. The toString basic data types
Let’s take a look at the following example
console.log(Object.prototype.toString.call(null)); //"[object Null]"
console.log(Object.prototype.toString.call(undefined)); //"[object Undefined]"
console.log(Object.prototype.toString.call(1)); //"[object Number]"
console.log(Object.prototype.toString.call("str")); //"[object String]"
console.log(Object.prototype.toString.call(true)); //"[object Boolean]"
console.log(Object.prototype.toString.call(Symbol()));//"[object Symbol]"
Copy the code
We find that it seems to work better than Typeof, right? It can even handle null that Typeof can’t detect? Before you jump to conclusions, let’s take another example.
console.log(Object.prototype.toString.call(new Number)); //"[object Number]"
console.log(Object.prototype.toString.call(new String)); //"[object String]"
console.log(Object.prototype.toString.call(new Boolean)); //"[object Boolean]"
Copy the code
For number, string and Boolean, we rely on the Object. The prototype. The toString is unable to distinguish them with number, string, Boolean difference between objects.
If you want to learn more about the Object. The prototype. ToString implementation mechanism, recommend reading the following article, in this paper, it is no longer a lot here.
“Data types” chat & JavaScript data type Object. The prototype. ToString
Meal 4: a reference scheme for a solution type of detection
Next, I will give a reference scheme for a more general solution type detection. This scheme refers to type.js, a method library written by Yan Haijing for determining data types. For the sake of simplicity, I’ve removed some of the compatibility code, so you can focus on some of the points covered in this article
function type(x) {
// 1. When using typeof detection, the special case is null first
if(x === null) {
return 'null';
}
const t = typeof x;
if(t ! = ='object') {return t;
}
/ / 2. The use of the Object. The prototype. ToString detection, capture part of the character
const cls = Object.prototype.toString.call(x).slice(8, -1);
const clsLow = cls.toLowerCase();
if(clsLow ! = ='object') {// Distinguish between the Number Boolean String object and the Number Boolean String basic data type
// Capitalize the former and lower case the latter
if (clsLow === 'number' || clsLow === 'boolean' || clsLow === 'string') {
return cls;
}
return clsLow;
}
// 3. Return 'Object' if the constructor of the Object is Object
if(x.constructor === Object) {
return clsLow;
}
// 4. Handle the case where object.create (null) creates an Object with no prototype
if (x.__proto__ === null) {
return 'object'
}
// 5. Handle other non-built-in objects
const cname = x.constructor.name;
if (typeof cname === 'string') {
return cname;
}
// 6. Unknown object type
return 'unknown';
}
Copy the code
Test the
console.log(type(1)); //number
console.log(type(new Number)); //Number
console.log(type({})); //Object
console.log(Object.create(null)); //object
function Person(){}
console.log(type(new Person)); //Person
Copy the code
Write in the last
So far, the mouse thought that the knowledge points related to basic data types and type detection had been listed in detail. If there is any omission, please bring it up. This article will be updated and supplemented for a long time. Welcome to like and collect.