likes
comments
collection
share

面试篇小结一,数据类型、类型判断里的细节

作者站长头像
站长
· 阅读数 31

类型

  • 原始类型 (存储在栈中)
    • string
    • number
      • 浮点数也是number的一种类型
    • boolean
    • null
    • undefined
    • Symbol
    • bigInt(132456n)
  • 引用类型(存储在堆中)
let a = 1 // new Number(1)
a.b = 2 // new Number(1).b = 2
console.log(a.b); // delete new Number(1).b  undeifned

问1:

  1. 会报错吗? 不会,隐式转换
  2. 打印什么? undefined,原始类型,delete掉属性了

问2:

0.1 + 0.2 === 0.3 // false

打印结果? 答:false,在 JavaScript 中,出现这种情况是因为浮点数在计算机中的表示存在精度限制。0.1 和 0.2 在二进制表示中是无限循环的小数,当进行计算并转换回十进制时,就会产生微小的误差,导致结果与预期的 0.3 不完全相等

问3:

引用类型数据为什么存放在堆里?答:

  • 大小不固定:引用类型的数据,如对象、数组等,其大小可能会动态变化。堆内存可以提供更灵活的空间分配方式,适应引用类型数据的大小变化。
  • 共享和传递:将引用类型数据存放在堆中,可以通过引用(指针)来共享和传递数据。多个变量可以指向同一个堆内存中的对象,从而实现数据的共享和高效传递。
  • 内存管理:堆内存的管理由 JavaScript 引擎负责,它可以自动进行垃圾回收,释放不再使用的对象所占用的内存。这样可以减轻程序员手动管理内存的负担。
let a = {
    n: 1
}
let b = a;
b.n = 2;
console.log(a.n); // 2

问4:打印结果? 答:2,a,b引用地址相同。


const a = []
a = []
console.log(a);

问5:行得通吗? 答:行不通,const常数,a=[],new了一个新数组,更改了地址,报错。

function test(person) {
    person.age = 26; p1.age=26
    person = {
        name: 'tom', 
        age: 30
    }
}

const p1 = {
    name: 'john',
    age: 25
}
const p2 = test(p1);
console.log(p1); 

问6 p1长什么样 答:{ name: 'john', age: 26 }

类型判断

  1. typeof
  2. instanceof
  3. Object.prototype.toString.call()

问7 手写instanceof

instanceof:

  1. 只能用来判断引用数据类型
  2. 通过原型链查找来判断类型
/**
 * 自定义的instanceof检查函数。
 * @param {Object} L - 左侧对象,需要检查是否是右侧构造函数的实例。
 * @param {Function} R - 右侧构造函数,用来检查左侧对象是否是其实例。
 * @returns {boolean} 如果L是R的实例,则返回true;否则返回false。
 */
function myinstanceof(L, R) {
   // 当L不为null时,继续检查
   while (L !== null) {
        // 如果L的__proto__等于R的prototype,则说明L是R的实例
        if (L.__proto__ === R.prototype) {
            return true;
        }
        // 将L更新为其原型,继续向上遍历原型链
        L = L.__proto__;
    }
    // 如果遍历完原型链仍未找到匹配的prototype,则L不是R的实例
    return false;
}

// 测试代码
console.log(myinstanceof([], Array));  // true
console.log(myinstanceof([], Object));  // true
console.log(myinstanceof({}, Array));  // false

问8 toString()

js中每一种类型都有自己的toString函数,这些toString可以分成3类

  1. 对象上的toString:返回一个'[Object xxxx]'结构的字符串
  2. 数组上的toString:返回数组内元素以逗号拼接得到的字符串
  3. 其他:返回字符串字面量
  • 对象上的toString
    • toString(x),v8会读取到x的内部属性[[class]],这个属性记录的就是x的所属的构造函数
    • toString最终会返回由'[object' + 'class' + ']'拼接而成的字符串
    • 因此想要判断类型,可以直接用到对象的toString方法,Object.prototype.toString()
    • 那么基础数据类型怎么办?Object.prototype.toString.call()
    • 由此,就要谈一谈call是什么了,显示绑定-->谈谈其他的默认绑定?隐式绑定?

问9 call的实现原理

let obj = {
    a:1
}
function foo(){

}

Function.prototype.call2 = function(context){
    context.fn = this;
    context.fn();
}
foo.call2(obj); // 隐式绑定call里的this指向foo
                // 往obj上挂载一个fn属性,值是foo
                // 执行foo的时候this指向obj(obj.fn())

问10 所以为什么Object.prototype.toString.call(123)能够判断类型?

就像上面的foo,往obj中植入了一份foo,然后赶紧调用掉,这里就相当于植入一份toString(),然后触发了toString,最终就相当于123在触发这个toString(),123触发的是对象原型上的toString()Object.prototype.toString,而不是自己构造函数身上自带的toString,而对象原型上的toString会返回[object xxx],因此就算我们传一个原始数据类型进去,也可以做到数据类型判断。

转载自:https://juejin.cn/post/7384266820465000500
评论
请登录