js面试题(自己的总结)

第一道:用递归实现1-100数字的相加

// 用递归实现1-100数字的相加
function add(num1, num2) {
    var num = num1 + num2;
    if (num2 < 100) {
        return add(num, num2 + 1)
    } else {
        return num
    }
}

add(1, 2); // 5050

第二道:Object.defineProperty()   (对象属性定义)

  • 语法:Object.defineProperty(obj, prop, descriptor)
  • 参数一:obj ( 要定义属性的对象 )
  • 参数二:prop ( 要定义或修改的属性的名称或 Symbol )
  • 参数三:descriptor ( 要定义或修改的属性描述符 )

 descriptor分别有以下描述符:(enumerable 、enumerable、value、writable、get、set)具体作用参考MDN描述解释,主要看一下enumerable描述符。

const obj = {
    name: 'chuan',
    message: 'Hello World'
}
Object.defineProperty(obj, 'name', {
    enumerable: false
})
for (let item in obj) {
    console.log(item); // message
}

        为什么上面 item 只打印了 message一个属性名?那其实就是因为我们为obj对象的描述符 enumerable 设置为false的原因,判断一个属性是否可枚举的一个标准是看:对象的这个属性能否被for in循环给遍历出来,当我们设置为false的时候表示不可枚举,那么就不会被for in遍历出来。

        而描述符 get,set就是在vue2中我们经常能够知道的,数据双向绑定的实现,对数据进行劫持。在vue3数据双向绑定原理从Object.defineproperty 变更为了 Proxy 代理。

第三道:Proxy

描述:Proxy 对象用于创建一个对象的代理,从而实现基本操作的拦截和自定义(如属性查找、赋值、枚举、函数调用等)。

简单来说就是对目标对象的操作之前提供了拦截,可以修改一些操作的默认行为,可以不直接操作对象背身,而是通过操作对象的代理对象间接来操作对象。

// 简单举个例子
const obj = {
    name: 'chuan'
}
let proxyObj = new Proxy(obj, {
    get: function (target, prop) {
        console.log(prop);
        return prop in target ? target[prop] : 18
    },
    set: function (target, prop, value) {
        target[prop] = value;
    }
})
console.log(proxyObj.name);        // 'chuan'
console.log(proxyObj.age);        // 18

proxyObj.age = 20;
console.log(proxyObj.age)         // 20

这儿推荐一篇比较好的文章可以详细看看proxy的作用和亮点(初探 Vue3.0 中的一大亮点——Proxy ! - 简书

第四道:怎么理解Promise对象?

Promise 对象有以下两个特点: 

  1. 对象的状态不受外界影响。Promise 对象共有三中状态 pendingfulfilledrejected。状态值只会被异步结果决定,其他任何操作无法改变。
  2. 状态一旦成型,就不会再变,且任何时候都可得到这个结果。状态值会由 pending 变为 fulfilledrejected,这时即为resolved

Promise 的缺点有如下三个缺点:

  1. Promise 一旦执行便无法被取消;
  2. 不可设置回调函数,其内部发生的错误无法捕获。
  3. 当处于 pending 状态时,无法得知其具体发展到了哪个阶段。

Promise 中常用的方法有: 

  1. Promise.prototype.then():Promise实例的状态发生改变时,会调用then内部的回调函数。then方法接受两个参数(第一个为resolved状态时时执行的回调,第一个为rejected状态时时执行的回调)。

  2. Promise.prototype.catch():.then(null, rejection)或.then(undefined, rejection)的别名,用于指定发生错误时的回调函数。

  3. Promise.all:当有一个ajax请求,它的参数需要另外2个甚至更多请求都有返回结果之后才能确定,那么这个时候,就需要用到Promise.all来帮助我们应对这个场景。Promise.all接收一个Promise对象组成的数组作为参数,当这个数组所有的Promise对象状态都变成resolved或者rejected的时候,它才会去调用then方法。

  4. Promise.race:与Promise.all相似的是,Promise.race都是以一个Promise对象组成的数组作为参数,不同的是,只要当数组中的其中一个Promsie状态变成resolved或者rejected时,就可以调用.then方法了。而传递给then方法的值也会有所不同,大家可以再浏览器中运行下面的例子与上面的例子进行对比。

 第五道:JavaScript中的垃圾回收机制        

参考回答:

  • 必要性:由于字符串、对象和数组没有固定大小,所有当他们的大小已知时,才能对他 们进行动态的存储分配。JavaScript 程序每次创建字符串、数组或对象时,解释器都必 须分配内存来存储那个实体。只要像这样动态地分配了内存,最终都要释放这些内存以 便他们能够被再用,否则,JavaScript 的解释器将会消耗完系统中所有可用的内存,造 成系统崩溃。

        这段话解释了为什么需要系统需要垃圾回收,JS 不像 C/C++,他有自己的一套垃圾回收 机制(Garbage Collection)。JavaScript 的解释器可以检测到何时程序不再使用一个对象 了,当他确定了一个对象是无用的时候,他就知道不再需要这个对象,可以把它所占用 的内存释放掉了。例如:

var a="hello world";
var b="world";
var a=b;
//这时,会释放掉"hello world",释放内存以便再引用 垃圾回收的方法:标记清除、计数引用。
  1. 标记清除:这是最常见的垃圾回收方式,当变量进入环境时,就标记这个变量为”进入环境“,从逻 辑上讲,永远不能释放进入环境的变量所占的内存,永远不能释放进入环境变量所占用 的内存,只要执行流程进入相应的环境,就可能用到他们。当离开环境时,就标记为离 开环境。
  2. 引用计数法:另一种不太常见的方法就是引用计数法,引用计数法的意思就是每个值没引用的次数, 当声明了一个变量,并用一个引用类型的值赋值给改变量,则这个值的引用次数为 1,; 相反的,如果包含了对这个值引用的变量又取得了另外一个值,则原先的引用值引用次 数就减 1,当这个值的引用次数为 0 的时候,说明没有办法再访问这个值了,因此就把 所占的内存给回收进来,这样垃圾收集器再次运行的时候,就会释放引用次数为 0 的这 些值。

 第六道:如何理解前端模块化?

        前端模块化就是复杂的文件编程一个一个独立的模块,比如 JS 文件等等,分成独立的 模块有利于重用(复用性)和维护(版本迭代),这样会引来模块之间相互依赖的问题, 所以有了 commonJS 规范,AMD,CMD 规范等等,以及用于 JS 打包(编译等处理)的 工具 webpack

 第七道:未定

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值