前端八股文(码字中)

1.css3新特性

  • 颜色:新增RGBA,HSLA模式
  • 文字阴影:text-shadow
  • 边框:圆角(border-radius)边框阴影:box-shadow
  • 盒子模型:box-sizing
  • 背景:background-size(背景图大小); background-origin(背景图起始位置,相对于背景区域的位置); background-clip(背景图片的裁剪方式)
  • 渐变:linear-gradient(线性渐变), radial-gradient(径向渐变)
  • 过渡:transition可实现属性的渐变
  • 自定义动画animate@keyfrom
  • 媒体查询多栏布局@media screen and (width: 800px){…}
  • border-image图片边框
  • 2D转换/3D转换: transform: translate(x,y)位移, rotate(x,y)旋转, skew(x,y)倾斜, scale(x,y)缩放
  • 字体图标iconfont/icomoon
  • 弹性布局flex

2.css优先级

!important > 行内选择器 > ID选择器 > 类选择器 > 标签选择器 > 通配符 > 继承 > 浏览器默认属性

3.px,vw/vh,rem的区别

  • px: 绝对单位,网页按照精确像素来显示
  • em: 相对单位, 相对自身定义的font-size来计算, 自身没有设置字体大小,相对父元素的字体大小
  • rem: 相对单位, 相对根元素html的字体大小来计算
  • vw/vh: 相对视口大小布局, 把屏幕平均划分为100等份

4. es6新特性

  • 新增声明命令let和const
  • 模版字符串
  • 函数的扩展
  • 对象的扩展
  • for…of循环
  • import和export
  • Promise对象
  • 对象的解构赋值
  • Set数据结构
  • class
  • …(展开运算符)
  • async、await
  • 修饰器
  • Symbol
  • Proxy

5. 如何理解响应式网站

针对不同的终端,采取不同的布局样式

优点: 减少工作量, 减少工时间, 每个设备都能得到一个正确的设计, 搜索的优化

缺点: 加载更多的样式和脚本资源, 设计比较难精确定位和控制,设计师要求高, 老版本浏览器兼容性不好

6.闭包

闭包是一个可以访问其他函数内部变量的函数,主要作用是解决变量污染问题,也可以用来延长局部变量的生命周期。闭包在 js 中使用比较多,几乎是无处不在的。一般大多数情况下,在回调函数中闭包用的是最多的
使用场景:

  • 创建私有变量
  • 延长变量的生命周期

注意事项:

  1. 由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,在IE中可能导致内存泄露。解决方法是,在退出函数之前,将不使用的局部变量全部删除
  2. 闭包会在父函数外部,改变父函数内部变量的值。所以,如果你把父函数当作对象(object)使用,把闭包当作它的公用方法(Public Method),把内部变量当作它的私有属性(private value),这时一定要小心,不要随便改变父函数内部变量的值

7.原型和原型链

原型

每个对象都有一个原型(prototype)。原型是一个对象,其他对象可以通过原型继承它的属性和方法

原型链

原型链是 js对象一种查找机制,遵循就近原则。当我们访问一个对象中的成员的时候,会优先访问自己的,如果自己没有就访问原型的,如果原型也没有就会访问原型的原型,直到原型链的终点null. 如果还没有,此时属性就会获取 undefined,方法就会报错 xxx is not a function。一般原型链主要是用来实现面向对象继承的

8.js继承

  • 原型链继承
  • 借用构造函数继承
  • 组合继承
  • 寄生继承
  • 寄生组合继承
  • ES6新增的extends继承

一般我们开发中用的比较多的就是原型链继承 还有class类函数继承. 其他的基本用的少

9.css画一个三角形

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>向上的三角形</title>
    <style>
        .box{
            width: 0px;
            height: 0px; 
            border-left: 100px solid transparent;
            border-right: 100px solid transparent;
            border-top: 100px solid transparent;
            border-bottom: 100px solid yellowgreen;
        }
    </style>
</head>
<body>
    <div class="box"></div>
</body>
</html>

10.如何拓展数组的方法

1.join()

将数组中所有的元素连成字符串,并使用分隔符连接

 <script>
         let arr=[1,2,3,4,'a','b','v']
         let obj = arr.join('-')
         console.log(obj)    //1-2-3-4-a-b-v
  </script>

2.reverse()

用于反转数组中元素的顺序,它会修改原始数组,并返回该修改后的数组

    <script>
         let arr=[1,2,3,4,'a','b','v']
         let obj = arr.reverse(arr)
         console.log(obj)    // ['v', 'b', 'a', 4, 3, 2, 1]
    </script>

3.sort()

将数组中的元素排序并返回排序后的数组

    <script>
        const array = [3, 1, 5, 2, 4]
        array.sort((a, b) => a - b)
        console.log(array) //[1, 2, 3, 4, 5]
    </script>

4.concat()

concat()方法用来合并两个或多个数组

    <script>
        let Array1 = [1, 2, 3, 4, 'a', 'b', 'v']
        let Array2 = ["C", "D", 4, "7", "9"] 
        let newArr = Array1.concat(Array2)
        console.log(newArr)  //[1, 2, 3, 4, 'a', 'b', 'v', 'C', 'D', 4, '7', '9']
    </script>

5.slice()

用于从数组中提取出指定范围的元素并返回一个新数组,而不改变原始数组

    <script>
        let Array1 = [1, 2, 3, 4, 'a', 'b', 'v']
        let newArr = Array1.slice(1,5)
        console.log(newArr)  //[2, 3, 4, 'a']
    </script>

6.push()

向数组最后面添加一个值,并返回一个数组的新长度,这个会改变原数组

    <script>
        let Array1 = [1, 2, 3, 4, 'a', 'b', 'v']
        let aa = Array1.push('嘻嘻')
        console.log(Array1)  //[1, 2, 3, 4, 'a', 'b', 'v', '嘻嘻']
        console.log(aa)   //打印数组的长度  8
    </script>

7.pop()

用于删除并返回最后一个元素,会修改原数组

    <script>
        let Array1 = [1, 2, 3, 4, 'a', 'b', 'v']
        let aa = Array1.pop()
        console.log(Array1)  //[1, 2, 3, 4, 'a', 'b']
        console.log(aa)   //返回最后一个元素 v
    </script>

8.unshift()

unshift()在数组的头部添加一个或多个元素,并将已经存在的元素移动到下一个位置. 最后返回元素新的长度

    <script>
        let Array1 = [1, 2, 3, 4, 'a', 'b', 'v']
        let aa = Array1.unshift('one','two','three')
        console.log(Array1)  // ['one', 'two', 'three', 1, 2, 3, 4, 'a', 'b', 'v']
        console.log(aa)   //返回新数组的长度 10
    </script>

9.shift()

shift()删除数组的第一个元素并将他返回, 然后把所有随后的元素下移一个位置填补数组头部的空缺

    <script>
        let Array1 = [1, 2, 3, 4, 'a', 'b', 'v']
        let aa = Array1.shift()
        console.log(Array1)  // [2, 3, 4, 'a', 'b', 'v']
        console.log(aa)   //返回删除的第一个元素 1
    </script>

10.filter()过滤

返回数组中满足条件的元素组成的新数组,原数组不变

    <script>
        let Array1 = [1, 2, 3, 4, 'a', 'b', 'v']
        const res = Array1.filter((item) => {
           return typeof(item) === 'number'
        })
        console.log(res)   // 返回满足条件的元素组成新的数组[1, 2, 3, 4]
    </script>

11.map() 格式化数组

方法将调用的数组的每个元素传递给指定的函数,并返回一个值

    <script>
        let Array1 = [1, 2, 3, 4]
        const res = Array1.every((item) => typeof(item) === 'number')
        console.log(res)   // true


        let Array2 = [1,2,3,4,'99']
        const result = Array2.every(item => typeof(item) === 'Number')
        console.log(result)  //false
    </script>

13.reduce()

reduce() 方法接收一个函数作为累加器,数组中的每个值 (从左到右) 开始缩减, 最终计算为一个值
prey表示上一次回调使用时的返回值, 或者初始值init, cur表示当前值, index表示数组的索引, init表示初始值 , arr表示原数组

    <script>
        let Array1 = [1, 2, 3, 4]
        const res = Array1.reduce((prey,cur,index) => prey + cur,0)
        console.log(res)   // 10
    </script>

14.indexOf() 和 lastIndexOf()

查找某元素在数组中的位置, 若存在, 则返回第一个位置的下标, 否则返回-1
lastIndexOf() 和indexOf()相同, 区别在于从尾部向首部查询

    <script>
        let Array1 = [1, 2, 3, 4]
        const res = Array1.indexOf(4) 
        console.log(res)   // 返回下标  3

        const res2 = Array1.indexOf(11)
        console.log(res2)  // 查找不到 返回 -1
    </script>

15.some()

对数组的每一项都运行给定的函数,若存在一项或多项返回true, 否则返回false

    <script>
        let Array1 = [1, 2, 3, 4]
        const res = Array1.some(item => item % 2 === 0) 
        console.log(res)   // 存在一项正确 返回 true

        const res2 = Array1.some(item => item % 5 === 0)
        console.log(res2)  // 没有一项存在 故返回false
    </script>

16.forEach()

用于调用数组的每一个元素, 并将元素传递给回调函数

    <script>
        let Array1 = [1, 2, 3, 4]
        Array1.forEach(item => console.log(item)) 
    </script>

17.splice()

传入三个参数,分别是开始位置,要删除元素的数量,要插入的任意多个元素,返回删除元素的数组,对原数组产生影响

    <script>
        let Array1 = [1, 2, 3, 4]
        Array1.splice(2,1,'嘻嘻')   //替换
        console.log(Array1)

        Array1.splice(0,1)
        console.log(Array1)  //删除
    </script>

12.如何判断数据类型

typeof 判断基本数据类型,存在弊端,它虽然可以判断基础数据类型(null 除外),但是引用数据类型中,除了function 类型以外,其他的也无法判断
instanceof 可以准确地判断复杂引用数据类型,但是不能正确判断基础数据类型

function fn(x){
  return console.log(Object.prototype.toString.call(x).replace(/^\[object (\S+)\]$/, '$1'))
}

采用Object.prototype.toString,调用该方法,统一返回格式“[object Xxx]”的字符串,
再利用正则去掉object

13. var, let和const的区别

共同点:都能声明变量
不同点:var 在ECMAScript 的所有版本中都可以使用,而const和let只能在ECMAScript6【ES2015】及更晚中使用

var

  • 声明变量可以重复声明,而let不可以重复声明
  • var是不受限于块级的,而let是受限于块级
  • var会与window相映射(会挂一个属性), 而let 不与window相映射
  • var可以在声明的上面访问变量,而let有暂存死区,在声明的上面访问变量会报错

let

  • let作用域为块作用域
  • 不能进行条件式声明
  • for循环使用let来声明迭代变量不会导致迭代变量外渗透

const

  • const声明之后必须赋值,否则会报错
  • const定义不可变的量,改变了就会报错
  • const和let 一样不会与window想映射,支持块级作用域, 在声明的上面访问变量会报错

14.defineproperty 和 Proxy

Proxy

  • Proxy可以直接监听对象而非属性
  • Proxy可以直接监听数组的变化
  • Proxy有多达13种拦截方法, 不限于apply, ownKeys, deleteProperty, has等等是Object.defineProperty不具备的
  • Proxy返回的是一个新对象,我们可以只操作新的对象达到目的,而Object.defineProperty只能遍历对象属性直接修改
  • Proxy作为新标准将受到浏览器厂商重点持续的性能优化,也就是传说中的新标准的性能红利

Object.defineProperty

  • 兼容性好,支持IE9, 而Proxy的存在浏览器兼容性问题, 而且无法用polyfill磨平的

15. 防抖和节流

防抖

单位时间内, 频繁触发事件, 只执行最后一次.
场景:

  • 搜索框搜索输入, 只需用户最后一次输入完,再发送请求
  • 手机号, 邮箱验证输入检测
节流

单位时间内,频繁触发事件,只执行一次.
场景:

  • 高频事件, 例如 resize事件, scroll事件
  • 手机号,邮箱验证输入检测

相同点:

  1. 都可以通过使用setTimeout来实现
  2. 减低回调执行频率,节省计算资源

不同点:

  1. 函数防抖,在一段连续操作结束后,处理回调,利用clearTimeout和setTimeout来实现.函数节流,在一段连续操作中,每一段时间只执行一次,频率较高的事件中使用来提高性能
  2. 函数防抖关注一定时间连续触发的事件,只在最后执行一次,而函数节流一段时间内只执行一次

16.箭头函数

  1. 箭头函数没有this, 所以需要通过查找作用域链来确定this的值, 这就意味着如果箭头函数被非箭头函数包含,this绑定的就是最近一层非箭头函数的this
  2. 箭头函数没有自己的arguments对象, 但是可以访问外围函数的arguments对象
  3. 不能通过new关键字调用, 同样也没有new.target值和原型

17. 重绘和重排

重绘

当元素的一部分属性发生改变, 如外观, 背景, 颜色等不会引起布局变化,只需要浏览器根据元素的新属性重新绘制,使元素呈现新的外观叫做重绘

重排(回流)

当render树中的一部分或者全部因为大小边距等问题发生改变而需要DOM树重新计算的过程

重绘不一定需要重排(比如颜色的改变),而重排必然导致重绘(比如改变网页位置)

18. 递归函数

一个函数在内部调用自己, 这个函数就是递归函数

优点: 结构清晰, 可读性强

缺点: 效率低, 调用栈可能会溢出, 其实每一次函数调用会在内存栈中分配空间, 而每个进程的栈的容量是有限的, 当调用的层次太多时, 就会超出栈的容量, 从而导致栈溢出。

19. 微任务和宏任务

ES6规范中 宏任务是由宿主浏览器或node发起的,而微任务由JS自身发起的

  • 宏任务与微任务都是异步任务,都是在同一个任务队列中,主要区别在于他们的执行顺序
  • 在异步任务队列下,又分为宏任务队列与微任务队列
  • 当一个宏任务执行结束之前, 会在微任务队列执行栈中查找是否有微任务,如果有则执行,没有则开启一个新的宏任务,所以微任务总是在宏任务结束之前执行的

宏任务: 就是JS内部(任务队列里)的任务,严格按照时间顺序压栈和执行,包括整体代码script,setTimeout,setInterval

微任务: 通常来说就是 需要在 当前 任务 执行结束后立即执行的任务 如:Promis.then(非new Promise),process.nextTick(node.js 环境中)

20.eventloop

js是一个单线程的,如果有一些高耗时操作就会带来进程阻塞问题,为了解决这个问题,js有两种任务执行模式 同步任务 和 异步任务

  • 同步模式下创建的同步任务是立即执行的
  • 异步模式下创建的异步任务分为宏任务与微任务两种

所有任务可以分成两种,一种是同步任务,另一种是异步任务。同步任务指的是,在主线程上排队执行的任务,只有前一个任务执行完毕,才能执行后一个任务。异步任务指的是,不进入主线程,而进入“任务队列”的任务,只有“任务队列”通知主线程,某个异步任务可以执行了,该任务才会进入主线程执行。

21.v-show和v-if

都能控制元素在页面是否可见
v-show: 隐藏是为该元素添加display:none,元素依旧还在,只是简单的基于css切换。

v-if: 显示隐藏是直接操作dom节点增加与删除。切换有一个局部编译/卸载的过程,切换过程中合适地销毁和重建内部的事件监听和子组件。

如果需要频繁地切换,则使用v-show较好, 例如:手风琴菜单,tab页签等
如果在运行时条件很少改变,则使用v-if较好。 例如:用户登录之后, 根据他的权限不同来显示不同的内容

22.key的作用

  • key的作用主要是为了更高效的更新虚拟DOM,因为它可以非常精确地找到相同节点,因此patch过程会非常高效
  • Vue在patch过程中会判断两个节点是不是相同节点,key是一个必要条件。比如渲染列表时,如果不写key,Vue在比较的时候,就可能会导致频繁更新元素,使整个patch过程比较低效,影响性能
  • 应该避免使用数组下标作为key,因为key值不是唯一的话可能会使Vue无法区分它,还有比如在使用相同标签元素过度切换的时候,就会导致只替换其内部属性而不会触发过渡效果
  • Vue判断两个节点是否相同时主要判断两者的元素类型和key等,如果不设置key,就可能永远认为这两个是相同节点,只能去做更新操作,就造成大量不必要的DOM更新操作,明显是不可取的

23.虚拟DOM

Virtual DOM 其实就是一颗以JavaScript对象(VNode节点)作为基础的数,用对象属性来描述节点, 相当于在js和真实dom中间加来一个缓存, 利用dom diff算法避免没有必要的dom操作,从而提高性能. 当然算法有时并不是最优解,因为他需要兼容很多时间中可能发生的情况,比如后续会讲到两个节点的dom树移动。

在vue中一般都是通过修改元素的state,订阅者根据state的变化进行编译渲染,底层的视线可以简单理解为是三个步骤:

  1. 用JavaScript对象结构表述dom树的结构,然后用这个树构建一个真正的dom树,插到浏览器的页面中
  2. 当状态改变了,也就是我们的state做出修改,vue便会重新构造一颗树的对象树,然后用这个新构建出来的树和旧树进行对比(只进行同层对比),记录两棵树之间的差异。
  3. 把记录的差异在重新应用到所构建的真正的dom树,视图就更新了。

它的表达方式就是把每一个标签都转为一个对象,这个对象可以有三个属性:tagpropschildren

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值