题库2

72 阅读16分钟

数组去重的方法

set
function removeDuplicates(array) { return [...new Set(array)]; }
filter 结合 indexof
let arrs = [6,1,2,3,5,3,6]; 
let newArrs = arrs.filter((item,index,self)=>{ return self.indexOf(item) === index })

数据类型:string boolean number undefined null object array function symbol bigint

BigInt类型不能和内置函数Math共同使用 BigInt不能和number类型进行运算, 只能和同为BigInt的数字进行运算 BigInt可以和number进行比较 BigInt不能转小数, 只能转整数, 遇到不是数字的情况(布尔值或者[] )内部应该会尝试先将其转为数字

数据类型的检测

一、typeof typeof在对值类型number、string、boolean、symbol、 undefined、 function的反应是精准的; 但对于对象{ } 、数组[ ] 、null都会返回 object

二、instanceof 来判断该对象是谁的实例 用 instanceof 判断一个实例是否属于某种类型 instanceof 运算符只能用于对象,不能用于原始类型的值

// 检测构造函数B的原型是否有出现在对象A的原型链上。 A instanceof B

[] instanceof Array // true

[].proto == Array.prototype // true

三、constructor

constructor 是每个实例对象都拥有的属性
console.log(("1").constructor === String); // true
console.log((1).constructor === Number); // true
console.log((NaN).constructor === Number); // true
console.log((true).constructor === Boolean); // true
console.log(([]).constructor === Array); // true
console.log((function () {}).constructor === Function); // true
console.log(({}).constructor === Object); // true
console.log((Symbol(1)).constructor === Symbol); // true 
console.log((null).constructor === Null); // 报错
console.log((undefined).constructor === Undefined); // 报错
用costructor来判断类型看起来是完美的,然而,如果我创建一个对象,更改它的原型,这种方式也变得不可靠了。

四、Object.prototype.toString.call()

// 定义检测数据类型的功能函数 function checkedType(target) { return Object.prototype.toString.call(target).slice(8, -1); }

console.log(checkedType(1)); // Number console.log(checkedType("1")); // String console.log(checkedType(NaN)); // Number console.log(checkedType(true)); // Boolean console.log(checkedType(Symbol(1))); // Symbol console.log(checkedType(null)); // Null console.log(checkedType(undefined)); // Undefined console.log(checkedType([])); // Array console.log(checkedType({})); // Object console.log(checkedType(function () {})); // Function

Object.defineProperty

function update() {  
    app.innerText = obj.foo  
}    
function defineReactive(obj, key, val) {  
    Object.defineProperty(obj, key, {  
        get() {  
            console.log(`get ${key}:${val}`);  
            return val  
        },  
        set(newVal) {  
            if (newVal !== val) {  
                val = newVal  
                update()  
            }  
        }  
    })  
}
  • 检测不到对象属性的添加和删除
  • 数组API方法无法监听到(例如push pop)添加删除监听不到
  • 需要对每个属性进行遍历监听,如果嵌套对象,需要深层监听,造成性能问题

proxy

Proxy的监听是针对一个对象的,那么对这个对象的所有操作会进入监听操作,这就完全可以代理所有属性了

var proxy = new Proxy(target, handler)

target表示所要拦截的目标对象(任何类型的对象,包括原生数组,函数,甚至另一个代理))

handler通常以函数作为属性的对象,各属性中的函数分别定义了在执行各种操作时代理 p 的行为

### handler解析

关于`handler`拦截属性,有如下:

-   get(target,propKey,receiver):拦截对象属性的读取
-   set(target,propKey,value,receiver):拦截对象属性的设置
-   has(target,propKey):拦截`propKey in proxy`的操作,返回一个布尔值
-   deleteProperty(target,propKey):拦截`delete proxy[propKey]`的操作,返回一个布尔值
-   ownKeys(target):拦截`Object.keys(proxy)``for...in`等循环,返回一个数组
-   getOwnPropertyDescriptor(target, propKey):拦截`Object.getOwnPropertyDescriptor(proxy, propKey)`,返回属性的描述对象
-   defineProperty(target, propKey, propDesc):拦截`Object.defineProperty(proxy, propKey, propDesc)`,返回一个布尔值
-   preventExtensions(target):拦截`Object.preventExtensions(proxy)`,返回一个布尔值
-   getPrototypeOf(target):拦截`Object.getPrototypeOf(proxy)`,返回一个对象
-   isExtensible(target):拦截`Object.isExtensible(proxy)`,返回一个布尔值
-   setPrototypeOf(target, proto):拦截`Object.setPrototypeOf(proxy, proto)`,返回一个布尔值
-   apply(target, object, args):拦截 Proxy 实例作为函数调用的操作
-   construct(target, args):拦截 Proxy 实例作为构造函数调用的操作
function reactive(obj) {  
    if (typeof obj !== 'object' && obj != null) {  
        return obj  
    }  
    // Proxy相当于在对象外层加拦截  
    const observed = new Proxy(obj, {  
        get(target, key, receiver) {  
            const res = Reflect.get(target, key, receiver)  
            console.log(`获取${key}:${res}`)  
            return res  
        },  
        set(target, key, value, receiver) {  
            const res = Reflect.set(target, key, value, receiver)  
            console.log(`设置${key}:${value}`)  
            return res  
        },  
        deleteProperty(target, key) {  
            const res = Reflect.deleteProperty(target, key)  
            console.log(`删除${key}:${res}`)  
            return res  
        }  
    })  
    return observed  
}

原文

map 键值对

  1. 双列集合一次存储一对数据,分别为键和值
  2. 键不能重复,值可以重复
  3. 键和值是一一对应的,每一个键都对应一个值
  4. 键+值整体称为键值对,也叫Entry对象

set 没有重复的集合 (类似数组没有重复子项)

1、undefined 和 null 有什么区别?

  • undefined:undefined是一个特殊值,表示变量已声明但未初始化时的值。
  • null:null是一个对象,一个准备用来保存对象,还没有真正保存对象的值。从逻辑角度看,null值表示一个空对象指针,即表示一个对象被定义了,但是值为“空值”。

2、JavaScript中的虚值是什么?

简单的来说虚值就是在转换为布尔值时变为 false 的值。

falsenullundefinedNaN0 +0 -0、空字符串(""''``)

 

3、什么是作用域?

    全局变量和局部变量

4、use strict 是干什么用的?

"use strict"​​ 是 ES5 特性,它使我们的代码在函数或整个脚本中处于==严格模式==。严格模式帮助我们在代码的早期避免 bug,并为其添加限制。

`严格模式的一些限制:

1、变量必须声明后再使用

2、函数的参数不能有同名属性,否则报错

3、不能使用​​with​​语句

4、不能对只读属性赋值,否则报错

5、不能使用前缀 0 表示八进制数,否则报错

6、不能删除不可删除的属性,否则报错

7、不能删除变量​​delete prop​​,会报错,只能删除属性​​delete global[prop]​​

8、​​eval​​不能在它的外层作用域引入变量

9、​​eval​​和​​arguments​​不能被重新赋值

10、​​arguments​​不会自动反映函数参数的变化 不能使用​​arguments.callee​​

11、不能使用​​arguments.caller​​ 禁止​​this​​指向全局对象 不能使用​​fn.caller​​和​​fn.arguments​​获取函数调用的堆栈 增加了保留字(比如​​protected​​、​​static​​和​​interface​​)

5、什么情况下不能使用箭头函数?

  • 请不要在原型链中使用箭头函数
  • 请不要在对象的方法中使用箭头函数。
  • 请不要在构造函数中使用箭头函数
  • 请不要在点击事件中操作this

 

6、Object.freeze和Object.seal

Object.seal 就是封闭某个对象

1)阻止添加新属性

2)现有属性变得不可配置(non-configurable)

1、不可以通过delete去删除该属性从而重新定义属性; 2、不可以转化为访问器属性; 3、configurable和enumerable不可被修改; 4、writable可单向修改为false,但不可以由false改为true; 5、value是否可修改根据writable而定。

Object.freeze 一旦对象被设置成freeze也就意味着被冻结 ,就被固定死了,什么都不可以改变,不能删除对象修改对象重新设置对象,Object的defineProperty里面的属性都不能改变了。

const 和 Object.freeze() 不同,const 防止重新分配,而 Object.freeze() 防止可变性。

 

7、小程序登录流程

 

8、小程序是分层的

 

9、ajax 、axios、fetch 区别

 

 

10、跨域问题

1)jsonp是怎么实现的

 

11、http、https的区别?

 

12、项目中单点登录如何实现的?

13、对箭头函数的理解

14、前端账号两小时失效如何做的

 

一:进程跟线程

进程是cpu分配的最小单位,线程是cpu调度的最小单位

进程有:

1.主进程:浏览器的页面显示,用户交互,前进,后退,收藏,其它子进程的创建销毁,网络请求,网络访问

2.GPU进程:UI绘制

3.渲染进程:将HTML,CSS 转换成网页

4.network Service进程:资源加载

渲染进程的线程

  1. JS引擎线程:解析和执行js脚本,单线程
  2. GUI渲染线程:负责渲染页面,布局和重绘。当触发回流和重绘的时候触发GUI线程
  3. 事件触发线程
  4. 定时触发器线程

异步http请求线程

二:输入url发生了什么

    1. 浏览器进程检查url,组装协议,构成完整url
    2. 浏览器进程通过进程间通信,把url发给网络进程
    3. 网络进程查看该url是否有本地缓存,如果有就返回给浏览器进程
    4. 如果没有,网络进程向web服务器发起http请求
    5. 4.1 进行DNS解析,获取IP地址(首先在本地DNS缓存里查找)
    6. 4.2 利用ip地址和端口建立TCP连接
    7. 4.3 构建请求头信息并发送
    8. 4.4 服务器响应后,网络进程接受响应头和响应数据,并解析其内容
    9. 网络进程响应
    10. 5.1 检查这状态码,如果是301、302,则从location中读取地址,重新请求
    11. 5.2 200处理:检查Content-Type,如果是字节流类型,则提交给下载管理器,不再进行后续渲染;如果是html则通知浏览器进程准备进行渲染
    12. 准备渲染进程
    13. 传输数据,更新状态
    14. 7.1 渲染进程准备好后,浏览器进程向渲染进程发起消息,渲染进程收到消息后和网络进程建立传输数据的管道
    15. 7.2 渲染进程接收完数据后,向浏览器进程回复消息
    16. 7.3 浏览器进程收到消息后更新浏览器界面状态
一、浏览器查找输入域名的IP地址(拿到 IP1、查找浏览器缓存(浏览器一般会缓存DNS记录一段时间,一般为2-30分钟)。

2、查找系统缓存(即hosts文件,有没有对应的IP3、以上都没有的话,就会经过DNS域名服务器进行域名解析

二、建立TCP连接(三次握手)

1、你在家么有外卖

2、我在家,你来吧

3、好的,我这就去

三、发送Http请求

四、服务器处理请求

五、返回响应结果

六、关闭TCP连接

七、浏览器解析html

八、浏览器布局渲染

渲染进程渲染页面

宏任务:

setTimeout

setInterval

setImmediate

requestAnimationFrame

微任务:

  1. process.nextTick
  2. MutationObserver
  3. Promise.then catch finally
<https://blog.csdn.net/mrszhang111/article/details/126861669>

>

> (1)宏任务一般是:script、setTimeoutsetInterval、postMessage、MessageChannelsetImmediate(Node.js 环境)

> (2)微任务:Promise.thenObject.observeMutationObserver、process.nextTick(Node.js 环境)

 

执行顺序:先执行同步代码,遇到异步宏任务则将异步宏任务放入宏任务队列中,遇到异步微任务则将异步微任务放入微任务队列中,当所有同步代码执行完毕后,再将异步微任务从队列中调入主线程执行,微任务执行完毕后再将异步宏任务从队列中调入主线程执行,一直循环直至所有任务执行完毕。

这里容易产生一个错误的认识:就是微任务先于宏任务执行。实际上是==先执行同步任务然后在执行异步任务,异步任务是分宏任务和微任务==两种的。

watch与computed区别


-   computed支持缓存,相依赖的数据发生改变才会重新计算;watch不支持缓存,只要监听的数据变化就会触发相应操作
-   computed不支持异步,当computed内有异步操作时是无法监听数据变化的;watch支持异步操作
-   computed属性的属性值是一函数,函数返回值为属性的属性值,computed中每个属性都可以设置set与get方法。watch监听的数据必须是data中声明过或父组件传递过来的props中的数据,当数据变化时,触发监听器

class

static:静态属性,静态属性是只有类本身才能访问的, 
静态属性通过static关键字来定义,或者直接Person.xxx
    通过static关键字设置的静态属性直接挂在Person类对象上了,
    实例属性都是挂在prototype上的

类的私有属性:this.#age 类的私有属性只能在当前类中访问

public:我理解都一样,挂在原型链下,如果有子类继承该类,也能访问修改 

static:静态属性,可通过类访问Person.xxx,

private:类成员只能在类中被访问。

public:类的所有成员都可以被类的实例获取。

protected:类成员在类以及子类中可以被访问

 

```js
class Parent {
    custructor(car) {
        // 构造函数,在生成实例时,会调用
        this.#age = '15';  //前面加#为私有属性,只能在class内部使用,如果想外部使用可以写个方法暴露出去
        this.#weight = '11';
        this.#bf='lijongsuk' 
        this.car = car
        this.doSomething = function(){
          console.log('aaa')
        };
    }
    #returnAMessage() { //私有方法
        return "You will do great things in life";
    }
    greet() {
      return this.#age  //向外暴露私有属性
    }
    // 挂在原型链下,如果有子类继承该类,也能访问
    sayHi() {
        console.log('hi')    
    }
 
   
    static things = '手机'
 
    // 加不加public我理解都一样,挂在原型链下,如果有子类继承该类,也能访问修改
    public sayYes() {
       console.log('yes')    
    }
    // 私有属性或方法,实例无法直接访问,可以间接访问,比如实现一个公共方法来修改访问,实例可以调用公共方法实现修改
    private noCount = 0
 
    sayNo() {
       console.log('no') 
       noCount += 1
    }
 
}

闭包

```js
在一个外函数中定义了一个内函数,内函数里运用了外函数的临时变量,并且外函数的返回值是内函数的引用。这样就构成了一个闭包。

①必须有一个内嵌函数(函数里定义的函数)——这对应函数之间的嵌套 
②内嵌函数必须引用一个定义在闭合范围内(外部函数里)的变量——内部函数引用外部变量 
③外部函数必须返回内嵌函数——必须返回那个内部函数

### 闭包的使用场景

可以实现变量的私有化

### 优点

当我们需要对一个变量进行私有化控制的时候,可以使用闭包函数。同时在函数内部可以对局部变量进行临界值控制等操作。

### 缺点

使用闭包函数,也就引申出了一个内存泄漏的问题

**由于js内存回收机制是标记清除法**,就是一个数据在有引用的情况下,不会被释放,因为闭包内的数据在外部有使用,所以不会被释放

 

解决方法:给外部应用的变量赋值为null

 

```js
function fn() {
    let a = 1
    function inner() {
       console.log(a)
    }
    return inner
}
 
let result = fn()
result()
result=null  //可以释放变量

数据类型检测

typeof:检测数据类型

-   可以把数据类型当作字符串返回,返回值是一个字符串 所以 typeof(typeof(a)) //string

typeof null; //"object" 因为特殊值null被认为是一个空的对象引用。 ==局限:对于array、null和对象,typeof一律返回object。对此可以通过instanceof来区分。==

typeof对于基本数据类型判断是没有问题的,但是遇到引用数据类型(如:Array,返回object)是不起作用的。

instanceof:判断一个变量是否是某个对象的实例 返回一个boolean 值

instanceof 运算符判断一个对象是否是另一个对象的实例。返回truefalse

instanceof 运算符用来检测 constructor.prototype 是否存在于参数 obj 的原型链上(或者说:检测obj的原型链上是否存在constructor.prototype )

 
 缺点:
  1.只适用于对象类型,对引用类型的判断较为准确。
  2.只要当前的这个类在实例的原型链上,检测出来的结果都是true




  console.log("1" instanceof String); //false(
  new Number(1) instanceof Number //true
  console.log(1 instanceof Number); //false
  console.log(true instanceof Boolean); //false
  console.log([] instanceof Array); //true
  console.log(function(){} instanceof Function); //true
  console.log({} instanceof Object); //true


constructor :属性返回对创建此对象的数组函数的引用。 
-   优点:对基本类型和引入类型都可以判断。  
-   缺点:无法判断 nullundefined ,而且 constructor 是可以修改的,会导致检查结果不准确。 
var test=new Array(); test.constructor==Array //true 

Object.prototype.toString.call() 来判断数据类型
 
Object.prototype.toString.call(12)//[boject Number]
Object.prototype.toString.call(true)//[boject Boolean]

var a = Object.prototype.toString;
console.log(a.call("aaa"));// [object String]
console.log(a.call(1));    // [object Number]
console.log(a.call(true)); // [object Boolean]
console.log(a.call(null)); // [object Null]
console.log(a.call(undefined));// [object Undefined]
console.log(a.call([]));   // [object Array]
console.log(a.call(function() {}));// [object Function]
console.log(a.call({}));   // [object Object]
 

new 的工作原理 通过new创建对象经历4个步骤

  1. 创建一个新对象;[var o = {};] //创建一个空对象obj,然后把这个空对象的__proto__设置为Person.prototype(即构造函数的prototype);
  2. 将构造函数的作用域赋给新对象 (因此this指向了这个新对象);[Person.apply(o)] [Person原来的this指向的是window]
  3. 执行构造函数中的代码(为这个新对象添加属性);
  4. 返回新对象
    1. 返回新对象
    2. 将构造函数的 this 指向这个新对象;
    3. 为这个对象添加属性、方法等;
    4. 最终返回新对象。

1、Class 与 Style 如何动态绑定?

对象语法:

<div v-bind:class="{ active: isActive, 'text-danger': hasError }"></div>


data: {
  isActive: true,
  hasError: false
}

数组语法:

<div v-bind:class="[isActive ? activeClass : '', errorClass]"></div>


data: {
  activeClass: 'active',
  errorClass: 'text-danger'
}

Style 也可以通过对象语法和数组语法进行动态绑定:

对象语法:

<div v-bind:style="{ color: activeColor, fontSize: fontSize + 'px' }"></div>


data: {
  activeColor: 'red',
  fontSize: 30
}

数组语法:

<div v-bind:style="[styleColor, styleSize]"></div>


data: {
  styleColor: {
     color: 'red'
   },
  styleSize:{
     fontSize:'23px'
  }  
}

 

2、computed 和 watch 的区别和运用的场景?

computed: 是计算属性,依赖其它属性值,并且 computed 的值有缓存,只有它依赖的属性值发生改变,下一次获取 computed 的值时才会重新计算 computed 的值;

watch: 更多的是「观察」的作用,类似于某些数据的监听回调 ,每当监听的数据变化时都会执行回调进行后续操作;

3、Vue 的父组件和子组件生命周期钩子函数执行顺序?

Vue 的父组件和子组件生命周期钩子函数执行顺序可以归类为以下 4 部分:

加载渲染过程 父 beforeCreate -> 父 created -> 父 beforeMount -> 子 beforeCreate -> 子 created -> 子 beforeMount -> 子 mounted -> 父 mounted

子组件更新过程 父 beforeUpdate -> 子 beforeUpdate -> 子 updated -> 父 updated

父组件更新过程 父 beforeUpdate -> 父 updated

销毁过程 父 beforeDestroy -> 子 beforeDestroy -> 子 destroyed -> 父 destroyed

4、 keep-alive

keep-alive 是 Vue 内置的一个组件,可以使被包含的组件保留状态,避免重新渲染 ,其有以下特性: 一般结合路由和动态组件一起使用,用于缓存组件; 提供 include 和 exclude 属性,两者都支持字符串或正则表达式, include 表示只有名称匹配的组件会被缓存,exclude 表示任何名称匹配的组件都不会被缓存 ,其中 exclude 的优先级比 include 高; 对应两个钩子函数 activated 和 deactivated ,当组件被激活时,触发钩子函数 activated,当组件被移除时,触发钩子函数 deactivated。

 

5、组件中 data 为什么是一个函数?

因为组件是用来复用的,且 JS 里对象是引用关系,如果组件中 data 是一个对象,那么这样作用域没有隔离,子组件中的 data 属性值会相互影响, 如果组件中 data 选项是一个函数,那么每个实例可以维护一份被返回对象的独立的拷贝,组件实例之间的 data 属性值不会互相影响;而 new Vue 的实例,是不会被复用的,因此不存在引用对象的问题。

 

6、vue传值方法

1、props $emit

2、this.$ref.parent / children

3、bus 总线

  • 挂载全局 Vue.prototype.$bus = this
  • 数据发送方 this.$bus. emit (‘hello’, this.data)
  • 数据接收 mounted 中 this.$bus. on ('hello', 当前函数)

在接收方的beforeDestroy中销毁 this.$bus. off ('hello')

4、vueX

5、local