前端面试题预热

html

css

选择器的优先级

!important

内联(1,0,0,0)

id: (0,1,0,0)

类:(0,0,1,0)

伪类/属性

元素:(0,0,0,1)

通配符

画出一个下三角

.triangle{
	 width: 0;
	 height: 0;
	 border-bottom: 200px solid pink;
	 border-left: 200px solid transparent;
	 border-right: 200px solid transparent;
 }

水平竖直居中

position 元素已知宽度,距上50%,据左50%,然后减去元素自身宽度的距离就可以实现

div class="box">
    <div class="content">
    </div>
</div>
 
.box {
    background-color: #FF8C00;
    width: 300px;
    height: 300px;
    position: relative;
}
.content {
    background-color: #F00;
    width: 100px;
    height: 100px;
    position: absolute;
    left: 50%;
    top: 50%;
    margin: -50px 0 0 -50px;
}

position transform 元素未知宽度

<div class="box">
    <div class="content">
    </div>
</div>
 
.box {
    background-color: #FF8C00;
    width: 300px;
    height: 300px;
    position: relative;
}
.content {
    background-color: #F00;
    width: 100px;
    height: 100px;
    position: absolute;
    left: 50%;
    top: 50%;
    transform: translate(-50%,-50%);
}

flex布局

<div class="box">
    <div class="content">
    </div>
</div>
 
.box {
    background-color: #FF8C00;
    width: 300px;
    height: 300px;
    display: flex;//flex布局
    justify-content: center;//使子项目水平居中
    align-items: center;//使子项目垂直居中
}
.content {
    background-color: #F00;
    width: 100px;
    height: 100px;
}

margin布局

.content{
	 width: 400px;
	 height:400px;
	 position:absolute;
	 left:0;
	 right:0;
	 top:0;
	 bottom:0;
	 margin:auto;
	 background-color: salmon;
}

table-cell布局

内容引用

js

let const

let const var的区别

varletconst
全局作用域块作用域块作用域
存在变量提升不存在变量提升不存在变量提升
值可变值可变值不可变

值和引用

值在栈中保存 上->下
引用在堆中保存 下->上

深拷贝

问题:一个对象复制为另一个对象的时候,由于存放在堆区(具体再看),因此改变复制对象后原对象也会发生变换,因此需要深拷贝。
思路:
  1.首先判断该变量类型是否为对象,不是则直接return
  2.然后判断该变量类型为数组还是对象,创建相应的空的变量。
  3.循环遍历一下对象的内容,如果都是他的本身属性(非原型属性),那么就递归调用该函数实现深拷贝。由于到末端的值都不为对象,因此在递归的时候会return出去然后赋值给上级的key,完成深拷贝。

ES6新增浅拷贝语法糖Object.assign(target,...sources)

const obj1={
  name:'张三',
  age:18,
  address:{
    city:'上海'
  },
  arr:['a','b','c']
}

const obj2=deepClone(obj1)
obj2.address.city="北京"
console.log('obj1是'+obj1.address.city, '')
console.log('obj2是'+obj2.address.city, '')

function deepClone(obj) {
  if(typeof obj !=='object'||obj==null){
    return obj
  }
  let res 
  // 判断是否为数组
  if(obj instanceof Array){
    res=[]
  }else{
    res ={}
  }
  for(let key in obj){
    // 保证key不是原型的属性
    if(obj.hasOwnProperty(key)){
      // 递归调用 防止深层次的东西没有复制过来
      res[key]=deepClone(obj[key])
    }
  }
  return res
}

另一种写法

const obj1={
  name:'张三',
  age:18,
  address:{
    city:'上海'
  },
  arr:['a','b','c']
}

function deepCopy(newObj,oldObj){
  // 循环遍历老对象赋值给新对象
  for(var k in oldObj){
    // 获取老对象的值
    var item=oldObj[k]
    if(item instanceof Array){
      newObj[k]=[];
      return deepCopy(newObj[k],item)
    }else if(item instanceof Object){
      newObj[k]={};
      return deepCopy(newObj[k],item)
    }else{
      newObj[k]=item
    }
  }
}
var o={}
deepCopy(o,obj1)
// console.log(o);

字符串拼接

问题

  1. typeof能判断哪些类型
    值类型 函数 引用
  2. 何时使用 === 以及 ==
    除了null之外
  3. 值类型与引用类型的区别
  4. 深拷贝

原型

每个构造函数都有一个原型对象,来存放所有对象所共享方法
一般的,公共属性会用构造函数定义,而公共方法却用函数的原型对象存放。

    function person(name,age){
      this.name=name;
      this.age=age;
      // this.sing=function() {
      //   console.log(name+'我会唱歌');
      // }
    }
    // 原型对象
    person.prototype.sing=(name)=>console.log(name+'我会唱歌');
    var zys=new person('张三','18');
    console.log(zys);
    zys.sing(zys.name);

继承

  • extend 继承父类
  • super 执行父类构造
  • instanceof为类型判断
    在这里插入图片描述 每个构造函数/class(ES5没有类的概念)都有显式原型 prototype
    每个实例都有隐式原型__ proto __,指向prototype
    隐式原型指向显式原型,隐式找不到就去显式去找
    (原型存放方法)
    __ proto __与prototype都有一个constructor属性,指回构造函数本身。

原型对象的this指向:无论是对象还是构造函数的this都指向被调用的实例对象。

// 利用原型对象扩展内置对象方法
Array.prototype.sum=function(){
      var sum=0;
      for(var i=0;i<this.length;i++){
        sum+=this[i];
      }
      return sum;
    }
    var arr=[1,2,3];
    console.log(arr.sum(), '求和');
    console.log(Array.prototype)

原型链

构造函数.prototype===obj.__ proto __

父.prototype===子.prototype.__ proto __

在这里插入图片描述
hasOwnProperty() //验证是否为自身属性
在这里插入图片描述
问题

  1. 判断一个变量是否为数组
    instanceof Array
  2. 手写简易的jquery
    没搞懂
class jQuery {
    constructor(selector) {
        const result = document.querySelectorAll(selector)
        const length = result.length
        for (let i = 0; i < length; i++) {
            this[i] = result[i]
        }
        this.length = length
        this.selector = selector
    }
    get(index) {
        return this[index]
    }
    each(fn) {
        for (let i = 0; i < this.length; i++) {
            const elem = this[i]
            fn(elem)
        }
    }
    on(type, fn) {
        return this.each(elem => {
            elem.addEventListener(type, fn, false)
        })
    }
    // 扩展很多 DOM API
}

// 插件
jQuery.prototype.dialog = function (info) {
    alert(info)
}

// “造轮子”
class myJQuery extends jQuery {
    constructor(selector) {
        super(selector)
    }
    // 扩展自己的方法
    addClass(className) {

    }
    style(data) {
        
    }
}

// const $p = new jQuery('p')
// $p.get(1)
// $p.each((elem) => console.log(elem.nodeName))
// $p.on('click', () => alert('clicked'))

3.class原型本质

作用域

  • 函数内部可以使用全局变量
  • 函数外部不能使用局部变量
  • 执行完毕后变量被销毁

闭包

闭包是指有权访问另一个函数作用域中的变量的函数
被访问的变量所在函数就是闭包函数。
作为参数被传入以及作为返回值返回,返回值返回可以通过闭包在全局调用局部变量,延伸了变量的作用范围。
案例1.

    // 点击li输出li的索引
    // 1.利用动态添加属性的方式
    var lis=document.querySelector('.nav').querySelectorAll('li')
    for(var i=0;i<lis.length;i++){
      lis[i].index=i;
      lis[i].onclick=function(){
        console.log(this.index);
      }
    }
    // 2.利用闭包的方式 不点的话就不会销毁,容易内存泄漏
    for(var i=0;i<lis.length;i++){
      (function(i) {
        // console.log(i);
        lis[i].onclick=function(){
          console.log(i);
        }
      })(i);
    }

案例2.

	var lis=document.querySelector('.nav').querySelectorAll('li')
    // 打印所有li内容
    for(var i=0;i<lis.length;i++){
      (function(i){
        setTimeout(() => {
          console.log(lis[i].innerHTML);
        }, 2000);
      })(i);
    }

自由变量的查找,是在函数定义的地方,向上级作用域查找,而不是在执行的地方。

this

取值是在执行时确认,而不是定义
应用场景:

  • 普通函数调用
  • .call apply bind
    • call()、apply()、bind() 都是用来重定义 this 这个对象的,可以改变this的指向
    • 区别:
          1. call的参数后边挨着放。call(obj,params1,params2)。
          用途:可以实现继承。
          2. apply的参数第二个在数组中。call(obj,[‘params1’,‘params2’])。
          用途:将传递的参数数组转化为相应类型,可对数组进行操作。求最大值。
          3. bind的参数同第一个但是后边得加()到新的函数。call(obj,params1,params2)()
          用途:不立即调用。禁用按钮,三秒后开启。
// call实现继承属性
function Father(name,age){
      this.name=name;
      this.age=age;
    }
    function Son(name,age,score) {
      Father.call(this,name,age);
      this.score=score;
    }
    var son=new Son('张三',18)
    console.log(son)
// call实现继承方法
function Father(name,age){
      this.name=name;
      this.age=age;
    }
    Father.prototype.money=function(){
      console.log(100000);
    }
    function Son(name,age,score) {
      Father.call(this,name,age);
      this.score=score;
    }
    // Son.prototype=Father.prototype //不能这么做,会把子方法赋给父方法
    Son.prototype=new Father();
    // 利用对象的形式修改了原型对象,别忘了利用constructor来指向原来了构造函数
    Son.prototype.constructor=Son;
    Son.prototype.exam=function(){
      console.log(100);
    }
    var son=new Son('张三',18)
    console.log(son)
// apply求最大值
var arr=[1,2,4,5,1,2,3,6];
var max=Math.max.apply(Math,arr);
console.log(max);
// bind禁用按钮
var btn=document.querySelector('button');
btn.onclick=function(){
	this.disabled=true;
	var that=this;
	setTimeout(function(){
		// 定时器的this指向window
		// this.disabled=false;
		// 此时this是bind绑定的btn对象
		this.disabled=false;
		// 可以这么做
		// that.disabled=false;
	// 这么做最好
	}.bind(this),3000)
}

JavaScript 中 call()、apply()、bind() 的用法

  • .对象方法调用
  • class的方法中调用
  • 箭头函数(指向上一级的this)

问题

  1. this在不同场景下如何取值
  2. 手写bind函数

函数内的this指向

调用方式this指向
普通函数调用window
构造函数调用实例对象,原型对象方法也指向实例对象
对象方法调用方法所属对象
事件绑定方法绑定事件对象
定时器函数window
立即执行函数window
// 模拟 bind
Function.prototype.bind1 = function () {
    // 将参数拆解为数组
    const args = Array.prototype.slice.call(arguments)

    // 获取 this(数组第一项)
    const t = args.shift()

    // fn1.bind(...) 中的 fn1
    const self = this

    // 返回一个函数
    return function () {
        return self.apply(t, args)
    }
}
  1. 闭包应用场景
      隐藏数据,只提供API。比如一个类的数据不能被外界修改
  2. 作用域和自由变量
  3. 闭包
  4. this

继承

原型链继承

  • 让新实例的原型等于父类的实例。

构造函数继承

  • 用.call()和.apply()将父类构造函数引入子类函数

组合继承(组合原型链继承和借用构造函数继承)(常用)
寄生式继承
寄生组合式继承
class继承-extends

引用链接

引用链接

单线程

js是单线程语言
js与DOM渲染之能用一个线程

异步

不会阻塞代码执行
使用场景

  • 网络请求
  • .定时任务

回调地狱callback hell
ajax异步调用接口不会顺序执行

 $.ajax({
      url:'http://localhost:3000/data',
      success:function(data){
        console.log(data)
      }
    })
    $.ajax({
      url:'http://localhost:3000/data1',
      success:function(data){
        console.log(data)
      }
    })
    $.ajax({
      url:'http://localhost:3000/data2',
      success:function(data){
        console.log(data)
      }
    })

解决方式为

$.ajax({
      url:'http://localhost:3000/data',
      success:function(data){
        console.log(data)
        $.ajax({
          url:'http://localhost:3000/data1',
          success:function(data){
            console.log(data)
            $.ajax({
              url:'http://localhost:3000/data2',
              success:function(data){
                console.log(data)
              }
            })
          }
        })
      }
    })

此方式容易容易造成回调地狱

问题
1.同步和异步的区别
2.手写promise加载图片

function loadImg(src) {
    const p = new Promise(
        (resolve, reject) => {
            const img = document.createElement('img')
            img.onload = () => {
                resolve(img)
            }
            img.onerror = () => {
                const err = new Error(`图片加载失败 ${src}`)
                reject(err)
            }
            img.src = src
        }
    )
    return p
}
const url1 = 'https://img.mukewang.com/5a9fc8070001a82402060220-140-140.jpg'
const url2 = 'https://img3.mukewang.com/5a9fc8070001a82402060220-100-100.jpg'
loadImg(url1).then(img1 => {
    console.log(img1.width)
    return img1 // 普通对象
}).then(img1 => {
    console.log(img1.height)
    return loadImg(url2) // promise 实例
}).then(img2 => {
    console.log(img2.width)
    return img2
}).then(img2 => {
    console.log(img2.height)
}).catch(ex => console.error(ex))

3.异步使用场景
  网络请求
  定时任务

Promise

promise为对象,它可以获取异步操作的消息。

promise实例

// 实例promise
var p=new Promise(function(resolve,reject){
  // 成功时调用resolve()
  // 失败时调用reject()
  setTimeout(() => {
    var flag=true;
    if(flag){
      // 正常情况
      resolve('hello')
    }else{
      reject('出错了')
    }
  }, 2000);
})
p.then(function(data){
  console.log(data);
},function(info){
  console.log(info);
})

基于promise方式处理ajax调用接口

function queryData(url){
  var p=new Promise(function(resolve,reject){
     var xhr= new XMLHttpRequest();
     xhr.onreadystatechange=function(){
       if(xhr.readyState!=4)return;
       if(xhr.readyState==4&&xhr.status==200){
         //处理正常的情况
         resolve(xhr.responseText)
       }else{
         reject('服务器错误')
       }
     }
     xhr.open('get',url)
     xhr.send(null)
   })
   return p;
 }
 queryData('http://localhost:3000/data')
 .then(function(data){
   console.log(data);
 },function(info){
   console.log(info);
 })

多次ajax请求

// 发送多个ajax请求且保证顺序
queryData('http://localhost:3000/data')
.then(function(data){
  console.log(data);
  return queryData('http://localhost:3000/data1')
})
.then(function(data){
  console.log(data);
  return queryData('http://localhost:3000/data2')
})
.then(function(data){
  console.log(data);
})

接口

const express=require('express')

const app=express()

const cors=require('cors')
app.use(cors())


app.get('/data',(req,res)=>{
  res.send('hello world1')
})
app.get('/data1',(req,res)=>{
  res.send('hello world2')
})
app.get('/data2',(req,res)=>{
  res.send('hello world3')
})

app.listen(3000,()=>{
  console.log('welcome to http://localhost/3000')
})

then参数的打印结果(上一个实例的返回值获得的结果)

  1. 返回上一个对象的结果
  2. 返回上一个对象的字符串,默认的promise

Promise常用API

  • 实例方法
操作说明
.then()得到异步任务的正确结果
.catch()获取异常信息
.finally()成功与否都会执行
function foo(){
  return new Promise(function(resolve,reject){
    setTimeout(() => {
      // resolve(123)
      reject('错误')
    }, 1000);
  })
}
foo(function(data){
  console.log(data);
}).then(function(data){
  console.log(data);
}).catch(function(data){
  console.log(data);
}).finally(function(){
  console.log('finished');
})
  • 对象方法
操作说明
.all()得并发执行所有异步任务,执行完成才得到结果
.race()得并发执行所有异步任务,只要有一个完成就能得到结果
var p1=queryData('http://localhost:3000/a1')
var p2=queryData('http://localhost:3000/a2')
var p3=queryData('http://localhost:3000/a3')

Promise.all([p1,p2,p3]).then(function(result){
  // 得到全部结果
  console.log(result);
})
Promise.race([p1,p2,p3]).then(function(result){
  // 只得到一个结果
  console.log(result);
})

原博客园链接(本人)

vue

v-bind原理

<div id="app">
    <span>{{message}}</span><br>
    <input type="text" v-bind:value="message" v-on:input="handle"><br>
    <input type="text" v-bind:value="message" v-on:input="message=$event.target.value"><br>
    <input type="text" v-model="message"><br>
  </div>
  <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
  <script>
    var app = new Vue({
      el: '#app',
      data: {
        message: 'Hello Vue!'
      },
      methods:{
        handle:function(event){
          this.message=event.target.value
        }
      }
    })
  </script>

子父组件传值

父组件向子组件传值

  1. 在父组件引入子组件
Vue.component('son-item',{
    // props:['title'],
    data(){
      return {
        submsg:'子组件数据'
      }
    },
    template:'<div>{{submsg+"---"+title}}</div>'
 })
  1. 父组件调用子组件
// 静态属性绑定
<son-item title="来自父组件的值"></son-item>
// 动态绑定
<son-item :title="msg"></son-item>
  1. 子组件引入props
// 使父组件的值可以在子组件使用
props:['title']

props命名规则

  • 在props中使用驼峰,在模板中使用短横线
  • 字符串模板无区分

子组件向父组件传值

通过自定义事件向父组件传递事件

  1. 子组件自定义事件
// 子组件
template:`<button @click="$emit('enlarge-text')">{{fTitle}}</button>`
  1. 父组件监听子组件事件
<span :style="{fontSize:fontSize+'px'}">{{msg}}</span>
<son-item :f-title="msg" @enlarge-text="handle"></son-item>
var app = new Vue({
  el: '#app',
  data: {
    msg: '父组件数据',
    // 字体大小数值
    fontSize:10
  },
  methods: {
  // 定义改变字体大小方法
    handle(){
      this.fontSize+=3
    }
  },
})

通过自定义事件向父组件传递参数

  1. 子组件自定义事件
// 传递参数
template:`<button @click="$emit('enlarge-text',5)">{{fTitle}}</button>`
  1. 父组件监听子组件事件
// $event为固定用法,代表传递过来的值
<son-item :f-title="msg" @enlarge-text="handle($event)"></son-item>
methods: {
  handle(val){
    this.fontSize+=val
  }
}

事件中心

  1. 定义两个子组件
Vue.component('test-tom',{
data(){
  return{
    num:0
  }
},
template:`
  <div>
    <div>TOM:{{num}}</div>
    <div>
      <button @click="handle">点击</button>
    </div>
  </div>
`,
methods: {
  handle(){
    hub.$emit('tom-event',1)
  }
},
mounted () {
  hub.$on('tom-event',(val)=>{
    // val为兄弟组件传的值
    this.num+=val
  });
}
})
Vue.component('test-jerry',{
data(){
  return{
    num:0
  }
},
template:`
  <div>
    <div>JERRY:{{num}}</div>
    <div>
      <button @click="handle">点击</button>
    </div>
  </div>
`,
methods: {
  handle(){
    hub.$emit('jerry-event',2)
  }
},
mounted () {
  hub.$on('jerry-event',(val)=>{
    // val为兄弟组件传的值
    this.num+=val
  });
}
})
  1. 调用子组件
<test-tom></test-tom>
<test-jerry></test-jerry>
  1. 定义事件中心
// 事件中心
var hub=new Vue();
  1. 监听事件中心
mounted () {
  hub.$on('jerry-event',(val)=>{
    // val为兄弟组件传的值
    this.num+=val
  });
}

销毁事件

handle(){
  hub.$off('tom-event')
  hub.$off('jerry-event')
}

组件插槽
具名插槽
在子组件的模板中放<slot></slot>
在父组件中组件中间可以放值=>传递给solt

高级用法可以给插槽一个属性值,可以根据属性名调用相应插槽

作用域插槽

父组件对子组件的数据进行加工

<template slot-scope="slotProps">
</template>

子父组件传值

methods/computed/watch区别

名称区别应用场景举例
methods无缓存
computed有缓存,避免消耗,可以直接使用一个数据受多个数据影响购物车结算
watch必须在data中先声明异步,开销较大,一个数据影响多个数据搜索框
  • 功能上:

    • computed是计算属性
    • watch是监听一个值的变化,然后执行对应的回调。
  • 是否调用缓存:

    • computed中的函数所依赖的属性没有发生变化,那么调用当前的函数的时候会从缓存中读取。
    • watch在每次监听的值发生变化的时候都会执行回调。
  • 是否调用return:

    • computed中的函数必须要用return返回。
    • watch中的函数不是必须要用return。
  • 使用场景:

    • computed:当一个属性受多个属性影响的时候,使用computed-------购物车商品结算。
    • watch:当一条数据影响多条数据的时候,使用watch-------搜索框。

内容引用

手写promise

手写promise

计算机网络

http与https的区别

http:超文本传输协议

https : 安全的超文本传输协议, 在 HTTP 协议基础上加入了 SSL 协议保证安全传输。

SSL 协议依靠证书来验证服务器的身份,并为浏览器和服务器之间的通信加密。

区别:

HttpHttps
证书CA证书,交费使用
协议超文本传输协议,明文SSL加密传输协议,安全
端口号不同80443
链接方式无状态链接由 SSL+HTTP 协议构成的可进行 加密传输,身份认证的网络协议

原文引用

tcp/ip协议(三次握手四次挥手)

引用链接

响应状态码

200 成功 post get
201 新建成功 post put

301 永久移动
302 临时移动
304 无修改,在客户端缓存调取数据

400 客户端语义有误,参数有误
401 需要验证权限
403 拒绝访问
404 无此资源
408 请求超时

500 服务器错误
501 服务器无此请求方法
503 服务器无法处理,维护或者超载

cookie&session&jwt

cookie认证机制
在这里插入图片描述
session的认证机制
在这里插入图片描述
JWT(JSON Web Token)认证机制
session身份认证需要结合cookie,因为cookie不支持跨域,如果前后端跨域,则使用jwt进行前后端身份认证。
在这里插入图片描述
组成部分:Header.Payload.Signature
Header Signature:确保Token的安全性
Payload:加密信息

在服务器生成并返回Token之后,通常会存储在客户端的localStorage或者sessionStorage中
每次请求都要将该字符串放在http请求头的Authorization字段中
Authorization:Bearer <token>

访问一个网页的全过程

域名解析成IP地址
与目的主机进行TCP连接(三次握手)
发送与收取数据(浏览器与目的主机开始HTTP访问过程)
与目的主机断开TCP连接(四次挥手)

引用链接

跨域

同源策略会阻止一个域的javascript脚本和另外一个域的内容进行交互。所谓同源(即指在同一个域)就是两个页面具有相同的协议(protocol),主机(host)和端口号(port)

当一个请求url的协议、域名、端口三者之间任意一个与当前页面url不同即为跨域

引用链接

get post

在这里插入图片描述

性能优化

SEO优化

  • 好的域名
  • 好的标题
  • 网页结构优化
  • 关键字,描述优化
  • 友情链接优化

性能优化

  • 减少http请求
    • 资源合并与压缩:合并CSS和JS文件;图片较多的页面也可以使用 lazyLoad 等技术进行优化。
    • 设置 HTTP缓存:缓存的力量是强大的,恰当的缓存设置可以大大的减少 HTTP请求。
  • 请减少对DOM的操作
  • 使用JSON格式来进行数据交换
  • 精简Javascript和CSS,注意引用位置
  • 使用CDN(内容分发网络)
  • 压缩图片和使用图片Sprite技术
  • 减小cookie大小
  • 图片延迟加载
  • 缓存ajax‘

内容引用

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值