面试题总结

12 篇文章 0 订阅

JS部分

call 与 apply

apply:调用一个对象的一个方法,用另一个对象替换当前对象。例如:B.apply(A, arguments);即A对象应用B对象的方法。
call:调用一个对象的一个方法,用另一个对象替换当前对象。例如:B.call(A, args1,args2);即A对象调用B对象的方法
都“可以用来代替另一个对象调用一个方法,将一个函数的对象上下文从初始的上下文改变为由thisObj指定的新对象”
apply:最多只能有两个参数——新this对象和一个数组argArray。如果给该方法传递多个参数,则把参数都写进这个数组里面,当然,即使只有一个参数,也要写进数组里。
apply()方法 接收两个参数,一个是函数运行的作用域(this),另一个是参数数组。
语法:apply([thisObj [,argArray] ]);,调用一个对象的一个方法,2另一个对象替换当前对象。

说明:如果argArray不是一个有效数组或不是arguments对象,那么将导致一个
TypeError,如果没有提供argArray和thisObj任何一个参数,那么Global对象将用作thisObj。

call()方法 第一个参数和apply()方法的一样,但是传递给函数的参数必须列举出来。

let obj3 = {
            age:10,
            fnt:function(gender){
                console.log(this.name+'性别:'+gender)
            }
        }
        let obj4 = {
            name:'小明',
            fnt:function(){
                console.log(this.age)
            }
        }
        obj4.fnt.call(obj3)
        obj3.fnt.apply(obj4,['男'])

在这里插入图片描述

都是在特定的作用域中调用函数,等于设置函数体内this对象的值,以扩充函数赖以运行的作用域。

js怎么创建私有变量

JS没有私有属性的概念;所有的属性都是公用的;
私有变量的概念:在任何函数中定义的变量,都是私有变量,因为不能在函数外部访问这些变量;

  • 私有变量:包括函数的参数/局部变量和函数内部定义的其他函数;
  • 特权使用:内部创建一个必报,必报可以直接访问私有变量;因此创建用于访问私有变量的公用方法,称为特权方法
  • 可以通过构造方法传参来访问私有变量,这种方法的缺点是会为每一个实例创建一组新的方法,不能实现共享。
js中命名函数与匿名函数的区别
  • 以函数声明的方式声明命名函数
    var baz = function e() {
    console.log(“bar2”);
    };

  • 以函数表达式的方式声明匿名函数
    var baz = function() {
    console.log(“bar2”);
    };

  1. 匿名函数不会被因为函数名而冲突掉
  2. 具名函数表达式可以明确地在调用栈中看到
for in 与for of
  1. for of 是遍历数组里的每一项,无法循环遍历对象
  2. for in循环遍历的是数组的键值(索引),而for of是循环遍历的是数组的值
  • for in 会遍历自定义属性,for of不会
		let arr = ['a','b','c','d']
        arr.name = "数组"
        for (const key in arr) {
            console.log(key,arr[key])
        }
        console.log('---分割线---')
        for (const item of arr) {
            console.log(item)
        }

noConflict()方法重新定义jquery默认的$符号

立即执行函数
宏任务和微任务
  • 表示异步任务的两种分类
    先执行宏任务,再执行微任务
    宏任务(macroTask):script 中代码、setTimeout、setInterval、I/O、UI render;
    微任务(microTask): Promise、Object.observe、MutationObserver。
Event Loop

Event Loop 是一个很重要的概念,指的是计算机系统的一种运行机制。
JavaScript语言就采用这种机制,来解决单线程运行带来的一些问题。
I/O操作很慢,所以这个线程的大部分运行时间都在空等I/O操作的返回结果。这种运行方式称为"同步模式"(synchronous I/O)或"堵塞模式"(blocking I/O)。
每当遇到I/O的时候,主线程就让Event Loop线程去通知相应的I/O程序,然后接着往后运行,所以不存在等待时间。等到I/O程序完成操作,Event Loop线程再把结果返回主线程。主线程就调用事先设定的回调函数,完成整个任务。

Object.freeze(obj)

冻结对象,不能修改,不能添加

on 和 addEventListener的区别
  • on下面的事件会替换掉前面的
  • addEventListener 都会触发
    在这里插入图片描述
  • 阻止事件冒泡:绑定在红色的div事件上
    e.stopPropagation();
aa.addEventListener('click',()=>{
           console.log('aaa')
           // true事件捕获,会先从外面触发
       },true)
防抖和节流

防抖:在限制的一定时间之内,我们只能让这个方法执行一次,最后一次的点击去执行
节流:在限制的时间内,只执行第一次

  • 防抖
//防抖debounce代码:
function debounce(fn,delay) {
    var timeout = null; // 创建一个标记用来存放定时器的返回值
    return function (e) {
        // 每当用户输入的时候把前一个 setTimeout clear 掉
        clearTimeout(timeout); 
        // 然后又创建一个新的 setTimeout, 这样就能保证interval 间隔内如果时间持续触发,就不会执行 fn 函数
        timeout = setTimeout(() => {
            fn.apply(this, arguments);
        }, delay);
    };
}
// 处理函数
function handle() {
    console.log('防抖:', Math.random());
}
        
//滚动事件
window.addEventListener('scroll', debounce(handle,500));
  • 节流
let btn = document.getElementById("btn")
       let timr = true
       const throuttle = (fn,delay) => {
           return () => {
               // 如果定时器没有走完里面的方法,则不往下走
               if(!timr) return
               timr = false
               setTimeout(() => {
                   fn()
                   timr = true
               }, delay);
           }
       }

       function success(){
           console.log('aaa')
       }
       btn.addEventListener('click',throuttle(success,2000))
值类型 /引用类型

值类型:数字 字符串 布尔值
引用类型:数组和对象

浅拷贝和深拷贝

深拷贝在计算机中开辟了一块内存地址用于存放复制的对象,而浅拷贝仅仅是指向被拷贝的内存地址,如果原地址中对象被改变了,那么浅拷贝出来的对象也会相应改变。
拷贝的对象的值中如果有函数,undefined,symbol,经过JSON.stringify()序列化后的JSON字符串中这个键值对会消失;

给数组对象添加一个新属性
let newArr = obj.map((item,index) =>{
   return Object.assign(item,{index:index})
})

ES6

import * as xxx from ‘xxx’

import * as xxx from ‘xxx’ 会将 “xxx” 中所有 export 导出的内容组合成一个对象返回(或import * as obj from ‘xx’ 这种写法是把所有的输出包裹到obj对象里)

import * as filters from '@/utils/filter'

Loadshjs

router与route的区别

route相当于当前正在跳转的路由对象。。可以从里面获取name,path,params,query等。
router为VueRouter的实例,相当于一个全局的路由器对象,里面含有很多属性和子对象,例如history对象。。。经常用的跳转链接就可以用this.$router.push,和router-link跳转一样

vue部分

脚手架中如何使用filter

utils文件夹中index文件

export const fmtGender = function (val) {
    return val ? '女' : '男'
}
export const fmtMoney = function (val) {
    return '$' + val
}

main 文件中

import * as filters from '@/utils/filter'
Object.keys(filters).forEach(key => {
    Vue.filter(key, filters[key])
})

在这里插入图片描述

虚拟dom和真实dom区别
  1. 虚拟dom不会进行排版与重绘操作
  2. 虚拟dom进行频繁修改,然后一次性比较并修改真实dom中需要修改的部分(注意),最后并在真实dom中进行排版与重绘,减少过多dom节点排版与重绘损耗
  3. 真实dom频繁排版与重绘的效率是相当低的
  4. 虚拟dom有效降低大面积(真实dom节点)的重绘与排版,因为最终于真实dom比较差异,可以只渲染局部(同2)
  • 总之,一切为了减弱频繁的大面积重绘引发的性能问题,不同框架不一定需要虚拟dom,关键是看框架是否频繁
虚拟dom的缺点

无法进行极致优化: 虽然虚拟 DOM + 合理的优化,足以应对绝大部分应用的性能需求,但在一些性能要求极高的应用中虚拟 DOM 无法进行针对性的极致优化

虚拟dom的实现原理
  1. 用 JavaScript 对象模拟真实 DOM 树,对真实 DOM 进行抽象
  2. diff 算法 — 比较两棵虚拟 DOM 树的差异;
  3. pach 算法 — 将两个虚拟 DOM 对象的差异应用到真正的 DOM 树。
小程序与vue传参
  • 小程序组件之间传参
  • 调用组件的page
//wxml
<selectMenu bind:select="selectCity" list="{{cityList}}" title="城市"> </selectMenu>

//wxjs
selectCity(e){
    this.setData({
    currentCityid:e.detail.id
    })
this.getShowlist()
},
  • 组件内的js
// 外面属性传过来的需要在里面声明属性
properties: {
title:{
type:String
},

methods: {
    select(e) {
    let obj = this.data.list[this.data.activeIndex]
    // 这边是事件发生,那边是select监听的,后面是需要传过去的东西
    this.triggerEvent("select", obj )
    }
}
  • 组件的wxml
<view wx:key="id" bindtap="select" >{{item.name}}</view>

  1. 父往子用props子往父用$emit
  2. 祖孙之间使用依赖注入
//祖代组件
provide: function() {
      return {
          //
      }
    },
//孙代组件
// 通过inject接收 
inject: ['obj'],
  1. 同级兄弟:使用中央事件总线,创造单独的vue实例利用$on监听 $emit触发
  • 事件传参
  1. 小程序是通过data- id= "{{item.id}}"将id传入到js中,js中在事件的e的对象中获取传入的值
//wxml
<view class="pergoods" wx:for='{{goods}}' bindtap="jumpDetail" data-detail="{{item}}" data-id='{{item.id}}' wx:key='index'>
//wxjs

jumpGoods(e) {
let id = e.currentTarget.dataset.id;
}
  1. vue是直接将所需要传的参数方法事件中,在事件方法的e中直接获取
<div v-for="(item, index) in list" :key="item.id" @click="tap(item.id)">
methods: {
    tap(id){
        console.log(id)
    }
},
  • 跳转页面时传参

  • 小程序中页面跳转时的传参

  1. 在前往的页面URL后面跟上参数
wx.navigateTo({
url: '../goodspage/goodspage?ti=' + detail + '&tt=' + index
})
  1. 在目标页面的初次渲染的函数中获取参数
onLoad: function (options) {
    options是传入的所有参数的对象展示出来
},
vue-loader

v-loader是加载器,作用是编译成浏览器可以识别的代码,能把.vue组件转化成JavaScript模块

  • 为什么我们要转译这个vue组件
    可以动态的渲染一些数据
    对三个标签都做了优化,script中可以直接使用es6 style也默认可以使用sass,并且提供了作用域的作用
    另外开发阶段,还提供了热加载
    还可以在标签上直接src引用
  • 懒加载是延迟加载
  • 预加载是提前加载
  • template 是结构 script是行为 style是表现

webpack常用的插件

ProvidePlugin

vue.nextTick()
  • 在下次 DOM 更新循环结束之后执行延迟回调。在修改数据之后立即使用这个方法,获取更新后的 DOM。简单解释:当数据更新了,在dom中渲染后,自动执行该函数
    与setInterval(() => { }, 0); 作用一样。
怎么实现双向绑定的

Object.defineProperty() 方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象。

let obj = {}
        let age = 20
        Object.defineProperty(obj, 'age', {
            // get 和 set自动调用
            get() {
                console.log('有人访问')
                // 修改的值返回出去
                return age
            },
            set(val) {
                // if(isNaN(val)) throw "非正整数"  throw 抛出异常
                console.log('有人赋值了')
                age = val
                app.innerHTML = obj.age
            }
        })
vue$set

向响应式对象中添加一个属性,并确保这个新属性同样是响应式的,且触发视图更新。它必须用于向响应式对象上添加新属性,因为 Vue 无法探测普通的新增属性

  • 一个对象或者数组修改时,页面没有相应
Vue.set(vm.items, indexOfItem, newValue)
// vm.$set,Vue.set的一个别名
vm.$set(vm.items, indexOfItem, newValue)
// Array.prototype.splice
vm.items.splice(indexOfItem, 1, newValue)

//
vm.items.splice(newLength)
  • v-model 的原理
    是语法糖 @input + :vaule
vue-router

小程序部分

一个小程序中怎么从一个小程序跳到另一个小程序
"navigateToMiniProgramAppIdList": [
	 "目标小程序的appid"
 ],
小程序里面怎么直接返回首页

小程序适配各个机型
小程序登录授权
wx.getUserInfo
<button open-type="getUserInfo" bindgetuserinfo="bindGetUserInfo">点击授权</button>
bindGetUserInfo(res) {
  let info = res;
  if (info.detail.userInfo) {
    console.log("点击了同意授权");
    wx.login({
      success: function (res) {
        console.log(res);
      }
    })
  } else {
    console.log("点击了拒绝授权");
  }
  • 判断是否登录
wx.checkSession({
  success () {
    //session_key 未过期,并且在本生命周期一直有效
  },
  fail () {
    // session_key 已经失效,需要重新执行登录流程
    wx.login() //重新登录
  }
})
  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值