面试(一)之JS数据类型、原型链

172 阅读3分钟

# 摘录于typeof和instanceof原理
# 摘录于instanceof原理

JS数据类型

基本数据类型(7):
null
undefined
boolean
number
string
symbol(符号,ES6中新增):表示独一无二的值
bigint(大整数,ES2020引入):用来解决 JavaScript中数字只能到 53 个二进制位(JavaScript 所有数字都保存成 64 位浮点数,大于这个范围的整数,无法精确表示的问题
引用数据类型(1):
object(对象)

typeof undefined // 'undefined'

typeof null // 'object'
typeof {} // 'object'
typeof [] // 'object'
typeof new Date() // 'object'

typeof Symbol() // 'symbol'

typeof 123n // 'bigint'

function foo() {}
typeof foo // 'function'
ps: function实际上是 `object` 的一个"子类型"

js变量是弱类型
一个变量可以现在被赋值为字符串类型,随后又被赋值为数字类型。
typeof
一个用来检测给定变量的数据类型的操作符

typeof不能判断对象具体是哪种类型,一般通过Object.prototype.toString(...)或instanceof来查看。

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

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

typeof原理
不同的对象在底层都表示为二进制,在Javascript中二进制前(低)三位存储其类型信息。

  • 000: 对象
  • 010: 浮点数
  • 100:字符串
  • 110: 布尔
  • 1: 整数

typeof null 为"object", 原因是因为 不同的对象在底层都表示为二进制,在Javascript中二进制前(低)三位都为0的话会被判断为Object类型,null的二进制表示全为0,自然前三位也是0,所以执行typeof时会返回"object"。 一个不恰当的例子,假设所有的Javascript对象都是16位的,也就是有16个0或1组成的序列,猜想如下:

Array: 1000100010001000
null:  0000000000000000

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

因为Array和null的前三位都是000。为什么Array的前三位不是100?因为二进制中的“前”一般代表低位, 比如二进制00000011对应十进制数是3,它的前三位是011。

instanceof原理
检测构造函数的 prototype 属性是否出现在某个实例对象的原型链上。

或者

查看对象B的prototype指向的对象是否在对象A的[[prototype]]链上。如果在,则返回true,如果不在则返回false。不过有一个特殊的情况,当对象B的prototype为null将会报错(类似于空指针异常)。

function _instanceof(A, B) {
    var O = B.prototype;// 取B的显示原型
    A = A.__proto__;// 取A的隐式原型
    while (true) {
        //Object.prototype.__proto__ === null
        if (A === null)
            return false;
        if (O === A)// 这里重点:当 O 严格等于 A 时,返回 true
            return true;
        A = A.__proto__;
    }
}

注意,instanceof运算符只能用于对象,不适用原始类型的值。 作用:

  1. 判断某个对象是不是另一个对象的实例 或者 用来比较一个对象是否为某一个构造函数的实例;
var Person = function() {};
var student = new Person();
console.log(student instanceof Person);  // true
  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

function Person() {};
function Student() {};
var p = new Person();
Student.prototype=p; //继承原型
var s = new Student();
console.log(s instanceof Student); //true
console.log(s instanceof Person); //true

原型链
     如果在对象上没有找到需要的属性或者方法引用,引擎就会继续在 [[ptototype]]关联的对象上进行查找,同理,如果在后者中也没有找到需要的引用就会继续查找它的[[prototype]],以此类推。这一系列对象的链接被称为“原型链”。

Object.ptototype是js原型链的最顶端,它的__proto__null

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

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

image.png

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