一名【合格】的前端工程师的自检清单

一名【合格】前端工程师的自检清单
(语法和API篇)
(数据结构和算法篇)
(浏览器API篇)
(JavaScript编码能力篇)
(浏览器原理篇)

###一、JavaScript基础

变量和类型

1.JavaScript规定了几种数据类型?

String、Number、Boolean、Null、undefined、Symbol、Object
2.JavaScript对象的底层数据结构是什么?
js基本类型数据都是直接按值存储在栈中的,每种类型的数据占用的内存空间的大小是确定的,并由系统自动分配和自动释放。这样带来的好处就是,内存可以及时得到回收,相对于堆来说 ,更加容易管理内存空间。
js引用类型数据被存储于堆中 。其实,说存储于堆中,也不太准确,因为,引用类型的数据的地址指针是存储于栈中的,当我们想要访问引用类型的值的时候,需要先从栈中获得对象的地址指针,然后,在通过地址指针找到堆中的所需要的数据。
3.Symbol类型在实际开发中的应用、可手动实现一个简单的Symbol
4.JavaScript中的变量在内存中的具体存储形式
5.基本类型对应的内置对象,以及他们之间的装箱拆箱操作
6.理解值类型和引用类型
7.null和undefined的区别
在JavaScript中,将一个变量赋值为undefined或null,老实说,几乎没区别。那为什么还要设计两个呢?由于一些历史原因。其次,JavaScript的最初版本没有包括错误处理机制,发生数据类型不匹配时,往往是自动转换类型或者默默地失败。Brendan Eich觉得,如果null自动转为0,很不容易发现错误。因此,Brendan Eich又设计了一个undefined。
null表示"没有对象",即该处不应该有值
undefined表示"缺少值",就是此处应该有一个值,但是还没有定义。
8.至少可以说出三种判断JavaScript数据类型的方式,以及他们的优缺点,如何准确的判断数组类型
typeof: 缺点不能细分对象、数组,并且null返回’object’
instanceof:([1,2,3] instanceof Array) 判断是否是某个类的实例,所以左侧要是一个对象 缺点:不能判断基本数据类型
constructor: ([1,2,3] .constructorArray)constructor是prototype对象上的属性,指向构造函数。根据实例对象寻找属性的顺序,若实例对象上没有实例属性或方法时,就去原型链上寻找,因此,实例对象也是能使用constructor属性的。 缺点:不能判断null、undefined,constructor 所指向的的构造函数 可以被修改的。
Object.prototype.toString.call(): Object.prototype.toString对任何变量都会返回这样一个字符串"[object class]",class 就是 JS 内置对象 构造函数的名字。 call是用来改变调用函数作用域的。
9.可能发生隐式类型转换的场景以及转换原则,应如何避免或巧妙应用
算术运算符:+号两边出现字符串,结果转换成字符串拼接;-、 *、/、 % 将字符转换成数字,再进行正常的运算,结果必为数值
关系(比较)运算符:<、<=、>、>=、!=、
任意一边出现数值,就会把另一边转成数值,再进行比较;如果都是字符,才是字符的比较规则:逐位比较(ASCII值),得到结果就停止比较;
isNaN( ):使用number()转换成数字
判断语句if():判断语句的判断条件,表达式的结果就是真和假,隐式转换,将其他转成布尔值
10.出现小数精度丢失的原因,JavaScript可以存储的最大数字、最大安全数字,JavaScript处理大数字的方法、避免精度丢失的方法
出现小数精度丢失的原因:JS 遵循 IEEE 754 规范,采用双精度存储),占用 64 位。二进制只有 0 和 1 两个,超出64位于是变为 0 舍 1 入。这即是计算机中部分浮点数运算时出现误差,丢失精度的根本原因。
JavaScript可以存储的最大数字、最大安全数字:(9007199254740991)2的53次方减一
JavaScript避免精度丢失的方法

1、把小数放到位整数(乘倍数),再缩小回原来倍数(除倍数)
/**
 * floatObj 包含加减乘除四个方法,能确保浮点数运算不丢失精度
 *
 * 我们知道计算机编程语言里浮点数计算会存在精度丢失问题(或称舍入误差),其根本原因是二进制和实现位数限制有些数无法有限表示
 * 以下是十进制小数对应的二进制表示
 *      0.1 >> 0.0001 1001 1001 1001…(1001无限循环)
 *      0.2 >> 0.0011 0011 0011 0011…(0011无限循环)
 * 计算机里每种数据类型的存储是一个有限宽度,比如 JavaScript 使用 64 位存储数字类型,因此超出的会舍去。
  舍去的部分就是精度丢失的部分。
 *
 * ** method **
 *  add / subtract / multiply /divide
 *
 * ** explame **
 *  0.1 + 0.2 == 0.30000000000000004 (多了 0.00000000000004)
 *  0.2 + 0.4 == 0.6000000000000001  (多了 0.0000000000001)
 *  19.9 * 100 == 1989.9999999999998 (少了 0.0000000000002)
 *
 * floatObj.add(0.1, 0.2) >> 0.3
 * floatObj.multiply(19.9, 100) >> 1990
 *
 */
var floatObj = function() {
    /*
     * 判断obj是否为一个整数
     */
    function isInteger(obj) {
        return Math.floor(obj) === obj
    }
    
    /*
     * 将一个浮点数转成整数,返回整数和倍数。如 3.14 >> 314,倍数是 100
     * @param floatNum {number} 小数
     * @return {object}
     *   {times:100, num: 314}
     */
    function toInteger(floatNum) {
        var ret = {times: 1, num: 0}
        var isNegative = floatNum < 0
        if (isInteger(floatNum)) {
            ret.num = floatNum
            return ret
        }
        var strfi  = floatNum + ''
        var dotPos = strfi.indexOf('.')
        var len    = strfi.substr(dotPos+1).length
        var times  = Math.pow(10, len)
        var intNum = parseInt(Math.abs(floatNum) * times + 0.5, 10)
        ret.times  = times
        if (isNegative) {
            intNum = -intNum
        }
        ret.num = intNum
        return ret
    }
    
    /*
     * 核心方法,实现加减乘除运算,确保不丢失精度
     * 思路:把小数放大为整数(乘),进行算术运算,再缩小为小数(除)
     *
     * @param a {number} 运算数1
     * @param b {number} 运算数2
     * @param digits {number} 精度,保留的小数点数,比如 2, 即保留为两位小数
     * @param op {string} 运算类型,有加减乘除(add/subtract/multiply/divide)
     *
     */
    function operation(a, b, digits, op) {
        var o1 = toInteger(a)
        var o2 = toInteger(b)
        var n1 = o1.num
        var n2 = o2.num
        var t1 = o1.times
        var t2 = o2.times
        var max = t1 > t2 ? t1 : t2
        var result = null
        switch (op) {
            case 'add':
                if (t1 === t2) { // 两个小数位数相同
                    result = n1 + n2
                } else if (t1 > t2) { // o1 小数位 大于 o2
                    result = n1 + n2 * (t1 / t2)
                } else { // o1 小数位 小于 o2
                    result = n1 * (t2 / t1) + n2
                }
                return result / max
            case 'subtract':
                if (t1 === t2) {
                    result = n1 - n2
                } else if (t1 > t2) {
                    result = n1 - n2 * (t1 / t2)
                } else {
                    result = n1 * (t2 / t1) - n2
                }
                return result / max
            case 'multiply':
                result = (n1 * n2) / (t1 * t2)
                return result
            case 'divide':
                result = (n1 / n2) * (t2 / t1)
                return result
        }
    }
    
    // 加减乘除的四个接口
    function add(a, b, digits) {
        return operation(a, b, digits, 'add')
    }
    function subtract(a, b, digits) {
        return operation(a, b, digits, 'subtract')
    }
    function multiply(a, b, digits) {
        return operation(a, b, digits, 'multiply')
    }
    function divide(a, b, digits) {
        return operation(a, b, digits, 'divide')
    }
    
    // exports
    return {
        add: add,
        subtract: subtract,
        multiply: multiply,
        divide: divide
    }
}();
2.toFixed(Chrome 不会四舍五入)的修复如下:
// toFixed 修复
function toFixed(num, s) {
    var times = Math.pow(10, s)
    // 放大time倍 +0.5为了达到四舍五入
    // 例如:3.445*100+0.5 = 345 3.444*100+0.5 = 344.9 在使用parseInt达到四舍五入
    var des = num * times + 0.5
    des = parseInt(des, 10) / times
    return des + ''
}

处理大数字的方法:①使用big-integer处理大数 ②将数字变为字符串进行处理

原型和原型链

1.理解原型设计模式以及JavaScript中的原型规则

原型规则:所有引用类型(数组、对象、函数),都具有对象特征,即可自由扩展属性;都有一个__proto__属性,属性值是原型对象;所有函数都具有prototype,值是原型对象;所有引用类型指的__proto__指向器构造函数的原型对象;当得到一个属性没有时会根据___proto__去查找。
原型对象:prototype 在js中,函数对象其中一个属性,值为原型对象。普通对象没有这个属性但是___proto__指向原型对象。原型的作用就是给这个类的每一个对象都添加一个统一的方法,在原型中定义的方法和属性都是被所以实例对象所共享。
原型链:当试图得到一个对象f的某个属性时,如果这个对象本身没有这个属性,那么会沿着__proto__查找。
2.instanceof的底层实现原理,手动实现一个instanceof
3.实现继承的几种方式以及他们的优缺点
实现继承的几种方式:

1、原型继承(继承方法)
function Parent(){
    this.name = '名字'
    this.age = 18
}
Parent.prototype = sun(){
    console.log('唱歌')
}
function Son(){}
// 子类的原型指向父类的实例, 子类实例在调用方法的时候会通过__proto__向上查找
Son.prototype = new Son()

2、借用call继承属性
function Son(){
    // 借用call 来实行构造函数
    Parent.call(this)
}

3、组合继承(原型继承和借用继承一起使用)

4.至少说出一种开源项目(如Node)中应用原型继承的案例
5.可以描述new一个对象的详细过程,手动实现一个new操作符

new关键字的执行过程:1、创建一个空对象 2、改变this指向 3、向其中添加属性 4、返回这个对象

new关键字的执行过程
如果一个类返回值是一个引用类型那么就返回这个引用类型值
function mockNew(fn){
    let obj = {}
    let newValue = fn.call(obj)
     if((typeof returnVal === 'object' && returnVal !== null) || typeof returnVal === 'function'){
            return returnVal;
    }
    obj.__proto__ = fn.prototype
    return obj
}

6.理解es6 class构造以及继承的底层实现原理

Class本质上是一个特别的函数 Class 在语法上更加贴合面向对象的写法 Class 实现继承更加易读、 易理解 更易于写 java 等后端语言的使用 本质还是语法糖, 使用 prototype
我们可以借助babel来探究es6类和继承的实现原理

作用域和闭包

1.理解词法作用域和动态作用域
2.理解JavaScript的作用域和作用域链

作用域:也就是创建函数时当前执行上下文存储变量的地方
作用域链:变量取值的过程,先在自己执行上下文中的变量对象中找看是否是自己AO中的私有变量,找不到就去上级作用域查找,有则停止,无就继续,一直找到全局作用域。
3.理解JavaScript的执行上下文栈,可以应用堆栈信息快速定位问题
4.this的原理以及几种不同使用场景的取值
5.闭包的实现原理和作用,可以列举几个开发中闭包的实际应用
闭包:函数执行形成一个全新的执行上下文,进栈执行后所创建的一些变量被外部所引用,不能出栈销毁,就形成了闭包。
作用:延长了局部变量的生命周期,保护全不被污染
缺点:函数不能被出栈销毁,频繁使用会造成内存泄漏问题。
解决方法:手动销毁 fn=null
6.理解堆栈溢出和内存泄漏的原理,如何防止
7.如何处理循环的异步操作
8.理解模块化解决的实际问题,可列举几个模块化方案并理解其中原理

执行机制

1.为何try里面放return,finally还会执行,理解其内部机制
2.JavaScript如何实现异步编程,可以详细描述EventLoop机制

ES 6以前:

  • 回调函数
  • 事件监听(事件发布/订阅)
  • Promise对象
    ES 6:
  • Generator函数(协程coroutine)
    ES 7:
  • async和await
    事件队列和事件循环:
    js是单线程的只有等主线程执行完毕,才会去执行异步的任务。
    异步任务放在任务队列中,任务队列分为微任务和宏任务 先执行微任务在执行宏任务
    微任务:promise、async、await
    宏任务:定时器
    事件循环:主线程执行完代码后去任务队列中查找可执行异步任务,先找微任务找到执行,在查找执行,微任务没有后再找宏任务,查找执行;这一套机制称之微事件循环机制。
    3.宏任务和微任务分别有哪些
    宏任务:I/O 、setTimeout、setInterval、setImmediate、requestAnimationFrame
    微任务:process.nextTick、MutationObserver、promise、async、await
    4.可以快速分析一个复杂的异步嵌套逻辑,并掌握分析方法
    5.使用Promise实现串行
    6.Node与浏览器EventLoop的差异
    7.如何在保证页面运行流畅的情况下处理海量数据
语法和API

1.理解ECMAScript和JavaScript的关系

1996年11月,JavaScript的创造者Netscape公司,决定将JavaScript提交给国际标准化组织ECMA,希望这种语言能够成为国际标准。所以说ECMAScript和JavaScript的关系是,前者是后者的规格(标准)。
2.熟练运用es5、es6提供的语法规范,
es5语法规范
es6语法规范1 es6语法规范1
3.熟练掌握JavaScript提供的全局对象(例如Date、Math)、全局函数(例如decodeURI、isNaN)、全局属性(例如Infinity、undefined)
4.熟练应用map、reduce、filter 等高阶函数解决问题

5.setInterval需要注意的点,使用settimeout实现setInterval

6.JavaScript提供的正则表达式API、可以使用正则表达式(邮箱校验、URL解析、去重等)解决常见问题

7.JavaScript异常处理的方式,统一的异常处理方案

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值