面试回顾
1.基本数据类型
答:基本数据类型有string,null,number,symbol,undefined,boolean。
2.string和object的区别
答:string是基本数据类型,object是引用数据类型。基本数据类型是储存于栈中,引用数据类型存储于堆中。
string用于表示0或者多个16位unicode字符组成的字符序列。对象就是一组数据和功能的集合。
3.function和箭头函数的区别
- 写法不一样
function test(a,b){
return a-b;
}
var test2 = (a,b)=>{
return a-b;
}
- this指向不一样
// function的this指向在调用的时候才知道指向谁,是不固定的
function test(){
console.log(this);
}
test(); //Window {postMessage: ?, blur: ?, focus: ?, close: ?, frames: Window, …}
var obj = {aa:test};
obj.aa(); //{aa: ?}
// 箭头函数没有自己的this,它里面的this是继承所属上下文中的this,所以this指向是固定的
var test1 = () =>{
console.log(this);
}
test1(); //Window {postMessage: ?, blur: ?, focus: ?, close: ?, frames: Window, …}
var obj1 = {bb:test1};
obj1.bb(); //Window {postMessage: ?, blur: ?, focus: ?, close: ?, frames: Window, …}
- function可以作为构造函数,但是箭头函数不行
function test(){
console.log(‘1‘);
}
let t = new test(); //1
//箭头函数没有prototype,constructor在prototype中,所以不能使用new生成构造函数
var test1 = ()=>{
console.log(‘2‘);
}
let t1 = new test1(); //test1 is not a constructor
- function可以先调用再定义,箭头函数不行
test(); //1
function test(){
console.log(‘1‘);
}
test1(); //Uncaught TypeError: test1 is not a function
//用箭头函数定义函数的时候,需要var(let const定义的时候更不必说)关键词,而var所定义的变量不能得到变量提升,故箭头函数一定要定义于调用之前!
function test1(){
console.log(‘2‘);
}
4.箭头函数为什么不能使用new
new一个实例的过程
function New(fc){
//1.创建一个新的对象
let newObj = {};
//2.将对象的_proto_指向函数的prototype
if(fc.prototype!==null){
newObj.__proto__=fc.prototype;
}
//3.调用apply或者call方法,将步骤1新创建的对象作为this的上下文
let res = fc.apply(newObj,Array.prototype.slice.call(arguments,1));
if((typeof res === ‘object‘|| typeof res === ‘function‘) && res!==null){
return res;
}
//4.如果该函数没有返回对象,则返回this
return newObj;
}
function A(){
return 1;
}
var B = () => {
return 1;
}
console.log(New(A))
console.log(New(B)) // 箭头函数没有自己的原型prototype,没有this指向
5.callback
回调函数,把函数作为参数传给另一个函数进行调用,一般来说,只要参数是一个函数,那么这个函数就是回调。
- 异步调用(例如读取文件,进行HTTP请求,动态加载js文件,图片加载完成后进行回调)
- 事件监听器、处理器
$button.on(‘click‘, function(){})
- setTimeout、setInterval方法
6.call和apply
call和apply 都是用来修改函数中this的指向问题
不同的是传参方式,call方法可以传多个参数,apply方法只能将多个参数合成一个数组作为参数
var name = ‘windowName‘
var age = ‘windowAge‘
var person = {
name : ‘personName‘,
age : ‘personAge‘,
getPerson : function(){
return this.name + ‘ ‘ + this.age;
},
setPerson : function(name, age){
return name + ‘ ‘ + age;
}
}
var person1 = {
name : ‘person1Name‘
}
console.log(person.getPerson()); //personName personAge
// 使用call和apply,不传任何参数,默认指向windows
console.log(person.getPerson.call())//windowName windowAge
console.log(person.getPerson.apply())//windowName windowAge
// 有参数时,this指向第一个参数
console.log(person.getPerson.call(person))//personName personAge
console.log(person.getPerson.apply(person1))//person1Name undefined
// 当需要传递参数时,call可以直接写多个参数,apply需要用数组方式传递
console.log(person.setPerson.call(person,‘callName‘,‘callAge‘)) //callName callAge
console.log(person.setPerson.apply(person1,[‘applyName‘,‘applyAge‘])) //applyName applyAge
//当参数超过3个时,call会比apply性能好
//call 方法比 apply 快的原因是方法的参数格式正是内部方法所需要的格式。
7.前端的性能优化
-
减少网络连接
- 合并文件
- 对图片进行处理(雪碧图-将多个图片合成一张图片;Base64-将图片的内容以base64的形式嵌在HTML中;使用icon小图标)
- 减少重定向(当不得不重定向,使用301永久重定向,减少请求次数)
- 使用缓存(使用cath-control或者expired这类强缓存,缓存不过期的情况下,直接从缓存中读取;当缓存过期,可以使用etag或者last-modified这类协商缓存,向服务器发送请求,如果资源没变化,直接从缓存读取,返回304;如果资源更新了,服务器将更新之后的内容发给浏览器,返回200
- 避免使用空的src或者href(链接空的href会导致重定向到当前页面)
-
减小资源大小
- 压缩(对HTML,CSS,JS,图片等进行压缩
- 使用gzip进行压缩
-
优化网络连接
- 使用DNS预解析(提前解析域名,将结果缓存在系统缓存中,减少解析域名的时间)
<link rel=‘dns-prefetch‘ href=‘www.baidu.com‘>
- 持久连接(使用connect:keep-alive进行持久连接)
- 使用DNS预解析(提前解析域名,将结果缓存在系统缓存中,减少解析域名的时间)
-
优化资源加载
- 资源加载的位置(css文件放在head中,先外链,后内部;js文件放在body下,先外链,后内部;避免在body中使用style和script)
- 资源加载的时机(异步script标签-async,资源懒加载和预加载,模块按需加载)
- 懒加载:可视区加载,条件加载,纯粹延时加载
- 预加载:preload 加载页面必需的资源,prefetch 预测加载下一屏数据
-
减少重绘回流
-
样式设置(避免使用很多层的选择器,减少使用table布局;避免使用CSS表达式;尽量给图片、元素设置宽高;使用css实现效果而不使用js)
-
DOM优化
-
缓存DOM节点
let div = document.getElementById(‘app‘)
-
减少DOM的深度和数量
-
批量操作DOM或者CSS样式
-
防抖(debounce)和节流(throttle)
-
function debounce(fc,wait){ let timer; return function(){ var self = this; if(timer!==null) clearTimeout(timer); timer = setTimeout(function(){ fc.apply(self); },wait) } }
-
function throttle(fc,wait){ let canRun = true; return function(){ if(canRun){ canRun = false; fc.apply(this,arguments); serTimeout(function(){ canRun = true; },wait) } } }
-
-
-
-
使用较好的API
- 选择对的选择器(id > 类/属性/伪类 > 标签/为元素)
- id选择器(#app)
- 类选择器(.content)
- 标签选择器(div,p)
- 相邻选择器(div+p)
- 子类选择器(ul > li)
- 后代选择器(li a)
- 通配选择器(*)
- 属性选择器(a[rel="external"])
- 伪类选择器(a:hover,li:nth-child)
- 伪元素选择器(div::before,li:first-letter)
- 使用web worker(Web Worker是HTML5提供的一个javascript多线程解决方案)
- 选择对的选择器(id > 类/属性/伪类 > 标签/为元素)
-
webpack优化
- 打包公共组件
- 动态加载和按需导入
8.输入域名这个过程会发生什么
- DNS解析
- TCP连接
- 发送http请求
- 服务器收到请求回应http报文
- 浏览器渲染http
- 关闭TCP连接