数组去重的方法
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 键值对
- 双列集合一次存储一对数据,分别为键和值
- 键不能重复,值可以重复
- 键和值是一一对应的,每一个键都对应一个值
- 键+值整体称为键值对,也叫Entry对象
set 没有重复的集合 (类似数组没有重复子项)
1、undefined 和 null 有什么区别?
- undefined:undefined是一个特殊值,表示变量已声明但未初始化时的值。
- null:null是一个对象,一个准备用来保存对象,还没有真正保存对象的值。从逻辑角度看,null值表示一个空对象指针,即表示一个对象被定义了,但是值为“空值”。
2、JavaScript中的虚值是什么?
简单的来说虚值就是在转换为布尔值时变为 false 的值。
false、null、undefined、NaN、0 +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进程:资源加载
渲染进程的线程
- JS引擎线程:解析和执行js脚本,单线程
- GUI渲染线程:负责渲染页面,布局和重绘。当触发回流和重绘的时候触发GUI线程
- 事件触发线程
- 定时触发器线程
异步http请求线程
二:输入url发生了什么
-
- 浏览器进程检查url,组装协议,构成完整url
- 浏览器进程通过进程间通信,把url发给网络进程
- 网络进程查看该url是否有本地缓存,如果有就返回给浏览器进程
- 如果没有,网络进程向web服务器发起http请求
- 4.1 进行DNS解析,获取IP地址(首先在本地DNS缓存里查找)
- 4.2 利用ip地址和端口建立TCP连接
- 4.3 构建请求头信息并发送
- 4.4 服务器响应后,网络进程接受响应头和响应数据,并解析其内容
- 网络进程响应
- 5.1 检查这状态码,如果是301、302,则从location中读取地址,重新请求
- 5.2 200处理:检查Content-Type,如果是字节流类型,则提交给下载管理器,不再进行后续渲染;如果是html则通知浏览器进程准备进行渲染
- 准备渲染进程
- 传输数据,更新状态
- 7.1 渲染进程准备好后,浏览器进程向渲染进程发起消息,渲染进程收到消息后和网络进程建立传输数据的管道
- 7.2 渲染进程接收完数据后,向浏览器进程回复消息
- 7.3 浏览器进程收到消息后更新浏览器界面状态
一、浏览器查找输入域名的IP地址(拿到 IP)
1、查找浏览器缓存(浏览器一般会缓存DNS记录一段时间,一般为2-30分钟)。
2、查找系统缓存(即hosts文件,有没有对应的IP)
3、以上都没有的话,就会经过DNS域名服务器进行域名解析
二、建立TCP连接(三次握手)
1、你在家么有外卖
2、我在家,你来吧
3、好的,我这就去
三、发送Http请求
四、服务器处理请求
五、返回响应结果
六、关闭TCP连接
七、浏览器解析html
八、浏览器布局渲染
渲染进程渲染页面
宏任务:
setTimeout
setInterval
setImmediate
requestAnimationFrame
微任务:
- process.nextTick
- MutationObserver
- Promise.then catch finally
<https://blog.csdn.net/mrszhang111/article/details/126861669>
>
> (1)宏任务一般是:script、setTimeout、setInterval、postMessage、MessageChannel、setImmediate(Node.js 环境)
> (2)微任务:Promise.then、Object.observe、MutationObserver、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 运算符判断一个对象是否是另一个对象的实例。返回true或false
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 :属性返回对创建此对象的数组函数的引用。
- 优点:对基本类型和引入类型都可以判断。
- 缺点:无法判断 null 和 undefined ,而且 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个步骤
- 创建一个新对象;[var o = {};] //创建一个空对象obj,然后把这个空对象的__proto__设置为Person.prototype(即构造函数的prototype);
- 将构造函数的作用域赋给新对象 (因此this指向了这个新对象);[Person.apply(o)] [Person原来的this指向的是window]
- 执行构造函数中的代码(为这个新对象添加属性);
- 返回新对象
-
- 返回新对象
- 将构造函数的 this 指向这个新对象;
- 为这个对象添加属性、方法等;
- 最终返回新对象。
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