First of all, let’s recall that in JS, what are the ways we can determine the data type of a JS variable? We all thought of typeof, instanceof and Object. The prototype. ToString. The call () several ways to judge this type, so what is the difference between these?
Common ways to determine js types
typeof
The basic datatype null is identified as ‘object’. The basic datatype null is identified as ‘object’. The basic datatype null is identified as ‘object’. This is an old Bug and I’m not going to talk about it; The other is that functions in complex data types are judged to be ‘function’, indicating that functions can be correctly identified.
Therefore, Typeof is not accurate enough to judge data types, and has certain defects.
typeof 1 // 'number'
typeof '1' // 'string'
typeof undefined // 'undefined'
typeof true // 'boolean'
typeof Symbol() // 'symbol'
typeof null // 'object'
typeof [] // 'object'
typeof {} // 'object'
typeof console // 'object'
typeof console.log // 'function'
Copy the code
instanceof
The instanceof operator is used to detect whether a variable is an instanceof a type of data by looking up the stereotype chain.
As you can see, Instanceof can be used to determine complex data types, returning true/false. It cannot be used to determine primitive data types, but it can determine the wrapper type of primitive data types, which is also a drawback of Instanceof.
1 instanceof Number // false
new Number(1) instanceof Number // true
'1' instanceof String // false
new String('1') instanceof String // true
true instanceof Boolean // false
(Symbol() instanceof Symbol // false
console.log instanceof Function // true
[] instanceof Array // true
{} instanceof Object // true
Copy the code
Object.prototype.toString.call()
Each of the first two methods has its drawbacks, but this method is a killer app that can correctly judge any type.
Each reference type inherits directly or indirectly from the Object type, so they all contain the toString() function. ToString () returns different values for different data types, so the toString() function can be used to determine exactly what type the value is.
Object.prototype.toString.call(1) // "[object Number]"
Object.prototype.toString.call('1') // "[object String]"
Object.prototype.toString.call(true) // "[object Boolean]"
Object.prototype.toString.call(null) // "[object Null]"
Object.prototype.toString.call(undefined) // "[object Undefined]"
Object.prototype.toString.call(Symbol()) // "[object Symbol]"
Object.prototype.toString.call(function(){}) // "[object Function]"
Object.prototype.toString.call([]) //"[object Array]"
Object.prototype.toString({}) // "[object Object]"
Object.prototype.toString.call(/123/g) //"[object RegExp]"
Object.prototype.toString.call(new Date()) //"[object Date]"
Copy the code
With that in mind, let’s take a look at how underscore is implemented
Underscore implementation
So in order, first of all, how do we identify objects? Underscore counts variables of type function and object as objects, excluding null of course.
function isObject(obj) { var type = typeof obj; return type === 'function' || type === 'object' && !! obj; }Copy the code
Determine a NULL
function isNull(obj) {
return obj === null;
}
Copy the code
Judge a undefined
Function isUndefined(obj) {// void 0 = undefined (obj); Return obj === void 0; return obj === void 0; }Copy the code
Judge a Boolean
function isBoolean(obj) {
return obj === true || obj === false || toString.call(obj) === '[object Boolean]';
}
Copy the code
Wrote so many model, whether to one by one to write like this, other type or use typeof, instanceof and special value, of course not, write down the Object. The prototype. ToString. The call () come on stage, The underscore encapsulates a function tagTester as follows
Var toString = Object. The prototype. ToString; Function tagTester(name) {var tag = '[object '+ name + ']'; return function(obj) { return toString.call(obj) === tag; }; }Copy the code
With the above function, there are many other types of functions, and suddenly there are many more functions
var isString = tagTester('String');
var isNumber = tagTester('Number');
var isDate = tagTester('Date');
var isRegExp = tagTester('RegExp');
var isError = tagTester('Error');
var isSymbol = tagTester('Symbol');
var isArrayBuffer = tagTester('ArrayBuffer');
var isFunction = tagTester('Function');
Copy the code
Seen here is wonder, how no judgment of the array, the original isArray was took out alone, so how to determine an array
// If underscore is supported by the browser, var nativeIsArray = array.isarray is preferred in underscore; var isArray = nativeIsArray || tagTester('Array');Copy the code
Judge a Boolean
Var _isNaN = isNaN; var _isNaN = isNaN; var _isNaN = isNaN; var _isNaN = isNaN; var _isNaN = isNaN; }Copy the code
Is this the end of it? Of course not, underscore also does compatibility handling for some type judgments, and those are the ones we’ll take a look at.
var isFunction = tagTester('Function'); // Optimize `isFunction` if appropriate. Work around some `typeof` bugs in old // v8, IE 11 (#1621), Safari 8 (#1929), and PhantomJS (#2236). var nodelist = root.document && root.document.childNodes; Old V8, IE 11 and Safari 8 are compatible with isFunction. Typeof obj == 'function' performs better if Typeof does not have compatibility bugs in that environment // otherwise if (typeof /. = 'function' && typeof Int8Array ! = 'object' && typeof nodelist ! = 'function') { isFunction = function(obj) { return typeof obj == 'function' || false; }; }Copy the code
var isArguments = tagTester('Arguments'); // Define a fallback version of the method in browsers (ahem, IE < 9), Where // there isn't any inspectable "Arguments" type Object. The prototype. ToString. Call method result is [Object Object] / / not we expect [Object the Arguments]. Function () {if (! isArguments(arguments)) { isArguments = function(obj) { return has$1(obj, 'callee'); }; }} ());Copy the code
Is that it? Underscore also implements many type judgments and compatibility processing, which ends here.
Reference: github.com/lessfish/un…