JS篇:
1.JS是一门面向对象的语言,说说面向对象语言的三大特征?
封装、继承、多态。
类的继承:构造 原型 实例 拷贝
2.说说你是如何理解JS中封装、继承这两个特点的?
封装指的是隐藏逻辑实现过程,只对外暴露属性和方法
继承指的是建立一个对象与另一个对象之间的父子关系,使得子对象可以拥有父级对象的属性和方法
3.JS中函数继承主要继承的是什么?可以继承函数体吗?为什么?
JS函数的继承主要继承的是函数名,没办法实现函数体继承
4.声明一个函数fn,对其使用typeof,结果返回什么?然后我给fn添加一个属性,请问会报错吗?为什么?
结果返回是function字符串。添加属性不会报错,因为在js中,函数并不是真正的函数,function本身是一个object对象,而对象是可以添加属性和方法的,所以不会报错
5.定义一个字符串,对这个字符串使用typeof,结果返回什么?既然返回结果是string,而属性和方法是对象才有的,那为什么会在我定义的字符串上可以使用split,join(),length等方法和属性?(作用域问题)
字符串形式的string,
全局环境存在在简单数据类型的对象,String对象就是其中一个,所有的字符串都是这个对象的实例,当我们对字符串使用方法和属性时,其实字符串本身并没有对应的方法,这个时候,JavaScript会沿着作用域链往上寻找,最终在对象String上找到了对应的方法和属性,而这个过程对于开发者是无感的,所以看上去像是调用了字符串本身的方法
6. 什么是闭包?
闭包的实质是因为函数嵌套而形成的作用域链
比如说:函数 A 内部有一个函数 B,函数 B 可以访问到函数 A 中的变量,那么函数 B 就是闭包
用途:使用闭包主要是为了设计私有的方法和变量
优点:可以避免变量被全局变量污染
缺点:函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包
解决方法:在退出函数之前,将不使用的局部变量全部删除
7. 数组去重
// 去除数组的重复成员 [...new Set([1, 2, 2, 3, 4, 5, 5])]; // [1, 2, 3, 4, 5]
8. 原型和原型链
每个"构造函数"中都有一个默认的属性, 叫做 prototype, prototype属性保存着一个对象, 这个对象我们称之为"原型对象", prototype 指向它的原型对象
每个"原型对象"中都有一个默认的属性, 叫做constructor, constructor 指向当前原型对象对应的那个"构造函数"
通过构造函数创建出来的对象我们称之为"实例对象", 每个"实例对象"中都有一个默认的属性, 叫做__proto__, __proto__
指向创建它的那个构造函数的"原型对象"
基本关系
1. 所有函数都是Function构造函数的实例对象
2. 所有函数都是对象, 包括Function构造函数
3. 所有对象都有__proto__属性
4. 普通对象的__proto__属性指向创建它的那个构造函数对应的"原型对象"
复制代码
特殊关系
5. 所有对象的__proto__属性最终都会指向"Object原型对象"
6. "Object原型对象"的__proto__属性指向NULL
复制代码
对象中__proto__组成的链条我们称之为原型链
对象在查找属性和方法的时候, 会先在当前对象查找, 如果有就用自己的
如果当前对象中找不到想要的, 会依次去上一级原型对象中查找
如果找到Object原型对象都没有找到, 就会报错
9.typeof与instanceof区别
typeof
在判断null
、array
、object
以及函数实例(new + 函数)
时,得到的都是object
instanceof它的判断就是根据原型链进行搜寻,在对象obj1的原型链上如果存在另一个对象obj2的原型属性,那么表达式(obj1 instanceof obj2)返回值为true;否则返回false
它的判断就是根据原型链进行搜寻,在对象obj1的原型链上如果存在另一个对象obj2的原型属性,那么表达式(obj1 instanceof obj2)返回值为true;否则返回false
9.如何区分深拷贝与浅拷贝
9.如何区分深拷贝与浅拷贝
简单点来说,就是假设B复制了A,当修改A时,看B是否会发生变化,如果B也跟着变了,说明这是浅拷贝,拿人手短,如果B没变,那就是深拷贝
用JSON对象的parse和stringify来进行深拷贝
function deepClone(obj){ let _obj = JSON.stringify(obj), objClone = JSON.parse(_obj); return objClone } let a=[0,1,[2,3],4], b=deepClone(a); a[0]=1; a[2][0]=1; console.log(a,b);
这样的话b,完全不受a的影响
10.如何区分深拷贝与浅拷贝
10.如何区分深拷贝与浅拷贝
搜索框搜索输入。只需用户最后一次输入完,再发送请求防抖函数:就是指触发事件后在 n 秒内函数只能执行一次,如果在 n 秒内又触发了事件,则会重新计算函数执行时间 eg:
节流函数:限制一个函数在一定时间内只能执行一次。eg:滚动加载,加载更多或滚到底部监听
11.函数柯里化
11.函数柯里化
主要是实现参数的复用性
12.
ES5继承和ES6继承
12.
ES5继承
- 在子类中通过call / apply方法借助父类的构造函数
- 将子类的原型函数设置为父类的实例对象
ES6继承
- 通过子类extends父类, 来告诉浏览器子类要继承父类
- 通过super()方法修改 this
HTML篇:
1 . 从输入 URL 到页面加载完成的过程中都发生了什么
1. 浏览器会进行DNS域名解析,拿到域名对应的服务器ip地址,再用该ip去访问web服务器 2. 然后会和web服务器进行tcp的三次握手建立tcp连接 3. 连接建立成功后,浏览器会发送http的get请求 4. 服务器收到请求并给予响应,返回请求的数据 5. 浏览器拿到数据并进行解析、渲染 6. 浏览器和服务器进行tcp的四次挥手,断开连接
2. 请介绍一下回流(Reflow)与重绘(Repaint)
回流:当我们对 DOM 的修改引发了 DOM 几何尺寸的变化(比如修改元素的宽、高或隐藏元素等)时, 浏览器需要重新计算元素的几何属性(其他元素的几何属性和位置也会因此受到影响), 然后再将计算的结果绘制出来。这个过程就是回流(也叫重排)。
重绘:当我们对 DOM 的修改导致了样式的变化、却并未影响其几何属性(比如修改了颜色或背景色)时, 浏览器不需重新计算元素的几何属性、直接为该元素绘制新的样式(跳过了上图所示的回流环节)。这个过程叫做重绘。
由此我们可以看出,重绘不一定导致回流,回流一定会导致重绘。 硬要比较的话,回流比重绘做的事情更多,带来的开销也更大。但这两个说到底都是吃性能的, 所以都不是什么善茬。我们在开发中,要从代码层面出发,尽可能把回流和重绘的次数最小化。
2.get和post的区别
get是url传参,然后post是body里,get更快,但体积安全性都小,但是post则相反。
get和post本质上没有区别,都是tcp链接,但是get方法会吧header和data一起发送出去,但是post会先发送header,在发送data
css篇:
1.我有一段文字,但不知道多长,如何实现单行文本居中,多行文本居左显示?
display: flex;
flex-direction: row;
justify-content: center;
2. 介绍一下 CSS 的盒子模型?
有两种, IE 盒子模型、W3C 盒子模型;
盒模型: 内容(content)、填充(padding)、边界(margin)、 边框(border);
区 别: IE 的 content 部分把 border 和 padding 计算了进去;
vue篇:
1. Vue是如何实现双向数据绑定的(Vue双向数据绑定原理)
mvvm 双向绑定,采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()
来劫持各个属性的 setter、getter,在数据变动时发布消息给订阅者,触发相应的监听回调。
Vue主要通过以下4个步骤实现数据双向绑定:
1、实现一个数据监听器 Observer,能够对数据对象的所有属性进行监听,如有变动可拿到最新值并通知订阅者
2、实现一个指令解析器 Compile,对每个元素节点的指令进行扫描和解析,根据指令模板替换数据,以及绑定相应的更新函数
3、实现一个订阅者 Watcher,作为连接 Observer 和 Compile 的桥梁,能够订阅并收到每个属性变动的通知,执行指令绑定的相应回调函数,从而更新视图
4、最后实现 MVVM 作为数据绑定的入口,整合监听器、解析器和订阅者
8. 你对Vue项目进行了哪些优化
- 不在模板里面写过多表达式
- 循环调用子组件时添加key
- 频繁切换的使用v-show,不频繁切换的使用v-if
- 尽量少用float,可以用flex
- 按需加载,可以用require或者import()按需加载需要的组件
- 路由懒加载