前端面试题

面试题博客

面试题博客更新

vue2、vue3生命周期

1.什么是生命周期?
官网解释:每个 Vue 组件实例在创建时都需要经历一系列的初始化步骤,比如设置好数据侦听,编译模板,挂载实例到 DOM,以及在数据改变时更新 DOM。在此过程中,它也会运行被称为生命周期钩子的函数,让开发者有机会在特定阶段运行自己的代码。
简单说:vue从创建实例到销毁的过程中,会执行一系列的方法对应对应当前vue的状态,这些方法叫做生命周期。

vue2常用生命周期:
beforeCreate:在实例初始化之后,数据观测 (Data Observer) 和 event/watcher 事件配置之前被调用。
created:在实例创建完成后被立即调用。在这一步,实例已完成以下的配置:数据观测 (data observer)、属性和方法的运算,watch/event 事件回调;然而,挂载阶段还没开始,el属性目前不可见。
beforeMount:beforeMount() 指令已经解析完毕,内存中已经生成dom树。
mounted:dom渲染完毕页面和内存的数据已经同步。
beforeUptate:当data的数据发生改变会执行这个钩子,内存中的数据是新的,页面是旧的
Updated:内存和页面都是新的
beforeDestroy:即将销毁data和methods中的数据此时还是可以使用的,可以做一些释放内存的操作
Destroyed:Vue 实例销毁后调用。调用后,Vue 实例指示的所有东西都会解绑定,所有的事件监听器会被移除,所有的子实例也会被销毁。

vue3生命周期做出了一些改动前面的是vue2的后面是vue3:
beforeCreate -> setup() 开始创建组件之前,创建的是data和method
created -> setup()
beforeMount -> onBeforeMount 组件挂载到节点上之前执行的函数。
mounted -> onMounted 组件挂载完成后执行的函数
beforeUpdate -> onBeforeUpdate 组件更新之前执行的函数。
updated -> onUpdated 组件更新完成之后执行的函数。
beforeDestroy -> onBeforeUnmount 组件挂载到节点上之前执行的函数。
destroyed -> onUnmounted 组件卸载之前执行的函数。
activated -> onActivated 若组件实例是 缓存树的一部分,当组件被插入到 DOM 中时调用。
deactivated -> onDeactivated 组件实例是 缓存树的一部分,当组件从 DOM 中被移除时调用。
errorCaptured -> onErrorCaptured 捕获了后代组件传递的错误时调用。
Vue3.x还增加了onRenderTracked 和onRenderTriggered函数。
onRenderTracked:当组件渲染过程中追踪到响应式依赖时调用。(仅在开发模式下可用)
onRenderTriggered:响应式依赖的变更触发了组件渲染时调用。(仅在开发模式下可用)

vue2、vue3数据劫持、双向绑定怎么实现的

数据劫持,其实就是数据代理
指的是在访问或者修改对象的某个属性时,通过一段代码拦截这个行为,进行额外的操作或者修改返回结果。
Vue2:是通过Object.DefineProperty实现数据劫持,作用是往data中的一个对象中添加属性,get()和set()方法就是通过Object.DefineProperty添加的 Object.defineProperty(obj, prop, {get(){},set(){}}
Vue3:使用的是ES6的proxy来进行监听劫持的 new Proxy(target, handler)

总结Proxy和Object.defineProperty的区别
1.Proxy性能优于Object.defineProperty。 Proxy代理的是整个对象Object.defineProperty只代理对象上的某个属性,如果是多层嵌套的数据需要循环递归绑定;
2.对象上定义新属性时,Proxy可以监听到,Object.defineProperty监听不到。
3.数组的某些方法(push、unshift和splice)Object.defineProperty监听不到,Proxy可以监听到。
4.Proxy在ie浏览器存在兼容性问题
Proxy不同于Object.defineProperty的是,它是对整个数据对象进行数据劫持,而Object.defineProperty是对数据对象的某个属性进行数据劫持

Object.DefineProperty的实际应用

let person = {
  name: '奶茶伦',
  age: 20,
}
function defineProperty (obj, prop, val) {
  Object.defineProperty(obj, prop, {
    get () {
      console.log('get---------')
      return val
    },
    set (newVal) {
      console.log('set---------')
      val = newVal
    },
  })
}
Object.keys(person).forEach(item => {
  defineProperty(person, item, person[item])
})
// 读取name和age就会触发get()
console.log(person.name)
// 修改name和age就会触发set()
person.name = '优乐美'
console.log(person.name)

//缺点
//1.添加新属性 不会触发set
//2.无法监控到数组下标的变化,只要不是重新赋值一个新的数组对象,任何对数组内部的修改都不会触发set方法的执行

proxy应用

let person = {
  name: '奶茶伦',
  song: '七里香',
}
const handler = {
  // obj => 目标对象 prop => 属性吗
  get (obj, prop) {
    console.log('get----------')
    return obj[prop]
    // 设置初始值
    // return Reflect.get(obj, prop) ? obj[prop] : '初始值'
  },
  // obj => 目标对象 prop => 属性吗 value => 属性值
  set (obj, prop, value) {
    console.log('set-----------')
    obj[prop] = value
    
    // 注意⚠️:set()要返回一个布尔值
    return true
  },
}
let proxy = new Proxy(person, handler)
console.log('proxy.song', proxy.song) // 读取song,触发了get(),说明拦截成功
console.log('proxy.age', proxy.age) // undefined,因为没有age所以返回 undefined,可以设置一些初始值

proxy.name = '优乐美' // 修改name,出发了set(),说明拦截成功
console.log('proxy.name', proxy.name)

参考数据劫持…

vue的双向绑定
vue数据双向绑定是通过数据劫持结合发布者-订阅者模式的方式来实现的,数据劫持在vue2中通过Object.defineProperty这个ES5的新特性(ie8浏览器可不支持哦…),对vue传入的数据进行了相应的数据拦截,为其动态添加get与set方法。当数据变化的时候,就会触发对应的set方法,当set方法触发完成的时候,内部会进一步触发watcher,当数据改变了,接着进行虚拟dom对比,执行render,后续视图更新操作完毕。
参考双向绑定

vue中的nextTick

为什么使用nextTick
由于Vue DOM更新是异步执行的,即修改数据时,视图不会立即更新,而是会监听数据变化,并缓存在同一事件循环中,等同一数据循环中的所有数据变化完成之后,再统一进行视图更新。为了确保得到更新后的DOM,所以设置了nextTick()方法。
参考…

vue2与vue3相比

1.生命周期。
2.双向绑定:
vue2 的双向数据绑定是利⽤ES5 的⼀个 API ,Object.definePropert()对数据进⾏劫持 结合 发布订阅模式的⽅式来实现的。
vue3 中使⽤了 es6 的 ProxyAPI 对数据代理,通过 reactive() 函数给每⼀个对象都包⼀层 Proxy,通过 Proxy 监听属性的变化,从⽽ 实现对数据的监控。
3.for循环允许template标签添加key
4.新加入了 TypeScript 以及 PWA 的支持
5.vue3的⼀个按需引⼊,vue2中所有的方法都在vue实例对象上,如nextTick、computed、ref等
vue2只有一个根标签,vue3可以有多个
6.获取props
vue2:console.log(‘props’,this.xxx)
vue3:setup(props,context){ console.log(‘props’,props) }
7.给父组件传值emit
vue2:this.$emit()
vue3:setup(props,context){context.emit()}

webpack相关问题

1.对webpack的理解

webpack是一个打包模块化js的工具,在webpack里一切文件皆模块,通过loader转换文件,通过plugin注入钩子,最后输出由多个模块组合成的文件,webpack专注构建模块化项目。
webPack可以看做是模块的打包机器:它做的事情是,分析你的项目结构,找到js模块以及其它的一些浏览器不能直接运行的拓展语言,例如:Scss,TS等,并将其打包为合适的格式以供浏览器使用

2.webpack构建流程

1.初始化参数:解析webpack配置参数,合并shell传入和webpack.config.js文件配置的参数,形成最后的配置结果。
2.开始编译:上一步得到的参数初始化compiler对象,注册所有配置的插件,插件监听webpack构建生命周期的事件节点,做出相应的反应,执行对象的 run 方法开始执行编译。
3.确定入口:从配置的entry入口,开始解析文件构建AST语法树,找出依赖,递归下去。
4.编译模块:递归中根据文件类型和loader配置,调用所有配置的loader对文件进行转换,再找出该模块依赖的模块,再递归本步骤直到所有入口依赖的文件都经过了本步骤的处理。
5.完成模块编译:在经过第4步使⽤ Loader 翻译完所有模块后,得到了每个模块被翻译后的最终内容以及它们之间的依赖关系;
6.输出资源:根据⼊⼝和模块之间的依赖关系,组装成⼀个个包含多个模块的 Chunk,再把每个 Chunk 转换成⼀个单独的⽂件加⼊到输出列表,这步是可以修改输出内容的最后机会;
7.输出完成:在确定好输出内容后,根据配置确定输出的路径和⽂件名,把⽂件内容写⼊到⽂件系统。

3.loader 和 plugin 的区别是什么

Loader直译为"加载器"。Webpack将一切文件视为模块,但是webpack原生是只能解析js文件,如果想将其他文件也打包的话,就会用到loader。 所以Loader的作用是让webpack拥有了加载和解析非JavaScript文件的能力。
loader它只专注于转化文件(transform)这一个领域,完成压缩,打包,语言翻译; 而plugin不仅只局限在打包,资源的加载上,还可以打包优化和压缩,重新定义环境变量等
Plugin直译为"插件"。Plugin可以扩展webpack的功能,让webpack具有更多的灵活性。 在 Webpack 运行的生命周期中会广播出许多事件,Plugin 可以监听这些事件,在合适的时机通过 Webpack 提供的 API 改变输出结果
loader运行在打包文件之前(loader为在模块加载时的预处理文件);plugins在整个编译周期都起作用
一个loader的职责是单一的,只需要完成一种转换。一个loader其实就是一个Node.js模块。当需要调用多个loader去转换一个文件时,每个loader会链式的顺序执行
常见的loader和plugin插件
Loader: 样式:style-loader、css-loader、less-loader、sass-loader等
Plugin: webpack内置UglifyJsPlugin,压缩和混淆代码,通过UglifyES压缩ES6代码。

4.webpack5个核心概念

1.入口entry
2.出口output
3.加载器loader
4.插件plugins
5.mode

事件循环

宏任务:
script (可以理解为外层同步代码)
setTimeout/setInterval
UI rendering/UI事件
postMessage、MessageChannel
setImmediate、I/O(Node.js)
微任务:Promise.then
MutaionObserver
Object.observe(已废弃;Proxy 对象替代)
process.nextTick(Node.js)

事件循环执行机制参考
相关参考

1.什么是事件循环机制

就是一个执行消息队列的机制,先执行同步再执行异步,异步遇到微任务,先执行微任务,执行完后如果没有微任务,就执行下一个宏任务,如果有微任务,就按顺序一个一个执行微任务。

2.为什么要事件循环

javascript 是单线程的编程语言,只有一个调用栈,在同一时间只能做一件事,按顺序来处理事件,但前端的某些任务是非常耗时的,比如网络请求、定时器和事件监听,如果让它们和别的任务一样,都老老实实排队等待执行的话,执行效率会非常低,甚至导致页面的假死。
在遇到耗时的任务(异步任务)时,js 并没有阻塞,还会继续执行,这就是因为有事件循环机制,实现了单线程非阻塞的方法。

路由

1.浅谈对路由的理解

什么是路由?根据不同的url地址展示不同的页面内容 或者数据

2.路由跳转的方式有哪几种?

1、a标签进行跳转。
2、声明式:<router-link :to=“…”>进行跳转。相当于调用 router.push(…) :
3、编程式:router.push({ path: ‘/register’, query: { plan: ‘private’ } })

3.route 是用来获取路由信息的,router是用来操作路由的,vue3使用useRouter 和 useRoute 函数

4.路由/页面传值的方式 有哪几种?

1、search传参<router-link to=“/地址?属性名=属性值”></router-link> route.query.属性名
2、动态路由 path:“/地址/变量名” <router-link to=“/地址/数据值”></router-link>route.params.变量名
3、编程式导航 this.$router.push({path:“/home”,query:{}})

5.什么是路由守卫?路由的钩子函数有哪些?分别说出使用的场景、及用法

.什么是路由守卫?路由跳转前后的一些验证

全局守卫
全局前置守卫router.beforeEach((to, from,next)=>{})主要是用于登录验证,就是路由还没跳转前告知,跳转后再通知就晚了。
全局解析守卫router.beforeResolve((to, from,next)=>{})
全局后置守卫router.afterEach((to, from,next)=>{})路由跳转完成后触发
路由独享的守卫 beforeEnter

const routes = [
 path: '/users/:id',
 component: UserDetails,
   beforeEnter: (to, from) => {
    // reject the navigation
    return false
  },
 },

组件内的守卫
beforeRouteEnter
beforeRouteUpdate
beforeRouteLeave

TS泛型、枚举、基本数据类型、type和interface区别

1.泛型

是指在定义函数、接口或类的时候,不预先指定具体的类型,而在使用的时候再指定类型的一种特性。
通俗理解:泛型就是解决类 接口 方法的复用性、以及对不特定数据类型的支持

//函数泛型
function identity<T>(arg: T): T {
   return arg;
}
//使用  
let output = identity<string>("myString"); 
let output = identity("myString");
//接口泛型
interface GenericIdentityFn<T> {
   (arg: T): T;
}
let myIdentity: GenericIdentityFn<number> = identity;
//类泛型
class GenericNumber<T> {
   zeroValue: T;
   add: (x: T, y: T) => T;
}
let myGenericNumber = new GenericNumber<number>();

2.枚举

枚举是一个被命名的整型常数的集合,用于声明一组命名的常数,当一个变量有几种可能的取值时,可以将它定义为枚举类型
通俗来说,枚举就是一个对象的所有可能取值的集合

//数字枚举  Up使用初始化为 1。 其余的成员会从 1开始自动增长
//不使用初始化 Up的值为 0, Down的值为 1
enum Direction {
   Up = 1,
   Down,
   Left,
   Right
}
//字符串枚举 每个成员都必须用字符串字面量
enum Direction {
   Up = "UP",
   Down = "DOWN",
   Left = "LEFT",
   Right = "RIGHT",
}
//异构枚举 枚举可以混合字符串和数字成员,但是似乎你并不会这么做
enum BooleanLikeHeterogeneousEnum {
   No = 0,
   Yes = "YES",
}

3.基本数据类型

boolean布尔值 let isDone: boolean = false;
number数字 let decLiteral: number = 6;
string字符串 let name: string = “bob”;
array数组

//第一种,可以在元素类型后面接上 [],表示由此类型元素组成的一个数组:
let list: number[] = [1, 2, 3];
//第二种方式是使用数组泛型,Array<元素类型>:
let list: Array<number> = [1, 2, 3];

Tuple元组

//允许表示一个已知元素数量和类型的数组,各元素的类型不必相同
let x: [string, number] = ['hello', 10];

枚举enum

//自动递增从0 red = 0,green = 1
enum Color {Red, Green, Blue}
let c: Color = Color.Green;

Any let notSure: any = 4;
Void

//void类型像是与any类型相反,它表示没有任何类型。 
//当一个函数没有返回值时,你通常会见到其返回值类型是 void:
function warnUser(): void {
   console.log("This is my warning message");
}
//声明一个void类型的变量没有什么大用,因为你只能为它赋予undefined和null:
let unusable: void = undefined;

Object

4.type和interface区别

type作用就是给类型起别名

type second = number
let name:second = 1 //second就是number类型

区别
①interface只能定义对象类型。
type可以声明任何类型,基础类型、联合类型、交叉类型。

// 基础类型(相当于起别名)
type person = 'string';
// 联合类型
interface Dog {
 name:string
}
interface Cat {
 age:number
}
type animal = Dog | Cat;
// 元祖(指定某个位置具体是什么类型)
type animal = [Dog,Cat];
//交叉类型(多种类型的集合)
type animal = Dog & Cat;

②合并声明
定义两个同名的type回报异常;
顶一个两个同名的interface会合并;
③扩展性
interface可以使用extends,和implements,进行扩展

interface Dog {
 name:string;
}
interface Cat extends Dog {
 age:number;
}
// interface extends type
type Dog= {name:string};
interface Cat extends Dog {
 age:number;
}

但type可以使用交叉类型&进行合并

// type & type
 type Dog = {name:string};
 type Cat = {age:number} & Dog;
 // tyep & interface
 interface Dog {
   name:string;
 }
 type Cat = {age:number} & interface;

<font size='3’vuex和pinia

vuex和pinia的区别
(1)pinia它没有mutation,他只有state,getters,action【同步、异步】使用他来修改state数据
(2)pinia他默认也是存入内存中,如果需要使用本地存储,在配置上比vuex麻烦一点
(3)pinia语法上比vuex更容易理解和使用,灵活。
(4)pinia没有modules配置,没一个独立的仓库都是definStore生成出来的
(5)pinia state是一个对象返回一个对象和组件和data是一样的语法

flex布局

flex布局

下载文件并重命名

方法一:通过a标签下载,download属性修改文件名,缺陷只能是同源的。

<a href="/images/liang.jpg" rel="external nofollow" download="文件名称">

方法二:通过blob实现跨域下载并修改文件名(同样适用于URL地址)

//1.通过文件下载url拿到对应的blob对象
getBlob(url) {
  return new Promise(resolve => {
    const xhr = new XMLHttpRequest();
    xhr.open('GET', url, true);
    xhr.responseType = 'blob';
    xhr.onload = () => {
      if (xhr.status === 200) {
        resolve(xhr.response);
      }
    };
    xhr.send();
  });
//2.js模拟点击a标签进行下载,通过创建a标签下载download修改文件名
saveAs(blob, filename) {
  var link = document.createElement('a');
  link.href = window.URL.createObjectURL(blob);
  link.download = filename;
  link.click();
}
//3.调用
getBlob(file.url).then(blob => {
   this.saveAs(blob,'文件名.docx');
 });

🧐1.防抖和节流的区别

 <el-button @click="only">防抖</el-button>
 <el-button @click="jieliu">节流</el-button>
data() {
      return {
        timeout: null,
        flag: true, //阀门
      }
    },

1.防抖,多次连续点击只会执行一次(搜索框按钮)

 only() {
        clearInterval(this.timeout)
        this.timeout = setTimeout(() => {
          console.log(12)
        }, 2000)
      },

2.节流,多次连续点击会在一定间隙的时间内触发(页面自适应、监控页面滚动、鼠标移动)

//开源节流
      jieliu() {
        if (this.flag) {
          this.flag = false
          console.log('节流')
          setTimeout(() => {
            this.flag = true
          }, 2000)
        }
      },

🧐2.call,apply,bind的实现和区别 都是调用函数并且改变this指向

call和apple基本上一致,唯一区别在于传参方式
bind:语法和call一模一样,区别在于立即执行还是等待执行,bind不兼容IE6~8

fn.call(obj, 1, 2);// 改变fn中的this,并且把fn立即执行
fn.apply(obj, [1, 2]);// 改变fn中的this,并且把fn立即执行
fn.bind(obj, 1, 2); // 改变fn中的this,fn并不执行

🧐3.computed和watch的区别还有methods

computed和watch区别:
computed:
1.其计算结果会被缓存,只有他依赖的属性发生变化的时候他才会被重新计算并渲染。
2.不支持异步,当computed内部有异步操作时无效,无法监听数据的变化。
3.如果一个属性依赖其他计算属性计算而来,是一个多对一或者一对一,一般用computed.
4.如果computed属性值是一个函数默认会走get方法,函数的返回值就是属性的属性值,在computed中每一个属性都有get和set方法 ,当数据变化时调用set方法,函数必须有return。内部的函数调用的时候不需要加()
watch:
1.不支持缓存,数据变化时或者重新渲染时就会触发watch函数中相应的操作。
2.支持异步。
3.当一个属性发生变化时,需要执行相应的操作,一对多时,用watch。
4.监听函数必须是data中声明过或者父组件传递的props数据,当数据变化时触发响应的操作。函数是不需要调用的。
methods:methods是一个方法,它可以接受参数,而computed 不能,computed 是可以缓存的,methods 不会。computed 可以依赖其他 computed,甚至是其他组件的 data。
computed使用:是vue中的计算属性,用法和data中的数据一样,只有他依赖的属性发生变化时,computed才会被重新求值。函数必须return,适用于复杂逻辑的计算。
watch使用:是vue提供的一种更通用的观察和响应式vue实例上数据的变动-侦听属性,watch更像是data数据的监听回调,可以监听data、props4和computed中的数据。

🧐4.hash和history的区别

router中有两种模式hash(默认),history需要设置(mode:history)
hash:url显示有#、回车刷新正常显示、hash 能兼容到IE8
history:url显示没有#、回车刷新会报404、history能兼容到IE10
那么在声明时候要用history模式呢?
将#去除那么就要使用history模式,但是使用history模式还有一个问题就是,在访问二级页面的时候,做刷新操作,会出现404错误,那么就需要和后端人员配合让他配置一下apache或是nginx的url重定向,重定向到你的首页路由上就可以了。

🧐5.vuex的核心

有5个属性
state 唯一公共的数据源,所有共享的数据都要放在state进行存储
取的两种方式
1.this.$store.state.属性名
2.import { mapState } from 'vuex'
computed: { ...mapState(['count']) }
mutations 用于变更 Store中 的数据
触发mutations的第两种方式
1.this.$store.commit('函数名',参数)
2.import { mapMutations } from 'vuex'
methods: { ...mapMutations(['add', 'addN']) }
actions 用于处理异步任务,如果通过异步操作变更数据,必须通过 Action,而不能使用 Mutation,但是在 Action 中还是要通过触发Mutation 的方式间接变更数据。
触发actions的两种方式
1.this. $store.dispatch('函数名', 参数)
2.import { mapActions } from 'vuex'
methods: { ...mapActions(['addASync', 'addNASync']) }
getters用于对 Store 中的数据进行加工处理形成新的数据,不更改源数据类似 Vue 的计算属性,Store 中数据发生变化,Getter 的数据也会跟着变化,
使用 getters 的第两种方式
1.this. $store.getters.名称
2.import { mapGetters } from 'vuex'
computed: { ...mapGetters(['showNum']) }
module是模块化每个模块拥有自己的 state、mutation、action、getter、甚至是嵌套子模块——从上至下进行同样方式的分割

🧐6.原型和原型链

每一个js对象都会在内部初始化一个属性,就是prototype(原型),当我们访问这个对象的某一个属性的时候,如果这个对象内部不存在这个属性就会去prototype上查找,这个prototype又会有自己的prototype,然后就会一直这样查找形成原型链,查找不到就返回undefined。

🧐7.keep-alive

keep-alive 是 Vue 的内置组件,当它包裹动态组件时,会缓存不活动的组件实例
在组件切换过程中将状态保留在内存中,防止重复渲染DOM,减少加载时间及性能消耗,提高用户体验性

🧐8.vue组件之间的传值

父向子传值:在子组件上通过自定义属性,子组件通过props属性接受
父组件提供:provide(一个对象) / 子组件接受:inject(对象或数组字符串),(vue中的两个属性)
子向父传值:通过自定义事件,子组件通过this.$emit(‘事件名’,参数)
非父子传值:通过eventBus,给vue实例原型上添加一个属性,通过this.vm. $emit('事件名',参数),另一个组件通过this.vm.$on('事件名',(params)=>{})
获取组件实例 $parent / $children / ref ()
本地存储:vuex、本地存储
mixin (混入)

🧐8.vue插槽

插槽就是子组件中的提供给父组件使用的一个占位符,用 表示,父组件可以在这个占位符中填充任何模板代码。
具名插槽其实就是给插槽取个名字。一个子组件可以放多个插槽,而且可以放在不同的地方,而父组件填充内容时,可以根据这个名字把内容填充到对应插槽中

🧐9.vue双向绑定原理

参考文档的网址
采用数据劫持结合发布者-订阅者模式的方式,通过 Object.defineProperty() 来劫持各个属性的setter,getter,在数据变动时发布消息给订阅者,触发相应监听回调。
当把一个普通 Javascript 对象传给 Vue 实例来作为它的 data 选项时,Vue 将遍历它的属性,用 Object.defineProperty 将它们转为 getter/setter。用户看不到 getter/setter,但是在内部它们让 Vue 追踪依赖,在属性被访问和修改时通知变化。

🧐10.MVVM模式的理解

MVVM 由 Model、View、ViewModel 三部分构成,Model层代表数据模型,也可以在Model中定义数据修改和操作的业务逻辑;View 代表UI 组件,它负责将数据模型转化成UI展现出来,ViewModel 是一个同步View 和 Model的对象。
在MVVM架构下,View 和 Model 之间并没有直接的联系,而是通过ViewModel进行交互,Model 和 ViewModel 之间的交互是双向的, 因此View 数据的变化会同步到Model中,而Model 数据的变化也会立即反应到View 上。
 ViewModel 通过双向数据绑定把 View 层和 Model 层连接了起来,而View 和 Model 之间的同步工作完全是自动的,无需人为干涉,因此开发者只需关注业务逻辑,不需要手动操作DOM, 不需要关注数据状态的同步问题,复杂的数据状态维护完全由 MVVM 来统一管理。

🧐11.sessionStorage 、localStorage 和 cookie 之间的区别

共同点:都是保存在浏览器端,且同源的。
区别:cookie数据始终在同源的http请求中携带(即使不需要),即cookie在浏览器和服务器间来回传递;cookie数据还有路径(path)的概念,可以限制cookie只属于某个路径下。存储大小限制也不同,cookie数据不能超过4k,同时因为每次http请求都会携带cookie,所以cookie只适合保存很小的数据,如会话标识。
而sessionStorage和localStorage不会自动把数据发给服务器,仅在本地保存。sessionStorage和localStorage 虽然也有存储大小的限制,但比cookie大得多,可以达到5M或更大。
数据有效期不同,sessionStorage:仅在当前浏览器窗口关闭前有效,自然也就不可能持久保持;localStorage:始终有效,窗口或浏览器关闭也一直保存,因此用作持久数据;cookie只在设置的cookie过期时间之前一直有效,即使窗口或浏览器关闭。
作用域不同,sessionStorage不在不同的浏览器窗口中共享,即使是同一个页面;localStorage 在所有同源窗口中都是共享的;cookie也是在所有同源窗口中都是共享的。Web Storage 支持事件通知机制,可以将数据更新的通知发送给监听者。Web Storage 的 api 接口使用更方便。

🧐12.vue-loader是什么?使用他的用途有哪些?

一、vue-loader是解析 .vue 文件的一个加载器,提取出其中的逻辑代码 script,样式代码style,以及HTML 模板template,再分别把他们交给对应的loader去处理
二、用途
js可以写es6,style样式可以写scss或less、template可以加jade等
三、
css-loader:加载由vue-loader提取出的CSS代码
vue-template-compiler:把vue-loader提取出的HTML模板编译成可执行的jacascript代码

🧐13.Vue中那些方式可以实现页面之间传参,且如何获取到值

1、search传参 <router-link to="/地址?属性名=属性值"></router-link> this.$route.query.属性名
2、动态路由 path:“/地址/变量名” <router-link to="/地址/数据值"></router-link> this.$route.params.变量名
3、本地存储 setItem() getItem()

🧐14.vuex和本地存储有什么区别

  1. vuex数据刷新就没有了,本地存储还在
  2. vuex中的数据可以实时渲染,本地存储不行

🧐15.响应式布局实现的方法

  1. CSS3-Media Query(最简单的方式,但是无法满足很多需求)
    @media (max-width: 400px) { .leftColumn { background-color:orange; } }
  2. 借助原生Javascript(成本高,不推荐使用)
  3. 第三方开源框架(比如bootstrap,可以很好的支持浏览器的响应式布局)

🧐16.如何理解回流和重绘

回流:当我们对 DOM 的修改引发了 DOM 几何尺寸的变化(比如修改元素的宽、高或隐藏元素等)时,浏览器需要重新计算元素的几何属性(其他元素的几何属性和位置也会因此受到影响),然后再将计算的结果绘制出来。这个过程就是回流(也叫重排)。
重绘:当我们对 DOM 的修改导致了样式的变化、却并未影响其几何属性(比如修改了颜色或背景色)时,浏览器不需重新计算元素的几何属性、直接为该元素绘制新的样式(跳过了上图所示的回流环节)。这个过程叫做重绘。 由此我们可以看出,重绘不一定导致回流,回流一定会导致重绘。

🧐17.浅拷贝和深拷贝的区别

深浅拷贝只是针对Array与Object这样的引用数据类型。
浅拷贝只是拷贝了它在栈中存储的指针,它们指向的都是同一个堆内存地址,所以浅拷贝在某些情况会造成改变数据后导致别的另一份数据也同步被改变的情况;
基本数据值存储在栈中
引用类型数据的值存储在堆中,变量存储在栈中。
浅拷贝的方法
1.Object.assign()
2. Array.prototype.concat()
3. Array.prototype.slice()
深拷贝 当你赋值一个数据然后对这个数据进行修改不会影响到原来的数据就达到了深拷贝。
深拷贝的方法
1.JSON.parse(JSON.stringify()) 但是这个方法有个缺陷,可以实现对象或数组的深拷贝,但是不能处理函数,函数经过这样处理后会变成null。
2. 递归的方法,遍历要克隆的每个字段,发现它的值是对象或数组后继续递归。
第一步:获取你拷贝的数据时值类类型数据还是引用类型的数据.
​ 获取数据类型
第二步:获取的数据类型中,拷贝的数据分析是数组还是对象
第三步:如果是数组,那么定义容器 [ ] ,如果是对象,那么定义容器 { }
第4步:将拿到数据,进行循环.放入到你定义对应容器中.
第五步:在做一次递归

🧐18.三次握手和四次挥手

进行三次握手,建立TCP连接。(tcp传输控制协议)
第一次握手:建立连接。客户端发送连接请求报文段,将SYN位置为1,Sequence Number为x;然后,客户端进入SYN_SEND状态,等待服务器的确认;
第二次握手:服务器收到SYN报文段。服务器收到客户端的SYN报文段,需要对这个SYN报文段进行确认,设置Acknowledgment Number为x+1(Sequence Number+1);同时,自己自己还要发送SYN请求信息,将SYN位置为1,Sequence Number为y;服务器端将上述所有信息放到一个报文段(即SYN+ACK报文段)中,一并发送给客户端,此时服务器进入SYN_RECV状态;
第三次握手:客户端收到服务器的SYN+ACK报文段。然后将Acknowledgment Number设置为y+1,向服务器发送ACK报文段,这个报文段发送完毕以后,客户端和服务器端都进入ESTABLISHED状态,完成TCP三次握手。
完成了三次握手,客户端和服务器端就可以开始传送数据。
(注释:ACK:此标志表示应答域有效,就是说前面所说的TCP应答号将会包含在TCP数据包中;有两个取值:0和1,为1的时候表示应答域有效,反之为0。
TCP协议规定,只有ACK=1时有效,也规定连接建立后所有发送的报文的ACK必须为1。
SYN(SYNchronization) : 在连接建立时用来同步序号。当SYN=1而ACK=0时,表明这是一个连接请求报文。对方若同意建立连接,则应在响应报文中使SYN=1和ACK=1. 因此, SYN置1就表示这是一个连接请求或连接接受报文。
FIN (finis)即完,终结的意思, 用来释放一个连接。当 FIN = 1 时,表明此报文段的发送方的数据已经发送完毕,并要求释放连接。
发送HTTP请求,服务器处理请求,返回响应结果
TCP连接建立后,浏览器就可以利用HTTP/HTTPS协议向服务器发送请求了。服务器接受到请求,就解析请求头,如果头部有缓存相关信息如if-none-match与if-modified-since,则验证缓存是否有效,若有效则返回状态码为304,若无效则重新返回资源,状态码为200.)

关闭TCP连接
第一次分手:主机1(可以使客户端,也可以是服务器端),设置Sequence Number和Acknowledgment Number,向主机2发送一个FIN报文段;此时,主机1进入FIN_WAIT_1状态;这表示主机1没有数据要发送给主机2了;
第二次分手:主机2收到了主机1发送的FIN报文段,向主机1回一个ACK报文段,Acknowledgment Number为Sequence Number加1;主机1进入FIN_WAIT_2状态;主机2告诉主机1,我“同意”你的关闭请求;
第三次分手:主机2向主机1发送FIN报文段,请求关闭连接,同时主机2进入LAST_ACK状态;
第四次分手:主机1收到主机2发送的FIN报文段,向主机2发送ACK报文段,然后主机1进入TIME_WAIT状态;主机2收到主机1的ACK报文段以后,就关闭连接;此时,主机1等待2MSL后依然没有收到回复,则证明Server端已正常关闭,那好,主机1也可以关闭连接了。

🧐19.get和post区别

1.post请求更安全,(不会作为url的一部分,不会被缓存、保存在服务器日志、以及浏览器浏览记录中)
2.post传输的数据更大
3.post能发送更多的数据类型(get只能发送ASCII字符)
4.post请求比get慢
5. post用于修改和写入数据,get一般用于搜索排序和筛选之类的操作(淘宝,支付宝的搜索查询都是get提交),目的是资源的获取,读取数据

🧐20.null和undefined区别

null:表示值为空,准备将来存储一个对象;typeof返回值为object;转成数字为0Number(null)
undefined:表示声明了为赋值;typeof返回值undefined;转成数字为NaN Number(undefined)

🧐21.什么是闭包

函数里套函数;内部函数可以访问外部函数的变量、参数或者其他函数;
函数在包含他外部函数的外面被调用;闭包是连接内部函数和外部函数的桥梁。
function fn() {
var n = 10;
return function () { n++; return n; }
}
var v = fn();
console.log(v()); // 11
console.log(v()); // 12
console.log(v()); // 13`
闭包的应用场景1:模拟对象的私有属性
function fn() {
var _age = 3;
return {
// 设置
setAge: function (val) {
_age = val;
},
// 读取
getAge: function () {
return _age;
}
}
}
var obj = fn();
// console.log(obj);
obj.setAge(5);
console.log(obj.getAge());

🧐22:事件委托

事件委托又称事件代理,利用事件冒泡原理,将子级的事件指定给父级执行

🧐23:let、const和va区别

var:是函数作用域,有变量提升,可以声明多次,后面的变量会覆盖前面的
let:是块级作用域,没有变量提升,只能声明一次,在同一个作用域下不能重复定义
const:1是块级作用域只能定义一次不能重复定义且定义时就得赋值,后期不允许修改常量的值,

🧐24:es6新增了哪些内容

1. 新增了let、const命令
2. 解析赋值
数组的解析赋值 let [a,b]=[2,3]
对象的解析赋值 let {a,b}={a:1,b:2}
3. 模板字符串 ${}
4. 箭头函数,由于箭头函数不支持arguments函数 所以新增了rest剩余参数…变量名,将函数里面传过来的内容值,自动解析为一个数组.解决函数里面传值不确定时候使用rest剩余参数.
箭头函数特性:1.简洁,方便;2.没有自己的this,箭头函数不是调用时确定this,而是看他有没有上层父级,如果有则看上层父级定义,如果没有则是window;3.call、apply、bind方法不起作用。
5. 可扩展运算符…
用在字符串中 let str='abcd' console.log(...str); // a b c d
用在数组中 let arr = [1,2,3];let newarr = [6,7,...arr];console.log(newarr);//[6,7,1,2,3]
用在对象上 let obj={name:1,age:12} let newobj={sex:'女',...obj}
6. Symbol数据类型 let apply = Symbol("这是手机");
Symbol特效:实例后会得到一个独一无二的值,解决对象属性名被覆盖的问题
7. 新增了set和map容器
set和数组类似:特性 无序的没有规则,过滤set容器中重复的值
let arr=[...new Set([1,2,1])]
set容器方法:
set.add(“value”) 向set容器中添加一个值
set.size 获取set容器的长度
set.delete(“value”); 删除set容器中的一个值
set.has(“value”) 判断这个值是否在set容器中存在,存在返回true,不存在返回false.
set.clear() 情况set容器中的值 let map = new Map([['key',value'],['key','value']])Symbol,key可以是任意一个数据类型
map容器的方法:
map.set(key,value) 向map容器中添加一个值
map.get(key) 获取map容器中value对应的key值
map.size 获取map容器中的长度
map.delete(key) 删除map容器中一个key对应的value值
map.has(key) 判断该key对应的value值是否在map容器中存在
map.clear() 情况map容器的value值
8. Promise对象(函数),用来处理异步操作
当我主动调用了resolve()方法的时候,此时就会从pending 状态------->fulfilled状态
反之:当我主动调用了reject()方法的时候,此时就会从pending 状态------->rejected状态
Promise.all() 方法 const p = Promise.all([p1, p2, p3]); 其中p1,p2,p3都是promise对象
Promise.all()里面返回的是promise对象,且promise对象都返回的是resolve()状态,那么整个Promise.all()方法返回的是resolve()状态.如果其中有一个promise对象返回的是reject()状态,那么整个Promise.all()方法返回的是reject()状态.
Promise.race()方法 const p = Promise.all([p1, p2, p3]); 其中p1,p2,p3都是promise对象
Promise.race()方法接收整个返回结果,他不管是promise对象的resolve状态还是reject()状态,他是谁先被执行完,最终返回输出结果是被先执行完的内容.
9. Es6中定义类。
10.
字符串扩展
str.includes(“字符”)判断该相邻的字符是否在这个字符串中存在 返回的是true/false
str.startsWith(“字符”) 判断该字符是否在这个字符串中已这个字符开头 返回的是true/false
str.endsWith(“字符”) 已字符串结尾
数值扩展
Number.isInteger(数值) 判断这个数值是否是一个整数 (记忆)
Number.parseInt(“数值字符串”) 将字符串内容如果是数值开头,他会把数值解析出来。遇到字符串不做解析.
Math.trunc(数值) 去除小数点的内容
数组扩展
Array.from() 将一个维数组转换为一个真数组
Array.of() 将里面内容,解析到数组中
arr.find() 判断满足条件的,返回第一个满足条件的内容元素.
arr.findIndex() 判断满足条件的,返回第一个满足条件的下标
对象扩展
Object.is(值1,值2) 与严格比较运算符(===)的行为基本一致。
Object.assign(目标对象,源对象) 将源对象数据拷贝到目标对象中

🧐25:http和https区别

1、HTTPS 协议需要到 CA (Certificate Authority,证书颁发机构)申请证书,一般免费证书较少,因而需要一定费用。(以前的网易官网是http,而网易邮箱是 https 。)
2、HTTP 是超文本传输协议,信息是明文传输,HTTPS 则是具有安全性的 SSL 加密传输协议。
3、HTTP 和 HTTPS 使用的是完全不同的连接方式,用的端口也不一样,前者是80,后者是443。
4、HTTP 的连接很简单,是无状态的。HTTPS 协议是由 SSL+HTTP 协议构建的可进行加密传输、身份认证的网络协议,比 HTTP 协议安全。(无状态的意思是其数据包的发送、传输和接收都是相互独立的。无连接的意思是指通信双方都不长久的维持对方的任何信息。)

🧐26:讲一下浏览器缓存

浏览器缓存分为强缓存和协商缓存
强缓存 浏览器在加载资源时,先看看cache-control中的max-age判断数据是否过期,如果没有直接使用该缓存。有些用户可能在没有过期的时候点刷新按钮,这个时候就会请求服务器,如果要避免这样的操作,则可以向cache-control中添加一个immutable属性。
其中cache-control中还有一些其他属性
public :设置浏览器和服务器都可以缓存
private:设置浏览器可以缓存
no-cache:不允许强缓存,可以协商缓存
no-store:不允许缓存
协商缓存浏览器在加载资源时,没有设置强缓存,会向服务器发送请求,并且携带两个参数,个是If-None-Match,也就是响应头中的etag属性,每个文件对应一个etag;另一个参数是If-Modified-Since,也就是响应头中的Last-Modified属性,检验缓存是否过期,如果没有过期服务器会给浏览器返回304告诉浏览器可以使用旧缓存。
浏览器缓存机制
浏览器缓存就是把一个已经请求过的资源拷贝一份存储起来,当下次需要该资源时, 浏览器会根据缓存机制决定直接使用缓存资源还是再次向服务器发送请求. ∙ 作用: 减少网络传输的损耗以及降低服务器压力。 ∙ 缓存位置优先级:Service Worker > Memory Cache > Disk Cache > Push Cache. 都没有命中,就会向服务器发请求 ∙ 策略优先级: 强制缓存 > 协商缓存; cache-control > Expires > Etag > Last- modified

🧐27:什么是事件流和事件委托

事件流包含三个阶段:捕获阶段,目标阶段,冒泡阶段
事件委托,利用事件冒泡的原理(子向父一层层穿透),将事件绑定到父元素,实现事件委托

🧐28:http1.0、1.1、2.0区别

http1.0:增加了post、delete、put等请求方式
http1.1:新增了connection连接keep-alive,host主机域
http2:1.heared压缩:HTTP/2压缩消息头,减少了传输数据的大小
2.多路复用: 即多个请求都通过一个TCP连接并发地完成
3.服务端推送: 服务端能够主动把资源推送给客户端
4.新的二进制格式: HTTP/2采用二进制格式传输数据,相比于HTTP/1.1的文本格式,二进制格式具有更好的解析性和拓展性

🧐29:浏览器是如何渲染页面的

第一步:客户机提出域名解析请求,并将该请求发送给本地的域名服务器。
第二步:当本地的域名服务器(DNS)收到请求后,就先查询本地的缓存,如果有该纪录 项,则本地的域名服务器就直接把查询的结果返回。
第三步:如果本地的缓存中没有该纪录,则本地域名服务器就直接把请求发给根域名服 务器,然后根域名服务器再返回给本地域名服务器一个所查询域(根的子域)的主域名服务器的 地址。
第四步:本地服务器再向上一步返回的域名服务器发送请求,然后接受请求的服务器查 询自己的缓存,如果没有该纪录,则返回相关的下级的域名服务器的地址。
第五步:重复第四步,直到找到正确的纪录。 渲染的流程: 1.解析HTML文件,创建DOM树。
自上而下,遇到任何样式(link、style)与脚本(script)都会阻塞(外部样式不阻塞 后续外部脚本的加载)。 2.解析CSS。优先级:浏览器默认设置<用户设置<外部样式<内联样式<HTML中的 style样式; 3.将CSS与DOM合并,构建渲染树(Render Tree) 4.布局和绘制,重绘(repaint)和重排(reflow)

🧐30:key的作用

用于 管理可复用的元素,标识数据的唯一性。因为Vue 会尽可能高效地渲染元素,通常会复用已有元素而不是从头开始渲染
key的作用主要是为了高效的更新虚拟DOM

🧐31:v-for和v-if为什么避免一起使用,解决办法

原因:因为v-for会比v-if先执行,每次循环都会执行一次v-if(每次渲染都会先循环再进行条件判断),避免性能的浪费
解决:①:通过template标签先判断在循环
②:如果条件出现在循环内部,可通过计算属性computed提前过滤掉那些不需要显示的项

🧐32:vue和react区别

①.监听数据变化的实现原理不同
(Vue通过 getter/setter以及一些函数的劫持,能精确知道数据变化。
React默认是通过比较引用的方式(diff)进行的,如果不优化可能导致大量不必要的VDOM的重新渲染。为什么React不精确监听数据变化呢?这是因为Vue和React设计理念上的区别,Vue使用的是可变数据,而React更强调数据的不可变,两者没有好坏之分,Vue更加简单,而React构建大型应用的时候更加鲁棒。)
②.数据流的不同
(Vue1.0中可以实现两种双向绑定:父子组件之间,props可以双向绑定;组件与DOM之间可以通过v-model双向绑定。Vue2.x中去掉了第一种,也就是父子组件之间不能双向绑定了(但是提供了一个语法糖自动帮你通过事件的方式修改),并且Vue2.x已经不鼓励组件对自己的 props进行任何修改了。
React一直不支持双向绑定,提倡的是单向数据流,称之为onChange/setState()模式。不过由于我们一般都会用Vuex以及Redux等单向数据流的状态管理框架,因此很多时候我们感受不到这一点的区别了。)
③.组件通信的区别
(Vue中有三种方式可以实现组件通信:父组件通过props向子组件传递数据或者回调,虽然可以传递回调,但是我们一般只传数据;子组件通过事件向父组件发送消息;通过V2.2.0中新增的provide/inject来实现父组件向子组件注入数据,可以跨越多个层级。
React中也有对应的三种方式:父组件通过props可以向子组件传递数据或者回调;可以通过 context 进行跨层级的通信,这其实和 provide/inject 起到的作用差不多。React 本身并不支持自定义事件,而Vue中子组件向父组件传递消息有两种方式:事件和回调函数,但Vue更倾向于使用事件。在React中我们都是使用回调函数的,这可能是他们二者最大的区别。)
④.模板渲染方式的不同
(在表层上,模板的语法不同,React是通过JSX渲染模板。而Vue是通过一种拓展的HTML语法进行渲染,但其实这只是表面现象,毕竟React并不必须依赖JSX。
在深层上,模板的原理不同,这才是他们的本质区别:React是在组件JS代码中,通过原生JS实现模板中的常见语法,比如插值,条件,循环等,都是通过JS语法实现的,更加纯粹更加原生。而Vue是在和组件JS代码分离的单独的模板中,通过指令来实现的,比如条件语句就需要 v-if 来实现对这一点,这样的做法显得有些独特,会把HTML弄得很乱。)
⑤.渲染过程不同
(Vue可以更快地计算出Virtual DOM的差异,这是由于它在渲染过程中,会跟踪每一个组件的依赖关系,不需要重新渲染整个组件树。
React在应用的状态被改变时,全部子组件都会重新渲染。通过shouldComponentUpdate这个生命周期方法可以进行控制,但Vue将此视为默认的优化。
如果应用中交互复杂,需要处理大量的UI变化,那么使用Virtual DOM是一个好主意。如果更新元素并不频繁,那么Virtual DOM并不一定适用,性能很可能还不如直接操控DOM。)
⑥.框架本质不同
(Vue本质是MVVM框架,由MVC发展而来;
React是前端组件化框架,由后端组件化发展而来)
⑦.Vuex和Redux的区别
(从表面上来说,store注入和使用方式有一些区别。在Vuex中,$store被直接注入到了组件实例中,因此可以比较灵活的使用:使用dispatch、commit提交更新,通过mapState或者直接通过this.$store来读取数据。在Redux中,我们每一个组件都需要显示的用connect把需要的props和dispatch连接起来。另外,Vuex更加灵活一些,组件中既可以dispatch action,也可以commit updates,而Redux中只能进行dispatch,不能直接调用reducer进行修改。
从实现原理上来说,最大的区别是两点:Redux使用的是不可变数据,而Vuex的数据是可变的,因此,Redux每次都是用新state替换旧state,而Vuex是直接修改。Redux在检测数据变化的时候,是通过diff的方式比较差异的,而Vuex其实和Vue的原理一样,是通过getter/setter来比较的,这两点的区别,也是因为React和Vue的设计理念不同。React更偏向于构建稳定大型的应用,非常的科班化。相比之下,Vue更偏向于简单迅速的解决问题,更灵活,不那么严格遵循条条框框。因此也会给人一种大型项目用React,小型项目用Vue的感觉。)

---------基础

---------------基础篇-------------

1rem、1em、1vh、1px各自代表的含义?

rem
rem是全部的长度都相对于根元素元素。通常做法是给html元素设置一个字体大小,然后其他元素的长度单位就为rem。
em
子元素字体大小的em是相对于父元素字体大小
元素的width/height/padding/margin用em的话是相对于该元素的font-size
vw/vh
全称是 Viewport Width 和 Viewport Height,视窗的宽度和高度,相当于 屏幕宽度和高度的 1%,不过,处理宽度的时候%单位更合适,处理高度的 话 vh 单位更好。
px
px像素(Pixel)。相对长度单位。像素px是相对于显示器屏幕分辨率而言的。
一般电脑的分辨率有{1920x1024}等不同的分辨率
1920x1024 前者是屏幕宽度总共有1920个像素,后者则是高度为1024个像素

画一条0.5px的直线?

考查的是css3的transform
height: 1px;
transform: scale(0.5);

javascript篇

JavaScript 有几种类型
基本数据类型:undefined、null、boolean、number、string、symbol(es6的新数据类型)
引用数据类型:object、array、function(统称为object)
数据类型检测
typeof 对于基本数据类型来说,除了 null 都可以显示正确的类型,typeof 对于对象来说,除了函数都会显示 object
Object.prototype.toString.call()可以检测所有的数据类型,算是一个比较完美的方法了
例:Object.prototype.toString.call({}).replace(/^\[object\s(\S+)\]$/, '$1') // Object
深浅拷贝
浅拷贝:Object.assign() //es6的方法
深拷贝:JSON.parse(JSON.stringify(obj))
用js实现一个深拷贝:其实深拷贝可以拆分成 2 步,浅拷贝 + 递归,浅拷贝时判断属性值是否是对象,如果是对象就进行递归操作,两个一结合就实现了深拷贝。
this 对象的理解
普通函数:
this 总是指向函数的直接调用者
如果有 new 关键字,this 指向 new 出来的实例对象
在事件中,this 指向触发这个事件的对象
IE 下 attachEvent 中的 this 总是指向全局对象 Window
箭头函数中:
函数体内的this对象,就是定义时所在作用域的对象,而不是使用时所在的作用域的对象。
apply、call、bind
call、apply和bind是Function对象自带的三个方法,都是为了改变函数体内部 this 的指向。
apply 、 call 、bind 三者第一个参数都是 this 要指向的对象,也就是想指定的上下文;
apply 、 call 、bind 三者都可以利用后续参数传参;
bind 是返回对应 函数,便于稍后调用;apply 、call 则是立即调用 。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值