前端面试题 js+ES6、vue、项目场景....(持续更新)

js

js执行上下文:

概念:抽象概念,包含当前代码执行的环境信息

全局 --> js 引擎 默认创建 <script>全局</script>

函数(局部) --> function

Eval --> eval函数中创建

应用场景:在作用域和程序执行顺序的程序中,都会有执行上下文

全局执行上下文:

js在执行任何代码前都会创建一个新的执行上下文,新的执行上下文--> 全局执行上下文

两个阶段:

创建阶段:全局对象和this被创建,为全局变量和函数分配内存,允许有“未定义”的值

执行阶段:代码的执行开始,为变量赋值 且 定义函数

函数执行上下文:

执行函数的时候被创建

eval执行上下文:

执行eval函数的时候创建,可能执行恶意的字符串,引起安全隐患

作用域和作用域链:

概念:作用域就是在运行时代码中的某些特定部分中变量,函数和对象的可访问性

作用域作用:

Jquery zepto函数库 自执行函数中

箭头函数 this指向问题

DOM事件中定义的变量都是局部函数,有可能在外部调用,比如:定时器

作用域

全局:任何地方都可以访问

局部:又叫函数作用域,在函数内部可以访问

全局作用域:

最外层的函数和最外层的变量都是全局作用域

所有未定义直接赋值的变量直接声明为全局作用域

所有window对象的属性拥有全局作用域

注意:全局变量容易污染命名空间

局部作用域(函数作用域):

声明在函数内部的变量

注意:快语句{},{}之内的 比如if、switch、for、while不会创建作用域

作用域链:

变量取值是在当前作用域中取值,如果没有就向外层作用域查找,直到找到全局作用域,查找的过程就是作用域链

闭包

概念:就是说一个函数访问他的父级或者父级以上的变量

作用:

访问函数的变量

让变量保持在内存中

闭包执行顺序:

闭包中的内存变量是驻留内存的****

闭包应用场景:

典型 jquery zepto库 (function (){属性 方法})()

防抖节流

Vue事件处理中

Methods:{

        方法名(){

        }

}

        }

闭包优缺点:

优点:

减少全局变量的定义,减少全局污染

能够读取函数内部的变量

内存中驻留变量可以当作缓存使用

缺点:

内存泄露

因变量内存驻留可能影响性能

建议:闭包会跨作用域访问,会导致性能下降,尽量把变量定义为局部变量

原型和原型链

概念:

原型目的:共享内存,节省资源

原型:

每一个js对象创建(null除外),同时会创建一个原型对象,js对象会继承原型对象的内容

原型分为 显式原型和隐式原型

显式原型:显式原型是prototype 创建对象的时候会被创建

隐式原型:实例对象都有的__proto__属性,指向对应构造函数的原型对象

prototype :指向函数的原型对象,属于一个地址引用

对象下的prototype引用 对象.prototype

__proto__:在谷歌90之前显示的是__proto__,新版本中__proto__变成了 [[prototype]]

注意:任何构造函数中的方法和属性,执行过程中是实例化对象调用, 先查找构造函数本身有没有属性和方法,有则调用没有就去原型上查找, 要是也没有,就报错

Constructor:__proto__下的Constructor,是指向构造函数本身的

原型链:

实例对象有__proto__,而__proto__又指向构造函数的prototype属性 ,prototype 呢也有__proto__,就这样一层一层往上找,最后会找到object.protype上, 这就是原型链

原型链呢主要是一种继承的方式

this指向

this是一个指针变量,动态的指向当前函数的运行环境,指向其所在函数的调用者

如果没有人调用,就指向全局变量window

全局环境:全局环境下的this指向window

函数内部:指向的依然是window

对象中的this:对象内部方法的this指向调用这些方法的对象

一层对象:谁调用指向谁

二层对象:在多层对象中,this是离谁近指向谁

箭头函数:没有this和arguments(阿给门磁),捕捉外层的执行环境,继承 外层的this

构造函数:this指向构造函数创建的实例

注意:在js继承机制中,this指向构造函数创建的实例,非原型链

高阶函数 

函数式编程:把现实世界的事物和事物之间的联系抽象到编程世界(对运算 过程进行抽象)

高阶函数:是函数式编程的一个重要概念,函数可以作为参数或者返回的 存在         函数可以作为参数被传递    函数可以作为返回值输出

高阶函数应用:

在数组函数中常用:filter map reduce every....,另外在防抖节流,程序设计模式中都有类似的应用

设计模式

单例模式:一个类 只能有一个实例对象 提供一个全局访问点

应用场景:弹窗   axios封装

工厂模式:用固定的方式批量创建对象

应用场景:权限和角色进行判断

观察者模式:多个观察者,对象发生变化是,通知所有观察者让他们更新 自己的状态

Object.defineProperty()

Setter --> set()设置  

Getter    --> get()取值

对象由键值对 组成的无序集合,对象中的每个属性值:任意类型

Object.defineProperty(obj,prop,desc)

Obj   目标对象

Prop  属性名称

Desc  属性特征

返回函数对象,返回obj

发表订阅模式:发布者内容变化,通过中间层接收并通知订阅者,订阅者收 到通知,更新对应的属性和其他模式

观察者模式和发布订阅模式有什么区别

观察者模式:只有两个元素,观察者和被观察者

发布订阅模式: 他有一个中间层。发布-->中间层-->订阅者

继承

面向对象:继承 封装 多态

继承:父类的属性和方法 可以被子类继承

        

// 手动实现call/apply
        var obj = {
            getInfo:function(){
                console.log('this',this);
                return this.name
            }
        }
        var obj2 = {
            name:"张三"
        }
        // Function 原型上定义的方法,所有对象都可用
        Function.prototype.testcall = function(val){
            console.log(1,val); // obj2
            console.log(2,this); // getInfo
            // this判断
            if(typeof this !== "function"){
                throw new Error("this错误")
            }
            context = val || window
            // 处理参数
            // console.log(3,val,[arguments]);
            let arrs = [...arguments].slice(1)
            // console.log(4,arrs);
            val.fn = this
            var res = val.fn(...arrs)
            console.log(5,res,this); // this指向obj2
            return 1
        }
        console.log('外层',obj.getInfo.testcall(obj2,11,22,333));

子类就可以调用父类的属性和方法

原型和原型链继承:

优点:实例是子类的实例同时也是父类的实例(他是将父类实例绑定 在子类原型上)

        父类新增的属性和方法子类都可以访问

缺点:原型的属性是共享的,修改一个属性,所有的属性都修改了

        创建子类实例,无法向父类传递参数

构造函数继承:子类构造函数内部调用父类的构造函数

使用call/apply  将父对象的构造函数绑定在子类上

        优点:子类实例共享引用属性的问题

                子类可以向父类传参

缺点:每个子类对象都有自己的执行函数,如果对象多了,内存消 耗大

组合式继承:原型链继承和构造函数 组合

优点:不存在引用属性共享问题

         子类可向父类传参

缺点:子类原型上多余了一份父类的实例

原型式继承:有一个封装 继承过程的函数,是用来增强对象的

        优点:不需要单独创建构造函数

        缺点:属性会在对象中共享,子类实例不能向父类传参

寄生式继承:创建对象的方法,封装创建过程的函数,实际的对象

        优点:不需要单独创建构造函数

        缺点:代码复用性差,编写起来相对复杂

ES6继承:extends

Call/apply的作用以及手动实现

Call和apply的作用

是原型中方法,所有的函数都是function实例

调用一个对象的方法,另一个对象替换当前对象,this发生改变-->call/apply

        Apply:

                方法A.apply(方法B,[数组参数])  方法A的this指向方法B

                前面方法的this指向后面方法

        Call:

                方法A.call(方法B,参数,参数)  方法A的this指向方法B

                Call不像apply参数写在数组内传,他是一个一个的传(参数,参数,参数)

        实际使用:

                Js中构造函数继承

                判断js的某些数据类型

                        typeof {}  []

                伪数组--》数组

        手动实现call/apply

                在Function原型上定义要实现的call方法

                获取程序执行的上下文

                转换this的指向

// 手动实现call/apply
        var obj = {
            getInfo:function(){
                console.log('this',this);
                return this.name
            }
        }
        var obj2 = {
            name:"张三"
        }
        // Function 原型上定义的方法,所有对象都可用
        Function.prototype.testcall = function(val){
            console.log(1,val); // obj2
            console.log(2,this); // getInfo
            // this判断
            if(typeof this !== "function"){
                throw new Error("this错误")
            }
            context = val || window
            // 处理参数
            // console.log(3,val,[arguments]);
            let arrs = [...arguments].slice(1)
            // console.log(4,arrs);
            val.fn = this
            var res = val.fn(...arrs)
            console.log(5,res,this); // this指向obj2
            return 1
        }
        console.log('外层',obj.getInfo.testcall(obj2,11,22,333));

深拷贝浅拷贝

  1. 回顾数据类型和储存方式

基本数据类型 储存在栈内存中string number boolean null undefined Symbol

引用数据类型(复杂) 将其地址存在栈内存中, 真实数据存在堆内存中

object( function arrya data..... )

注意:基本数据类型在栈内存中   引用数据类型在堆内存中

浅拷贝:

在栈内存开辟一个新空间,并且将数据完全拷贝

基本数据类型

引用:复制地址的时候,两个变量指向同一片内存空间

浅拷贝的常用方法:

复制:

扩展运算符 对象的属性 数组 浅拷贝***

for ...in 对对象进行拷贝:二级是浅拷贝一级不是

深拷贝:

在栈内存中会开辟新空间,若对象的引用类型,堆内存中也会开辟空间用 来 存储值

JSON.parse()

缺点:对象属性的函数,无法拷贝

 原型链上的属性值,无法拷贝

 不能处理正则

 会忽略Symbol和undefined

递归拷贝

深拷贝使用场景:

对象修改---》深拷贝

框架获取接口数据的时候,需要拷贝一份

小结:

浅拷贝:栈中开辟一块空间,并将对象的栈内存数据完全拷贝到该空间中。

对简单数据类型就是拷贝值,

对复杂数据,引用(复杂)类型时,实际复制的是其引用地址

深拷贝: 会在栈中开辟另一块空间,若被拷贝对象中有引用类型,则 还会在内存中开辟另一块空间储存引用类型的真实数据

共同点:都是用来复制数据

不同点:复制的对象不同,分为对地址操作(浅拷贝)和对地址里发值进 行操作

防抖节流

节流:n秒内只运行一次,若n秒内 反复的出发,只有一次生效

防抖:n秒后执行事件,如果n秒内重新出发,则重新计时

应用场景:

防抖:搜索框连续输入onchenge事件,窗口改变相关的事件

节流:懒加载,加载更多,防止高频点击,防止表单重复提交

浏览器如何渲染页面

cssom

css object model

采用css代码,选择器呈现树状结构,是css对象化表示,提供了api 操作css

分为两部分:

model:描述样式和规则的模型部分

view: 和元素视图相关的api部分

mode是cssom的本地,用style或link标签创建

<style></style>

<link rel=”” href=””>

model

构建DOM结构:

通过网络获取字节流和字符

分词--》得到一个一个的词组序(token) div span p

根据token分析语法,得到node

根据node 构建DOM树

cssom是依赖于DOM,在构建cssom树的时候,为元素添加样式, 浏览器会从父节点开始,递归向下,直到每个元素都添加上为止

view

窗口:moveTo  moveBy  resizeTo  resizeBy

滚动:scrollx/y  scroll()  scrollBy()

布局:位置  尺寸  innerHeight/width  screen....

浏览器如何渲染页面

从服务器拿到htm后

根据html构建DOM和cssom树

构建渲染树

页面重排和重绘

重绘:渲染节点发生改变时,不影响空间和位置

重排:也称回流,对位置( 比如说,宽高 内外边距 定位 )进行 操作,所以页面就会重排,重新渲染

减少重排

多个样式尽量合并

DomcumtFragment 进行缓存操作,引发一次重排

重排频率高的元素,采用绝对定位

小结:

1根据html文件构建DOM树和cssom树,构建DOM树期间,如 果遇到js,堵塞DOM树及cssom树,优先加载js文件,加载完毕,再继续构建DOM树以及cssom树

2渲染树:渲染树由DOM树、cssom树合并而成,构建渲染树,根 据渲染树计算每个可见元素的布局,并输出到绘制流程,将元 素渲染到屏幕上

3页面的重绘与重排,页面渲染完成后,js操作的DOM节点,根据js对DOM操作动作的大小,浏览器对页面进行重绘和重排

同步异步

Js单线程,不能同时进行多个任务

同步:发出功能,没得到结果之前,调用就不返回

过程:提交请求--》等待服务器处理

--》处理完结果为止(浏览器静止)

异步:异步调用发出请求,不能立刻得到结果通过状态值或回 调通知调用者

过程:提交请求--》服务器处理( 浏览器可以做其他任务 )

--》得到状态/通知--》处理完毕

同步任务:栈      异步任务:队列

同步

缺点:容易代码堵塞

优点:容易理解

异步

缺点:不按照顺序,不容易理解

优点:解决代码堵塞

小结:

同步是再执行栈中排队执行,顺序执行( 前一个执行完后面 才执行 )

异步是任务队列,等执行栈的任务执行完毕了,任务队列进 入执行栈,再按顺序执行

事件循环机制

Js执行顺序:

逐行执行,遇到报错,就停止,先同步后异步

执行步骤:

1把代码按照顺序放入js主线程的执行栈中,依次执行,执行完毕清空执行栈

2遇到异步代码,会放到event table中,同步执行完毕,把异步代码放入回调队列

3通过event loop轮询机制,把回调队列中的代码,放入执行栈中执行

4 Event loop 继续轮询回调队列,直到回调队列为空

宏任务和微任务:

在event table中区分执行时机

宏任务:setTimeout setInterval ajax dom 事件

微任务:promise  async  await

微任务比宏任务执行早

宏任务和微任务区别:

宏任务:浏览器定义的,DOM渲染后触发

微任务:es6定义的,DOM渲染前触发

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值