欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

常见问题

程序员文章站 2022-07-07 20:19:32
...

es6

  1. let 和var 的区别:var作用域为所在函数内,let作用域为语句所在代码块,不存在变量提升且不允许重复声明

  2. 为什么var可以重复声明:

    当我们执行代码时,我们可以简单的理解为新变量分配一块儿内存,命名为 a,并赋值为 2,但在运行的时候编译器与引擎还会进行两项额外的操作:判断变量是否已经声明:首先编译器对代码进行分析拆解,从左至右遇见 var a,则编译器会询问作用域是否已经存在叫 a 的变量了,如果不存在,则招呼作用域声明一个新的变量 a,若已经存在,则忽略 var 继续向下编译,这时 a = 2被编译成可执行的代码供引擎使用。引擎遇见 a=2时同样会询问在当前的作用域下是否有变量 a,若存在,则将 a赋值为 2(由于第一步编译器忽略了重复声明的var,且作用域中已经有 a,所以重复声明会发生值得覆盖而并不会报错)。若不存在,则顺着作用域链向上查找,若最终找到了变量 a则将其赋值 2,若没有找到,则招呼作用域声明一个变量 a并赋值为 2

  3. 箭头函数:

    1)跟普通函数的区别:箭头函数内的this继承自外围作用域
    2)普通函数的this指向调用它的那个对象
    3)箭头函数是匿名函数,不能作为构造函数,不能使用new
    4)箭头函数在定义之后this就不会改变,无论用super(),arguments都不会改变
    5)箭头函数不绑定arguments
    6)普通函数达到箭头函数的效果的方法:
    定义一个局部变量:_self = this

var obj = {
  name:"hha",
  fn:() => {
    console.log(this) // window
  },
  fnn(){
    console.log(this) // obj
  },
  fn2:{
    fn3:() => {
      console.log(this) // window
    }
  },
  c: function() {
     return ()=>{
           console.log(this) // obj
           console.log(this.name); //hha
     }
  }
}
obj.fn() // Window
obj.fn1() // obj
obj.fn2.fn3() // Window
obj.c()() // obj,hha
var obj = {
  name: 'hah',
  fn: function () {
    console.log(this) // obj
  },
  fn1() {
    console.log(this) // obj
  },
  fn2: {
    fn3: function () {
      console.log(this) // fn2
    }
  }
}
obj.fn() // obj
obj.fn1() // obj
obj.fn2.fn3() // fn2

3.promise

promise接收一个函数作为参数,这个函数有两个方法作为参数,resolve和reject,当异步操作成功后我们调用resolve函数,将异步任务的结果作为参数传递出去,失败的时候调用reject去处理,他的then方法可以接受两个回调作为参数,一个是resolve,一个就是reject
有3个状态pending,resolve,reject

js

原型链:

每个对象都有一个proto属性指向创建该对象的构造函数的原型,
每个函数都有一个prototype属性指向原型

new的时候发生了什么:
1.新生成了一个对象
2.链接到原型
3.绑定 this
4.返回新对象

https://juejin.im/entry/5883672c570c350062be16e5(转载参考)

常见问题

常见问题

闭包:
  1. 闭包的定义很简单:函数 A 返回了一个函数 B,并且函数 B 中使用了函数 A 的变量,函数 B 就被称为闭包。

2.js的数据类型

基本数据类型:Undefined、Null、Boolean、Number和String,

复杂的数据类型:object、Array、Function...引用类型,

typeof(null) // 返回Object(表示空指针) 

3.深拷贝和浅拷贝

1)浅拷贝只将对象的各个属性依次复制,深拷贝则递归复制了所有层级

2)浅拷贝区别:因为js存储对象都是存地址,所以浅拷贝会造成:shallowObj.arr[1] = 5;obj.arr[1]   // = 5

3)深拷贝会生成一个新对象,深拷贝会影响性能吧,如果层级很多的话

4)方法:浅拷贝:jquery: extend(deep,target,object1,objectN):
let b = Object.assign({},a)
or
var a = {age:88}
let b = {...a}

deep类型: Boolean
如果是 true,合并成为递归(又叫做深拷贝)。不支持给这个参数传递 false

target类型: Object
对象扩展。这将接收新的属性。

object1类型: Object
一个对象,它包含额外的属性合并到第一个参数.

objectN类型: Object
包含额外的属性合并到第一个参数

4.如何区别node环境和浏览器环境

1)node中this指向global,浏览器中this指向window

2)在浏览器中的window下不少的API 比如 alert 、document、location、history 等等还有很多。我门就不能在node环境中xxx();或window.xxx();了。因为这些API是浏览器级别的封装,纯javascript中是没有的。

5.prototypehe proto的区别

1):对象有属性——proto指向对象的构造函数的原型对象

2)方法除了有属性proto,还有属性prototype,prototype指向该方法的原型对象:

6.mouseover和 mouseenter有什么区别:

1)mouseenter不会冒泡

2)当两者绑定的元素均没有子元素的时候两者无差

3)有子元素时mouseover经过绑定元素和资源苏都会触发

7.移动端的click事件和PC的不同

1)移动端的click会延迟300ms触发事件回调,
部分厂商为了识别翻页或者双击放大等复杂手势所以加了300ms延迟处理

2)PC不需要,设置了禁止缩放的不需要user-scalable=no

3)解决方法:引入fastclick.js解决,

他的原理是fastclick在检测到touchend事件的时候,
会通过DOM自定义事件立即触发一个模拟click事件,
并把浏览器在300ms之后真正触发的click事件阻止掉

在main.js中引入,并绑定到document.body上

import FastClick from 'fastclick'

FastClick.attach(document.body);

8.移动端点击穿透,原理及解决方法

1)点击穿透是指在移动端click事件延迟300ms触发,那么如果300ms内,页面显示变化(主要指DOM的隐藏和显示)的话,会实际点击元素触发touch事件,而300ms后该位置的实际元素又被再次click:

2)几种现象:
点击蒙层(mask)上的关闭按钮,蒙层消失后发现触发了按钮下面元素的click事件。蒙层的关闭按钮绑定的是touch事件,而按钮下面元素绑定的是click事件,touch事件触发之后,蒙层消失了,300ms后这个点的click事件fire,event的target自然就是按钮下面的元素,因为按钮跟蒙层一起消失了。

跨页面点击穿透问题:如果按钮下面恰好是一个有href属性的a标签,那么页面就会发生跳转。因为 a标签跳转默认是click事件触发 ,所以原理和上面的完全相同。

另一种跨页面点击穿透问题:这次没有mask了,直接点击页内按钮跳转至新页,然后发现新页面中对应位置元素的click事件被触发了。

  1. 事件委托

    1)事件委托是指利用“事件冒泡”,只通过指定一个事件处理程序,来管理某一类型的所有事件。也就是说,当此事件处理程序被触发时,通过当前事件对象中的target来确认究竟是在哪个元素触发的事件,从而达到一次注册 处理多个元素触发事件的目的。https://www.cnblogs.com/liugang-vip/p/5616484.html

10.什么是事件循环

1)JavaScript是单线程的,“主线程”负责执行所有的同步任务,一旦所有同步任务执行完成,则立即从“任务队列”中读取最优先的任务放到“主线程”中执行,如此循环往复。向“任务队列”插入的是一个个事件处理函数(确切的说是函数地址)或定时任务(setTimeout的回调)。

11.css3中有哪些属性可以直接影响JS中的事件?(可以讲一下pointer-events和touch-action属性吗)–过吧,浪费时间

  1. js的继承:

    1)继承就是通过将父类的实例作为子类的原型,让子类拥有父类的属性和方法,
    可以通过寄生组合方式:es5:

        function parent(name){
            this.name = name
        }
        parent.prototype.getNama = function () {
            // do..
        }
        function child (age) {
            parent.call(this,namae)
            this.age = age
        }
        child.prototype = new parent()
        child.prototype.constructor = child
        child.prototype.getAge = function () {
            // do
        }
        var a = new child("name","age")
        a.getName()
        a.getAge()

es6

        class parent {
            constructor(name) {
                this.name = name
            }
            getName() {
                // do
            }
        }
        class child extends parent {
            constructor (name,age) {
                super(name)
                this.age = age
            }
            getAge() {
                // do
            }
        }

13.

1)arguments: 由此,我们可以使用arguments对象来获取实参,或者判断参数个数等
常见问题

2)实现方法的重载:

  1. 实现参数相加的函数
function add() {
    var len = arguments.length;
    var result = 0;
    for (var i = 0; i < len; i++) {
        result += arguments[i] 
    }
    return result
}

2.利用arguments.callee实现递归:

// 方法一
// 实现阶乘:5*4*3*2*1
function a (num) {
    if (num <= 1) {
        return 1
    } else {
        return num*a(num-1)
    }
}
//当这个函数变成了一个匿名函数时,我们就可以利用callee来递归这个函数。es4禁用了这个属性
// 方法二
function a (num) {
    if (num <= 1) {return 1}
    else {
        num*arguments.callee(num)
    }
}

数组去重:

// 方法一:
//indexof,判断当前循环的数组下标不是当前的i,则表示该数据重复
var arr = [1,2,2,3,'yy', 'lu','lu',1,5,6,5]
function doit (arr) {
  var temp = []
  for (let i = 0; i < arr.length; i++) {
    if (arr.indexOf(arr[i]) === i) {
      temp.push(arr[i])
    }    
  }
  return temp
}
doit(arr)

// 方法2:indexOf() === -1 ,不存在
//建立新数组,判断当前循环的值在新数组中是否存在,不存在就push
var arr = [1,2,2,3,'yy', 'lu','lu',1,5,6,5]
function doit (arr) {
  var temp = []
  for (let i = 0; i < arr.length; i++) {
    if (temp.indexOf(arr[i]) === -1) {
      temp.push(arr[i])
    }    
  }
  return temp
}
doit(arr)
方法3: es6的set()方法

var arr = [1,2,2,3,'yy', 'lu','lu',1,5,6,5]
function doit(arr) {
    var x = new Set(arr)
    return [...x]
}
var newArr = doit(arr)

缓存机制

  1. 强缓存(返回200)和协商缓存(命中缓存304)
  2. 强缓存:expires和cache-control:后者的优先级高于前者。
  3. 协商缓存,1,last-modified(文件的最后修改时间),if-last-modified发送last-modified到服务端,
  4. 协商缓存,2, etag(文件指纹),if-no-match会把etag发送给服务端,如果有跟新则返回更新资源

cookie,localstorage,sessionStorage

常见问题

jsonp的原理

利用script标签引用的文件没有同源限制,src访问服务端地址,服务端返回预先定义好的函数的调用。以及可以传递参数之类的。

网络安全

1、XSS: 通过执行js代码来攻击

防御:1、最普遍的做法是转义输入输出的内容,对于引号,尖括号,斜杠进行转义
2、建立白名单,规定了浏览器只能够执行特定来源的代码。HTTP header 中 Content-Security-Policy首部设置

2、CSRF: 跨站请求伪造

防范 CSRF 可以遵循以下几种规则:
Get 请求不对数据进行修改
不让第三方网站访问到用户 Cookie—cookie设置SameSite
阻止第三方网站请求接口–refer
请求时附带验证信息,比如验证码或者 token

webpack如何配置多页面

1.创建多个HtmlWebpackPlugin:

new HtmlWebpackPlugin({
    filename: 'a.html',
    template: './a.html',
    chunks: ['common']
}),
new HtmlWebpackPlugin({
    filename: 'index.html',
    template:'./index.html',
    chunks: ['app','common']
})

call,apply,bind

// 输出最大值458,a本身没有max方法,通过call和apply方法实现继承Math的max方法
var  numbers = [5, 458 , 120 , -215 ]; 
var a = {}
var maxInNumbers = Math.max.apply(a, numbers)
//或者
var maxInNumbers = Math.max.call(a,5,458,120,-215)
//或者
var maxInNumbers = Math.max.call(a,5,458,120,-215)
maxInNumbers() // 使用bind的话不会立即执行,所以要执行一次maxInNumbers()才能返回最大值

vue的双向绑定原理

1、有一个observer的数据监听器,可以对对象上的属性进行监听,如果有变动就可拿到最新值并通知订阅者,

observer的实现:通过Object.definproperty()来截止各个属性的get和set,监听属性的变动,然后通知订阅者

2、有一个指令解析器compile。对每个元素节点进行指令扫描解析,根据指令模板替换数据,以及绑定相应的更新函数,

3、有一个watcher,连接observer和compile,能够订阅并收到每个属性的变动通知,执行指令绑定的的相应的回调函数,从而更新视图

1、在自身实例化时往属性订阅器(dep)里面添加自己
2、自身必须有一个update()方法
3、待属性变动dep.notice()通知时,能调用自身的update()方法,并触发Compile中绑定的回调,则功成身退。
如果有点乱,可以回顾下前面的思路整理

vue 的生命周期

beforeCreate: vue实例的挂载元素$el和数据对象data都为undefined

created: 该阶段vue实例的数据对象data有了,$el还没有

beforeMount: $el和data开始初始化,但还是挂载前的的虚拟DOM,

mounted:$el挂载完成,data渲染成功

beforeUpdate:data变化会触发beforeUpdate和updated
updated:

beforeDestroy:执行destroyed后data的改变不会触发数据变动监听,说明已经解除了事件监听和Dom的绑定,但dom结构还存在
destroyed

平时代码里都用过哪些优化的写法

1.for循环一个变量的属性的时候,应该使用一个临时变量,比循环一个data.data会好点–这个应该算吧?
2.

有哪些模块化规范

require和import的区别?