1.简述vue生命周期?
1)beforeCreate:数据劫持 data -> vue
created:vue实例创建完毕,可以通过this来直接访问data,methods中的属性
2)beforeMount:此时具有渲染函数,template 模板-->产生 渲染函数 render
mounted:已经完成了初步绑定,render完成渲染(生命周期构造函数)执行ajax
3)------------数据改变-----------------
beforeUpdate:在重新渲染之前执行
updated:完成了重新渲染
4)beforeDestroy:在销毁之前,释放资源
destroyed:销毁后
2.什么是插槽?你用过哪些插槽?
插槽,它是vue提出的一个概念,插槽用于决定将所携带的内容,插入到指定的某个位置,使得模块分块,具有模块化特质。插槽的指令为v-slot,它目前取代了slot和slot-scope,插槽内容,vue实例一套内容分发的api,将slot元素作为承载分发内容的出口。
插槽有三种,默认,具名,作用域。
3.vue中key的作用
v-bind:key="唯一值"
在列表渲染的时候,在重复的元素上务必添加一个key,表示唯一值
利于Diff算法对dom操作进行优化(效率偏低,但是准确度高)
4.使用Promise封装ajax?
function(url,{ params={}, headers={} }){
return new Promise((resolve,reject)=>{
//1.初始化xhr
let xhr = new XMLHttpRequest();
//2.设置请求行
url = url+'?'+Qs.stringify(params)
xhr.open('GET',url)
//3.设置请求头
for(let k in headers){
let v = headers[k]
xhr.setRequestHeader(k,v)
}
//4.设置请求体
xhr.send()
//5.监听响应
xhr.onreadystatechange = function(){
if(this.readyState === 4){
if(this.status === 200){
let resp = JSON.parse(this.response)
resolve(resp) // 标识承诺成功
} else {
let error = JSON.parse(this.response)
reject(error) // 标识承诺失败
}
}
}
}
5.什么是跨域?如何解决跨域问题?
A网站想要获取B网站服务器上的资源,网站通过AJAX发送请求的时候,本地服务器地址与请求地址、协议类型(http)、IP地址(域名)、端口,三者有其一不同都称之为跨域请求资源
解决跨域问题:
1.CORS:cors是一个W3C制定的跨域标准,全称是:Cross-origin resource sharing,这句话的含义就是跨域资源共享,这种方式主要应用在服务端。
他是通过设置服务端设置一个HTTP头:setHeader("Access-Control-Allow-Origin", "*")
如果Access-Control-Allow-Origin中有A,或者是通配符*,浏览器就会允许A跨域,通配符代表任何地址都能跨域。
客户端不需要作任何设置,还是按照AJAX请求一样,这样就能获取跨域资源。
- JSONP:jsonp是通过script标签的src属性,我们都知道src属性能获取同一个ip服务器上,不同文件夹的文件,它其实就是一个HTTP请求,而且它支持跨域,不需要服务端设置直接就能跨域获取资源。
6.CommonJS模块与ES模块的区别?
1)CommonJS 模块化
社区提供的
半深拷贝
console.log("index模块中:", a.num);//1
console.log("index模块中:", a.obj.num);//2
1.模块的暴露
模块内部的变量其他模块无法访问,如果想要其他模块进行访问,
需要进行接口的暴露
module.exports
module是一个对象,每个模块都拥有这个对象,
exports属性是用于将当前目录信息传递到其他模块,
其默认值是一个空对象
1.module.exports.xxx
2.module.exports={}
2.模块导入
require(模块)
1.当模块为自定义模块时,参数为文件路径
require('./a.js')
2.当模块为内置模块时,参数为模块名称
require('http')
3.当模块为第三方模块时,参数为模块名称,但是需要先进行模块的安装
>cnpm install axios --save
require('axios')
模块引入的本质就是获取被引入模块中的module.exports属性
2)ES6 模块化
官方提供的
如果想要让nodejs支持es6模块化,nodejs版本v14+,
package.json添加一个配置项type:"module"
1.模块的暴露
1.export 声明
多次使用,使用哪个遍历暴露,就要使用哪个变量获取
2.export default
仅可使用一次,可以使用任意变量名来获取
一个模块中可以既使用export又使用export default
2.模块导入
import aa from './a.js'
7.简述for-in、for-of、forEach区别?
for-in:遍历数组索引、对象的属性
for-of:遍历数组,字符串的值
forEach:遍历数组
8.谈谈你对this的理解?
谁调用指向谁
- 箭头函数:this指向包含它的外层函数的this
- 单独使用thi指代全局
浏览器中指window对象
node环境中指global对象
3)函数内使用this
函数的所属者默认绑定到this上
4)事件中的this
this指向接收事件的HTML元素
9.ES6 中的 Set如何使用,如何实现自己的 Set?
Set:不可以存放相同的值,不可以通过索引来访问(没有索引)。
Set是一种特殊的Map
使用:数组去重
let arr=[1,2,3,1,2,3];
let result=[...new Set(arr)];
//实现自己的Set
class Set {
constructor(iterable) {
this.value = [];
if (!this instanceof Set) throw new Error('Constructor Set requires "new"');
if (isDef(iterable)) {
if (typeof iterable[Symbol.iterator] !== 'function') new Error(`${iterable} is not iterable`);
// 循环可迭代对象,初始化
forOf(iterable, value => this.add(value));
}
}
get size() {
return this.value.length;
}
has(val) {
return this.value.includes(val); // [ NaN ].includes(NaN)会返回true,正好Set也只能存一个NaN
}
add(val) {
if (!this.has(val)) {
this.value.push(val);
}
return this;
}
delete(val) {
const index = this.value.indexOf(val);
if (index > -1) {
this.value.splice(index, 1);
return true;
}
return false;
}
clear() {
this.value.length = 0;
}
forEach(cb, arg) {
forOf(this.values(), val => {
cb.call(arg, val, val, this);
})
}
keys() {
return new Iterator(this.value);
}
values() {
return this.keys();
}
entries() {
return new Iterator(this.value, (value) => [value, value])
}
[Symbol.iterable]() {
return this.values();
}
}
10.ES6 中 Symbol 如何使用,用在什么地方?
Symbol无法使用new来调用,Symbol()每次执行都可以产生一个唯一的值(基本数据类型),类似于字符串的值
例:
let s1=Symbol();
let s2="name";
let obj={
[s1]:"terry", //神秘的唯一值:"terry"
[s2]:"tom", //name:"tom"
s3:"jacky" //s3:"jacky"
}
obj[s1]
obj[s2]
obj.s3
1.Symbol()函数:用来产生唯一值
2.Symbol(flag):flag字符串,表示标识。生成具有标识的Symbol值
3.消除魔术字符串
4.Object.getOwnPropertySymbols:获取某个对象中所有的symbol属性名
Reflect.ownKeys():获取所有类型的键名,包括常规键名和Symbol键名
5.Symbol重复利用
Symbol.for() 缓存
Symbol.keyFor()
6.系统内置Symbol方法
1)Symbol.hasInstance
所有的构造函数都内置这个方法,当instanceOf的时候会调用
2)Symbol.iterator
当迭代对象的时候会被调用 for-of
11.谈谈var、let、const的区别
1)var
1.重复声明
2.变量的提升
console.log(d);//undefined
var d;
3.没有局部作用域
2)let
1.不可重复声明
2.不存在变量提升
3.有局部作用域
3)const
常量,只能赋值一次的变量,其他与let保持相同特性
- const定义的基本数据类型的变量不能修改
const b = 3;
b++; //error!
- const定义的引用数据类型的变量,const仅保证指针不发生改变,
修改对象的属性不会改变对象的指针,所以是被允许的。
const obj={age:1};
obj.age=2;//2
12.如何实现数组去重?[尽可能多方案]
方案一:
let arr=[1,2,3,1,2,3];
let result=[...new Set(arr)];
方案二:
var arr = [3, 2, 6, 7, 5, 3, 2, 7, 4, 4, 8, 9];
var a = [];
for (var i = 0; i < arr.length; i++) {
if (a.indexOf(arr[i]) == -1) {
a.push(arr[i]);
}
}
console.log(a);
13.如何实现对象深拷贝?
解构赋值:
var obj={name:"terry",age:12,gender:"male"}
let {...o}=obj;
o//{name:"terry",age:12,gender:"male"}
o===obj;//false 深拷贝 不改变原值
14.简述Promise.all()、Promise.race()、Promise.allSettled()、Promise.resolve()、Promise.reject()
1.Promise.all([p1,p2,...])
该方法返回值为Promise,当p1,p2,...全部执行完毕并且状态resolved的时候,Promise的then才会被调用,该then的回调函数的参数是p1,p2,...的运行结果
2.Promise.race(iterable)
返回值为Promise,返回先改变状态的Promise结果
3.Promise.allSettled(iterable)
返回值为Promise,与all不同,当所有的承诺对象状态被确认的时候会执行Promise的then,then的参数为结果
4.Promise.resolve(val)
直接返回一个承诺对象,并且状态为成功
new Promise(resolve=>{
resolve(val);
})
5.Promise.reject(error)
直接返回一个承诺对象,并且状态为失败
new Promise((resolve,reject)=>{
reject(error);
})
15.ES6中哪些对象是可迭代的?
ES6可迭代的对象:Array,String,Set,Map
实例对象可以直接访问Symbol.iterator,构造函数实现了Symbol.iterator
16.创建一个ArrayLike类,在该类的构造函数中完成数组到类数组对象的转换,并且为其提供迭代器
class ArrayLike {
constructor(args) {
for (let i = 0; i < args.length; i++) {
let val = args[i];
this[i] = val;
}
//定义内部属性length
Object.defineProperty(this, "length", {
configurable: true,
enumerable: false,
value: args.length
})
}
//手动实现一个类数组构造函数,并且该构造函数实现了Symbol.iterator接口
//请你实现迭代函数
*[Symbol.iterator]() {
for (let k in this) {
let v = this[k];
let index = parseInt(v)//为什么value赋给index
yield { value: v, done: index < this.length ? false : true }
}
}
}
let arr = new ArrayLike(["terry", "larry", "tom", "jacky"]);
console.log(arr);//ArrayLike { '0': 'terry', '1': 'larry', '2': 'tom', '3': 'jacky' }
for (let a of arr) {
console.log(a);
}
// { value: 'terry', done: true }
// { value: 'larry', done: true }
// { value: 'tom', done: true }
// { value: 'jacky', done: true }
17.ES6中如何创建一个静态方法?静态方法中是否可以访问成员属性,为什么?
//创建一个静态方法
static sayNum() {
// 静态方法只能访问静态属性
console.log(this.num);
// console.log(this.name);
}
静态方法只能访问静态属性
因为静态方法是属于整个类的,而非静态方法只能通过对象调用,非静态变量只在属于某个对象时有值,而属于类时是空的,所以不能调用。
18.ES6中如何完成类的继承,super的作用是什么?
// 继承
class Dog extends Animal {
gender;
constructor(name, age, gender) {
super(name, age);
this.gender = gender;
}
sayGender() {
console.log("my gender is", this.gender);
}
}
super的作用:在 constructor ⽅法中调⽤ super⽅法继承父类的属性,否则新建实例时会报错。⽗类的静态⽅法,也会被⼦类继承
19.什么是异步函数?异步函数如何使用?
同步就是一件事一件事的执行。只有前一个任务执行完毕,才能执行后一个任务。
异步(async)是相对于同步(sync)而言的。
1.setTimeout就是一个异步任务,当JS引擎顺序执行到setTimeout的时候发现他是个异步任务,则会把这个任务挂起,继续执行后面的代码。直到1000ms后,回调函数cbFn才会执行,这就是异步
2.ajax就是异步的JavaScript和HTML
使用:回调函数是异步操作最基本的方法。
20.ES6中代理是什么?如何使用?请说出至少三个常见的代理方法
代理Proxy
1.对象 set/get
let obj={}; //目标对象
let proxy=new Proxy(obj,{ //代理
set(target,key,val){
target[key]=val;
},
get(target,key){
return target[key];
}
})
proxy.name='terry'; //面向代理使用
2.函数 apply
let foo=function(msg){console.log(msg);}
let proxy=new Proxy(foo,{
apply(target,that,args){ //that指代this(关键字)? args数组
target.apply(that,args)
}
})
3.构造函数 constructor
let Person=function(name){this.name=name}
let proxy=new Proxy(Person,{
constructor(target,args){
return new target(...args)
}
})
21.ES6中反射是什么?如何使用?请说出至少三个常见的反射方法
反射Reflect
1.对象 set/get
let obj={}; //目标对象
let proxy=new Proxy(obj,{ //代理
set(target,key,val){
return Reflect.set(target, key, value)
},
get(target,key){
return Reflect.get(target, key)
}
})
proxy.name='terry'; //面向代理使用
2.函数 apply
let foo=function(msg){console.log(msg);}
let proxy=new Proxy(foo,{
apply(target,that,args){ //that指代this(关键字)? args数组
Reflect.apply(target, that, args);
}
})
3.构造函数 constructor
let Person=function(name){this.name=name}
let proxy=new Proxy(Person,{
constructor(target,args){
return Reflect.constructor(target, args);
}
})
22.简述Typescript与Javascript的区别与关联?
区别:1)es6是弱类型语言(一个变量的数据类型取决于值,数据类型可以改变)
2)ts添加了强类型特性(一个变量的数据类型在声明的时候确定,变量的数据类型一旦确定无法修改)
联系:Typescript是JavaScript超集
ts = es6 + 强类型
Typescript在JavaScript基础上增加了enum 枚举类型
23.什么是抽象类?抽象类应用在什么场景中?
抽象类:
如果一个类中出现了抽象方法,那么这个类一定是抽象类;
抽象类无法实例化,存在的意义是为了让其他子类继承
(当然抽象类中可以没有抽象方法)
应用场景:
//抽象类
abstract class Parent {
abstract study(): string;
eat() {
console.log("哎真香~");
}
work() {
console.log("工作");
}
}
class Child extends Parent {
study(): string {
super.eat();
super.work();
return "好好学习,找到了工作~";
}
}
24.什么是接口?接口应用在什么场景中?如何实现接口的实现?
接口:抽象到极致的抽象类
接口中的方法全部都是抽象方法,这些方法无需再使用abstract来修饰
接口是一种特殊的类,子类不再通过extends来继承,而是通过implements来实现
//接口
class User {
id: number;
name: string;
gender: string;
constructor(id: number, name: string, gender: string) {
this.id = id;
this.name = name;
this.gender = gender;
}
}
//老板
interface IBaseService {
foo(): void;
}
//副总
interface IUserService {
login(username: string, password: number): User;
register(user: User): void;
}
//经理
class UserServiceImpl implements IBaseService, IUserService {
foo(): void {
}
login(uesrname: string, password: number): User {
return new User(1, "terry", "male")
}
register(user: User): void {
}
}
25.什么是枚举?
enum 枚举类型
enum Gender {
MALE = 1,
FEMALE
}
console.log(Gender.MALE);//1
console.log(Gender.FEMALE);//2
console.log(Gender[1]);//MALE
console.log(Gender[2]);//FEMALE
26.什么是多态?
多态字面意思多种状态,指的是不同的对象按照统一接口执行时,产生多种不同的结果即同一个实现接口,使用不同的实例而执行不同的操作。
⽗类类型的引⽤【dog:Animal】指向的是⼀个⼦类对象【new Animal】,通过该引⽤调⽤say⽅法,依旧执⾏的是⼦类的函数的特点。此外通过⽗类类型引用
class Animal {
say(): void {
console.log('动物叫声');
}
}
class Dog {
say(): void {
console.log('旺旺');
}
watch(): void {
console.log('警戒!');
}
}
let dog: Animal = new Animal();
dog.say(); // 旺旺
dog.watch(); //无法访问!