JavaScript基础

面试题:

  1. JS的数据类型及判断数据类型的方式,为什么基本数据类型存到栈但是引用数据类型存到堆
  2. var、let和const的区别?如何使得const定义的对象的属性也不能被修改?

1、JavaScript有哪些数据类型

JavaScript共有八种数据类型,分别是 Undefined、Null、Boolean、Number、String、Symbol、BigInt、Object。
前 7 种类型为基础类型,最后 1 种(Object)为引用类型。
引用数据类型(Object)有几种常见的类型:Function、Array、RegExp、Date、Math。
![image.png](https://img-blog.csdnimg.cn/img_convert/7c39da9c01456a6f62b9f22aba312a07.png#clientId=u2fcc9ad2-e9ba-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=258&id=u8517a5bf&margin=[object Object]&name=image.png&originHeight=515&originWidth=916&originalType=binary&ratio=1&rotation=0&showTitle=false&size=258810&status=done&style=none&taskId=u3d09fde2-9279-4db9-8814-7964a753098&title=&width=458)

2、Symbol

https://es6.ruanyifeng.com/#docs/symbol
Symbol 代表创建后独一无二且不可变的数据类型,它主要是为了解决可能出现的全局变量冲突的问题。

Symbol 值作为属性名,遍历对象的时候,该属性不会出现在for…in、for…of循环中,也不会被Object.keys()、Object.getOwnPropertyNames()、JSON.stringify()返回。

  • Object.getOwnPropertySymbols(obj) 方法,可以获取指定对象的所有 Symbol 属性名。
  • Reflect.ownKeys(obj) 方法可以返回所有类型的键名,包括常规键名和 Symbol 键名。

Symbol.for() 接受一个字符串作为参数,然后搜索有没有以该参数作为名称的 Symbol 值。如果有,就返回这个 Symbol 值,否则就新建一个以该字符串为名称的 Symbol 值,并将其注册到全局。

let s1 = Symbol.for('foo');
let s2 = Symbol.for('foo');
s1 === s2 // true

Symbol.keyFor() 方法返回一个已登记的 Symbol 类型值的key。

let s1 = Symbol.for("foo");
Symbol.keyFor(s1) // "foo"

let s2 = Symbol("foo");
Symbol.keyFor(s2) // undefined

3、BigInt

https://es6.ruanyifeng.com/#docs/number#BigInt-%E6%95%B0%E6%8D%AE%E7%B1%BB%E5%9E%8B
BigInt 是一种数字类型的数据,它可以表示任意精度格式的整数,使用 BigInt 可以安全地存储和操作大整数,即使这个数已经超出了 Number 能够表示的安全整数范围。

4、判断数据类型的方式

1) typeof

typeof 变量名;

可以识别标准类型(Null除外),不能识别具体的对象类型(Function除外)。

typeof undefined // 'undefined'
typeof null      // 'object',不能判断null
typeof true      // 'boolean'
typeof 1         // 'number'
typeof "abc"     // 'string'
typeof Symbol()  // 'symbol'
typeof 1n        // 'bigint'

typeof {}           // 'object'
typeof [1,2]        // 'object',不能识别具体的对象类型
typeof function(){} // 'function',可以识别function

2) instanceof

变量名 instanceof 类型;

判别内置对象类型、自定义对象类型,不能判别标准类型。给定引用类型的实例则返回true,检测基本类型值返回false。

如果该类型在该变量的原型链上,则为true。

function Foo(name) {
    this.name = name
}
var foo = new Foo('bar')
foo instanceof Foo; // true
foo instanceof Object; // true

/\d/ instanceof RegExp; // true
/\d/ instanceof Object; // true

1 instanceof Number; // false

3) Object.prototype.toString.call()

toString() 是 Object 的原型方法。

调用该方法返回格式为 “[object Xxx]” 的字符串,其中 Xxx 就是对象的类型,第一个首字母要大写(注意:使用 typeof 返回的是小写)。

对于 Object 对象,直接调用 toString() 就能返回 [object Object];而对于其他对象,则需要通过 call 来调用,才能返回正确的类型信息。

可以识别标准类型以及内置(build-in)对象类型(函数、数组、Date、正则表达式等),不能识别自定义类型。
![无标题.png](https://img-blog.csdnimg.cn/img_convert/d5c5f5c70aa4e94a9c81403391fce293.png#clientId=u1f2d07c1-5307-4&crop=0&crop=0&crop=1&crop=1&from=drop&id=u39c61a17&margin=[object Object]&name=无标题.png&originHeight=505&originWidth=1266&originalType=binary&ratio=1&rotation=0&showTitle=false&size=50873&status=done&style=none&taskId=u6f21a7b4-4b76-4534-b046-3fcdbf6f3f0&title=)

4) constructor

对象原型的属性,指向构造器本身。识别标准类型(Undefined、Null除外)、内置对象类型、自定义对象类型。

"abc".constructor === String; // true
true.constructor === Boolean; // true
(123).constructor === Number; // true
({}).constructor == Object; // true
[].constructor == Array; // true
new Person("hsg").constructor == Person; // true

5、堆和栈的区别

数据类型分为原始数据类型(前7种)和引用数据类型(对象、数组和函数),两种类型的存储位置不同:

  • 原始数据类型直接存储在栈(stack)中的简单数据段,占据空间小、大小固定,属于被频繁使用数据;
  • 引用数据类型存储在堆(heap)中的对象,占据空间大、大小不固定。引用数据类型在栈中存储了指针,该指针指向堆中该实体的起始地址。

基础类型存储在栈内存,被引用或拷贝时,会创建一个完全相等的变量;引用类型存储在堆内存,存储的是地址,多个引用指向同一个地址,这里会涉及一个“共享”的概念。

JavaScript 引擎需要用栈来维护程序执行期间上下文的状态,如果栈空间大了话,所有的数据都存放在栈空间里面,那么会影响到上下文切换的效率,进而又影响到整个程序的执行效率。
![image.png](https://img-blog.csdnimg.cn/img_convert/1380d8e7654bc6c8a6a4dfb2f8b9fa47.png#clientId=u6968e597-beda-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=231&id=gPvQa&margin=[object Object]&name=image.png&originHeight=462&originWidth=912&originalType=binary&ratio=1&rotation=0&showTitle=false&size=136866&status=done&style=none&taskId=ue523be0b-45a4-42cf-a3e3-1ef14259862&title=&width=456)

6、var、let和const的区别?如何使得const定义的对象的属性也不能被修改?

var:

  • 不存在块级作用域;
  • 存在变量提升,var声明的变量会给全局对象window/global添加属性;
  • 重复声明时,后声明的变量会覆盖之前的变量;
  • 声明时,可以不用设置初始值

var声明的内层变量可能覆盖外层变量,用来计数的循环变量泄露为全局变量,循环时产生的闭包可能会出现怪异行为。

let和const:

  • 具有块级作用域;
  • 不存在变量提升,在声明之前不可以使用,存在暂时性死区;
  • 不可以重复声明;
  • let用来声明变量,const用于声明常量,必须在声明时进行初始化,且不可更改。

const声明的变量是不允许改变指针的指向,但可以改变指针所指对象的属性值。

如何使得const定义的对象的属性也不能被修改?
递归defineProperty?

ES5如何实现let、const?

(function(){
    var a = 1;
    console.log(a); // 1
})()
console.log(a); // Uncaught ReferenceError: a is not defined
function _const(key, value) {
    window[key] = value;
    Object.defineProperty(window, key, {
        enumerable: false, // 能否通过delete删除,能否修改属性特性
        configurable: false, // 能否通过for-in返回属性
        get: function () {
            return value;
        },
        set: function (newValue) {
            if (newValue !== value) {
                throw TypeError("只读变量,不可修改");
            } else {
                return value;
            }
        },
    });
}


_const('a', 10)
console.log(a) // 10
delete a
console.log(a) // 10
for (let item in window) {
    if (item === 'a') { // 不可枚举,所以不执行
        console.log(window[item])
    }
}
a = 20 // Uncaught TypeError: 只读变量,不可修改

7、为什么有的编程规范要求用void 0代替undefined?

Undefined 类型表示未定义,它的类型只有一个值,就是 undefined。任何变量在赋值前是 Undefined 类型、值为 undefined,一般我们可以用全局变量undefined(就是名为undefined的这个变量)来表达这个值,或者 void 运算来把任一一个表达式变成 undefined 值。

但是呢,因为JavaScript的undefined是一个变量,而并非是一个关键字,这是JavaScript语言公认的设计失误之一,所以,我们为了避免无意中被篡改,我建议使用 void 0 来获取undefined值

Undefined跟 null 有一定的表意差别,null表示的是:“定义了但是为空”。所以,在实际编程时,我们一般不会把变量赋值为 undefined,这样可以保证所有值为 undefined 的变量,都是从未赋值的自然状态。

8、0.1 + 0.2不是等于0.3么?为什么JavaScript里不是这样的?

浮点数运算的精度问题导致等式左右的结果并不是严格相等,而是相差了个微小的值。使用JavaScript提供的最小精度值:

Math.abs(0.1 + 0.2 - 0.3) <= Number.EPSILON
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值