(立下flag)每日10道前端面试题-10 关于let const十问

1.下面哪个会报错,为什么

let a;
const a;

答案:

let a; //不报错
const a; //报错

const 声明的常量不得改变值。这意味着, const 一旦声明常量,就必须立即初始化,不 能留到以后赋值

2. 如何在ES5环境下实现let

对于这个问题,我们可以直接查看babel转换前后的结果,看一下在循环中通过let定义的变量是如何解决变量提升的问题

babel在let定义的变量前加了道下划线,避免在块级作用域外访问到该变量,除了对变量名的转换,我们也可以通过自执行函数来模拟块级作用域

3. 如何在ES5环境下实现const

实现const的关键在于Object.defineProperty()这个API,这个API用于在一个对象上增加或修改属性。通过配置属性描述符,可以精确地控制属性行为。Object.defineProperty() 接收三个参数:

Object.defineProperty(obj, prop, desc)

对于const不可修改的特性,我们通过设置writable属性来实现

4.const的本质是什么

const 实际上保证的并不是变量的值不得改动,而是变量指向的那个内存地址不得改动。 对于简单类型的数据(数值、字符串、布尔值〉而言,值就保存在变量指向的内存地址中,因 此等同于常量。但对于复合类型的数据(主要是对象和数组)而言,变量指向的内存地址保存 的只是一个指针, const 只能保证这个指针是固定的,至于它指向的数据结构是不是可变的, 这完全不能控制。 因此,将一个对象声明为常量时必须非常小心。

5既然const不能保证 对象属性不被修改,那该怎么解决这个问题呢?

如果真的想将对象冻结,应该使用 Object.freeze 方法。

查看Object.freeze的用法与描述

Object.freeze()方法可以冻结一个对象。一个被冻结的对象再也不能被修改;冻结了一个对象则不能向这个对象添加新的属性,不能删除已有属性,不能修改该对象已有属性的可枚举性、可配置性、可写性,以及不能修改已有属性的值。此外,冻结一个对象后该对象的原型也不能被修改。freeze() 返回和传入的参数相同的对象。

6但是这样就能保证 对象冻结了吗?

不,因为Object.freeze()只能冻结基本数据类型的属性,若是属性还是引用类型的话,那就冻结不了了,因此,除了将对象本身冻结,对象的属性也应该冻结。下面是一个将对象彻底冻结的函数。

7既然你提到了Object.freeze,你能说下他的原理 吗

Object.freeze()的功能主要就是使对象属性冻结起来,这个功能跟 上面模拟const 类似,可以用Object.definedProperty()

Object.definedProperty()方法可以定义对象的属性的特性。如可不可以删除、可不可以修改、访问这个属性的时候添油加醋等等。。 所以,我们可以这样写:

8 但是这样就完整了没,你有没有发现问题呢?

emmmmm,的确还有个问题,就是Object.definedProperty()只是设置了 对象的属性,也就是说,要是此时我使用 给对象添加属性,还是可以的,因此还有个问题要解决,就是使对象不能 添加新的属性,而要限制 拓展功能,我想到了Object.seal(),

查看Object.seal介绍:

**Object.seal()**方法封闭一个对象,阻止添加新属性并将所有现有属性标记为不可配置。当前属性的值只要原来是可写的就可以改变。

因此用Object.seal()Object.definedProperty()就可以实现Object.freeze()

9 ES6之前真的没有块级作用域吗?

可以看下这道题,答案是什么

 

正确答案:内部是 21,外部是 1;

这个玄妙之处确实就在这个块级作用域 if 里面。

假如我们去掉 if 看题。

这道题估计没人好意思去问了,毫无疑问,输出的 a 都是 21 啊。

实际上,首先,if 里面的 function a(){} 会声明提升,将声明" var a" 移到函数级作用域最前面,将函数定义移到块级作用域最前面,预解析如下:

函数本身是【 定义函数名变量 指针指向 函数内存块】。

函数提升是在块级作用域,但是函数名变量是函数级别的作用域。所以在块级的函数定义(原始代码函数的声明位置)的时候,会将函数名变量同步到函数级作用域,实际上,只有这个时候,在块级作用域外才能访问到函数定义。

预解析如下:

关于此题查看更多

10 下面代码输出情况

 

可见在全局作用域中 var 声明的变量 会被挂载到 window中,而let 不会 而我在读一本关于es6书的时候 看到这一段话

ES6 将全局方法 parse!nt ()和 parseFloat ()移植到了 Number 对象上面,行为完全 >保持不变 这样做的目的是逐步减少全局性方法,使得语言逐步模块化。

是不是let 也想这样呢?当然这只是个人猜想,没什么理论依旧,您也不必往心里去

补充:后来在书里看到这段,好像符合我的猜想

顶层对象的属性与全局变量相关,被认为是 JavaScript 语言中最大的设计败笔之一。这样 的设计带来了几个很大的问题:首先,无法在编译时就提示变量未声明的错误,只有运行时才 能知道(因为全局变量可能是顶层对象的属性创造的,而属性的创造是动态的〉:其次,程序员 很容易不知不觉地就创建全局变量(比如打字出错〉:最后,顶层对象的属性是到处都可以读写 的,这非常不利于模块化编程。另一方面, window 对象有实体含义,指的是浏览器的窗口对 象,这样也是不合适的。

ES6 为了改变这一点, 一方面规定,为了保持兼容性, var 命令和 function 命令声明的 全局变量依旧是顶层对象的属性;另一方面规定, let 命令、 const 命令、 class 命令声明的 全局变量不属于顶层对象的属性。也就是说,从 ES6 开始,全局变量将逐步与顶层对象的属性 隔离。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值