前端面试题记录

HTML面试题记录

HTML5新特性

  1. 语义化标签:比如 article、footer、header、nav、section;
  2. 表单控件:calendar、date、time、email、url、search;
  3. 媒体元素video和audio元素
  4. 本地存储:localStorage sessionStorage
  5. 新的技术,websocket

前端页面由哪三个部分组成

  • html:页面结构,布局
  • css:样式
  • js:行为交互

HTML和XHTML的区别

XHTML:重写了HTML规范,比HTML更严格

  1. XHTML中所有的标记都必须有一个相应的结束标签;

  2. XHTML所有标签的元素和属性的名字都必须使用小写;

  3. 所有的XML标记都必须合理嵌套;

  4. 所有的属性都必须用引号“”括起来;

  5. 把所有<和&特殊符号用编码表示;

  6. 给所有属性附一个值;

  7. 不要在注释内容中使用“–”;

  8. 图片必须使用说明文字。

canvas和svg的区别

canvas svg
通过js绘制2D图形,按像素进行渲染,当位置发生改变会重新进行绘制 使用XML绘制的2D图形,可以为元素添加js处理器
依赖分辨率 不依赖分辨率
不支持事件处理器 支持事件处理器
弱的文本渲染能力 最适合带有大型渲染区域的应用程序(如谷歌地图)
能以.png或.jpg格式保存结果图像 复杂度高会减慢渲染速度
最适合图像密集型游戏,其中的许多对象会被频繁重绘 不适合游戏应用

div+css布局和table布局有什么优点

  • 表现和结构分离

  • 页面加载速度更快,结构化清晰,页面显示简洁

  • 修改样式方便,只要改css文件

  • 易于优化,搜索引擎更友好

语义化的了解

正确的标签做正确的事

  • 内容结构化,结构更清晰

  • 便于搜索引擎解析

  • 便于阅读理解维护

src和href的区别

src: 引用资源,替换当前元素,用在img,script,iframe上

href: 在当前元素和引用资源建立联系,用在link和a等元素上

img标签的title和alt是什么

title:解释信息,鼠标移上去显示的信息

alt:替换信息、图片不能显示时的信息

块级元素、行内元素、行内块元素

块级元素

  • 特点:可设置宽高边距,占满整行,会自动换行

  • 示例:div、 p、 h1 、h6、ol、ul、dl、table、address、blockquote、form

行内元素:

  • 特点:无法设置宽高边距,不会占满整行,不会自动换行

  • 示例:a、strong、b、em、i、del、s、ins、u、span

行内块元素:

  • 特点:可设置宽高,占满整行,但不会自动换行

seo的TDK是什么

title description keywords

JS面试题记录

JS==以及===区别 在什么情况下使用

=====都是用于比较两个值是否相等的JS运算符,它们之间的主要区别在于它们的比较方式和类型转换。

==比较两个值是否相等时,会进行类型转换。如果两个值的数据类型不同,JS会尝试将它们转换为相同的类型,然后再进行比较。这种类型转换可能会产生一些意想不到的结果,例如:

console.log(1 == '1'); // true
console.log(true == 1); // true
console.log(null == undefined); // true

===比较两个值是否相等时,不会进行类型转换。只有当两个值的类型相同且值相等时,才会返回true,否则返回false。这种比较方式更为严格和安全,因为它可以避免类型转换带来的问题。

在一般情况下,建议使用===运算符进行比较。只有在确实需要进行类型转换时,才使用==运算符。例如,在比较两个值是否为null或undefined时,使用==比较更为方便:

if (value == null) {
  // 这里会同时匹配 null 和 undefined
}

需要注意的是,使用==比较时,要注意避免类型转换带来的意想不到的结果。如果不确定类型转换的结果,可以使用===进行比较,或者先显式地将值转换为相应的类型,再进行比较。例如:

console.log(Number('1') == 1); // true
console.log(Number('foo') == NaN); // false,NaN 不等于任何值,包括它本身
console.log(String(1) === '1'); // true

typeof 与 instanceof 区别

typeofinstanceof操作符都是用来判断数据类型的 但使用场景却各不相同。

typeof

typeof运算符返回一个字符串,表示操作数的类型

typeof operand
typeof(operand)

operand表示要返回类型的对象或基本类型的表达式

typeof 666 // 'number'
typeof '666' // 'string'
typeof undefined // 'undefined'
typeof true // 'boolean'
typeof Symbol() // 'symbol'
typeof null // 'object'
typeof [] // 'object'
typeof {} // 'object'

typeof可以精准的判断基本数据类型(null)除外

instanceof

instanceof 运算符用于检测构造函数的prototype属性是否出现在某个实例对象的原型链上
使用方法如下

object instanceof constructor

object 是指某个实例对象
constructor是指某个构造函数

// 定义构造函数
function C(){}
function D(){}

var o = new C();

o instanceof C; // true,因为 Object.getPrototypeOf(o) === C.prototype
o instanceof D; // false,因为 D.prototype 不在 o 的原型链上

o instanceof Object; // true,因为 Object.prototype.isPrototypeOf(o) 返回 true
C.prototype instanceof Object // true,同上

C.prototype = {};
var o2 = new C();

o2 instanceof C; // true

o instanceof C; // false,C.prototype 指向了一个空对象,这个空对象不在 o 的原型链上。

D.prototype = new C(); // 继承
var o3 = new D();
o3 instanceof D; // true
o3 instanceof C; // true 因为 C.prototype 现在在 o3 的原型链上

区别

typeof与instanceof 都是判断数据类型的方法,区别如下:

  • typeof会返回一个运算数的基本类型,instanceof 返回的是布尔值
  • instanceof 可以准确判断引用数据类型,但是不能正确判断原始数据类型
  • typeof虽然可以判断原始数据类型(null 除外),但是无法判断引用数据类型(function 除外)

eval是做什么的?

 非严格模式,可以将json字符串转换为对象的形式。也可将字符串参数转化为脚本代码执行,但只适合在非严格模式下。它的功能是将对应的字符串解析成js并执行,应该避免使用js,因为非常消耗性能(2次,一次解析成js,一次执行),简单来说将字符串参数解析成js代码并执行,并返回执行结果。但应避免使用,不安全,也耗性能。

Vue面试题记录

什么是计算属性

计算属性是用来声明式的描述一个值依赖了其他的值,当它依赖的这个值发生改变时,就更新DOM
当在模板中把数据绑定到一个计算属性上时,vue会在它依赖的任何值导致该计算属性改变时更新DOM
每个计算属性都包括一个getter和setter,读取时触发getter,修改时触发setter

生命周期

vue生命周期是什么

Vue 实例从创建到销毁的过程为生命周期。从开始创建、初始化数据、编译模板、挂载Dom→渲染、更新→渲染、卸载等一系列过程,称之为 Vue 的生命周期。

vue生命周期总共有几个阶段

创建前/后, 载入前/后,更新前/后,销毁前/销毁后

简述每个周期具体适合哪些场景

beforeCreate:在new一个vue实例后,只有一些默认的生命周期钩子和默认事件,其他的东西都还没创建。在beforeCreate生命周期执行的时候,data和methods中的数据都还没有初始化。不能在这个阶段使用data中的数据和methods中的方法

created:data 和 methods都已经被初始化好了,如果要调用 methods 中的方法,或者操作 data 中的数据,最早可以在这个阶段中操作

beforeMount:执行到这个钩子的时候,在内存中已经编译好了模板了,但是还没有挂载到页面中,此时,页面还是旧的

mounted:执行到这个钩子的时候,就表示Vue实例已经初始化完成了。此时组件脱离了创建阶段,进入到了运行阶段。 如果我们想要通过插件操作页面上的DOM节点,最早可以在和这个阶段中进行

beforeUpdate: 当执行这个钩子时,页面中的显示的数据还是旧的,data中的数据是更新后的, 页面还没有和最新的数据保持同步

updated:页面显示的数据和data中的数据已经保持同步了,都是最新的

beforeDestory:Vue实例从运行阶段进入到了销毁阶段,这个时候上所有的 data 和 methods , 指令, 过滤器 ……都是处于可用状态。还没有真正被销毁

destroyed: 这个时候上所有的 data 和 methods , 指令, 过滤器 ……都是处于不可用状态。组件已经被销毁了。

第一次页面加载会触发哪几个钩子?

beforeCreate, created, beforeMount, mounted

组件传值的几种类型

  • 父组件给子组件传值
  • 子组件给父组件传值
  • 非父子组件传值(任意组件之间传值)

父组件给子组件传值

  • 父组件中通过 import - components - < /> 三部曲 注册子组件
  • 子组件在 props 对象中创建一个属性 prop
  • 父组件在注册的子组件标签中添加 prop 属性,即 prop=“value”
  • 父组件可以通过 v-bind:prop(:prop)实现数据双向绑定

    以下是具体实例

<!-- 父组件 -->
<template>
  <div>
    <child-component @myEvent="handleEvent"></child-component>
    <p>从子组件接收到的值:{{ receivedValue }}</p>
  </div>
</template>

<script>
import ChildComponent from '@/components/ChildComponent.vue'

export default {
  components: {
    ChildComponent
  },
  data() {
    return {
      receivedValue: ''
    }
  },
  methods: {
    handleEvent(value) {
      this.receivedValue = value
    }
  }
}
</script>
<!-- 子组件 -->
<template>
  <div>
    <button @click="emitValue">传值给父组件</button>
  </div>
</template>

<script>
export default {
  methods: {
    emitValue() {
      this.$emit('myEvent', '这是子组件传递给父组件的值')
    }
  }
}
</script>

子组件给父组件传值

  • 子组件中需要以某种方式的方法来触发一个自定义事件(例如点击事件)
  • 子组件使用 this.$emit 方法,第一个参数为父组件定义的方法名称 event,第二个参数为传递的值
  • 在父组件中注册子组件并在子组件标签上绑定对自定义事件的监听(event=“Event”),Event(data) 可以接收传过来的参数

    以下是具体实例

<!-- 子组件 -->
<template>
  <div>
    <button @click="emitValue">传值给父组件</button>
  </div>
</template>

<script>
export default {
  methods: {
    emitValue() {
      this.$emit('myEvent', '这是子组件传递给父组件的值')
    }
  }
}
</script>

子组件定义了一个按钮,当按钮被点击时,sendData方法会被调用,它通过this.$emit方法触发了一个自定义事件child-event,并传递了一个字符串值作为参数。

<!-- 父组件 -->
<template>
  <div>
    <child-component @myEvent="handleEvent"></child-component>
    <p>从子组件接收到的值:{{ receivedValue }}</p>
  </div>
</template>

<script>
import ChildComponent from '@/components/ChildComponent.vue'

export default {
  components: {
    ChildComponent
  },
  data() {
    return {
      receivedValue: ''
    }
  },
  methods: {
    handleEvent(value) {
      this.receivedValue = value
    }
  }
}
</script>

父组件通过import引入了子组件,然后在模板中使用<child-component>标签将子组件添加到父组件中。在子组件上,我们监听了myEvent事件,并在触发事件时调用了handleEvent方法。handleEvent方法将接收到的值设置为receivedValue,然后在模板中显示出来。

兄弟组件之间的传参

EventBus 是中央事件总线,不管是父子组件,兄弟组件,跨层级组件等都可以使用它完成通信操作
兄click设置点击事件,用$emit设置通道传参给中转站,弟通过 $on接收来自中转站的参数

任意组件之间的通信

任意关系的组件之间的传参可以通过 vue-router 来完成

vue路由传参的三种方式

params传参(显示参数)

params传参(显示参数)又可分为声明式编程式两种方式

声明式router-link

该方式是通过router-link组件的to属性实现,该方法的参数可以是一个字符串路径,或者一个描述地址的对象。使用该方式传值的时候,需要子路由提前配置好参数,例如:

// router/index.js
{
  path: '/child/:id',
  component: Child
}

// src/compants/father.vue
<router-link :to="/child/123">进入Child路由</router-link>

编程式 this.$router.push

使用该方式传值的时候,同样需要子路由提前配置好参数,如下实例:

// router/index.js
{
  path: '/child/:id',
  component: Child
}
//父路由编程式传参(通过Onclick点击事件触发)
this.$router.push({
    path:'/child/${id}',
})

子路由中可以通过下面代码来获取传递的参数值

this.$route.params.id

编程式 this.$router.push

使用该方式传值的时候,同样需要子路由提前配置好参数,不过不能再使用 :/id 来传递参数了,因为父路由中,已经使用 params 来携带参数了,例如:

// router/index.js
{
  path: '/child,
  name: 'Child',
  component: Child
}
//父路由编程式传参(通过Onclick点击事件触发)
this.$router.push({
    name:'Child',
    params:{
        id:123
    }
})

子路由中可以通过下面代码来获取传递的参数值

this.$route.params.id

query传参

query 传参(显示参数)也可分为 声明式 和 编程式 两种方式

声明式 router-link

该方式也是通过 router-link 组件的to属性实现,不过使用该方式传值的时候,需要子路由提前配置好路由别名(name 属性),例如:

// router/index.js
{
  path: '/child,
  name: 'Child',
  component: Child
}
//父路由组件
<router-link :to="{name:'Child',query:{id:123}}">进入Child路由</router-link>

编程式 this.$router.push

使用该方式传值的时候,同样需要子路由提前配置好路由别名(name 属性),例如:

// router/index.js
{
  path: '/child,
  name: 'Child',
  component: Child
}
//父路由编程式传参(一般通过事件触发)
this.$router.push({
    name:'Child',
    query:{
        id:123
    }
})

子路由中可以通过下面代码来获取传递的参数值

this.$route.query.id