5

1、元素上下垂直居中的方式有哪些?

元素水平垂直居中的方式有哪些?

absolute加margin方案

fixed 加 margin 方案

display:table 方案

行内元素line-height方案

flex 弹性布局方案

transform 未知元素宽高解决方案

absolute加margin方案
    div{
        position: absolute;
        width: 100px;
        height: 100px;
        left: 50%;
        top: 50%:
        margin-top: -50px;
        margin-left: -50px;
    }
fixed 加 margin 方案
    div{
        position: fixed;
        width: 100px;
        height: 100px;
        top: 0;
        right:0;
        left: 0;
        bottom: 0;
        margin: auto;
    }
display:table 方案
    div{
        display: table-cell;
        vertical-align: middle;
        text-align: center;
        width: 100px;
        height: 100px;
    }
行内元素line-height方案
    div{
        text-align: center;
        line-height: 100px;
    }
flex 弹性布局方案
    div{
        display: flex;
        align-items: center;
        justify-content:center
    }
transform 未知元素宽高解决方案
    div{
        position: absolute;
        top: 50%;
        left: 50%;
        transform: translate(-50%, -50%)
    }

2、var let const的区别及使用场景?

首先3个都是js声明变量所用

Var
var 所声明的变量,作用域为该语句所在的函数内,且存在变量提升

console.log(a) // 变量提升,var a 被提至所在作用域顶部, 所以这里输出的值为 undefined 
var a = 'JS'


for (var i = 0; i <10; i++) {  
  setTimeout(function() {  // 同步注册回调函数到 异步的 宏任务队列。
    console.log(i);        // 执行此代码时,同步代码for循环已经执行完成
  }, 0);
}

10 ... 10 // 10个10

console.log(i) // i 作用域全局 输出10
后面声明的会覆盖之前声明的变量

var a = 'JS'
var a = 'JavaScript'
Let
let 所声明的变量,作用域为该语句的代码块内,不存在变量提升

console.log(a) // 变量没有被提升, 输出 ReferenceError: a is not defined
let a = 'JavaScript'


for (let i = 0; i <10; i++) {  
  setTimeout(function() {  // 同步注册回调函数到 异步的 宏任务队列。
    console.log(i);        // 执行此代码时,同步代码for循环已经执行完成
  }, 0);
}

1...10 // 1到10

console.log(i) // i作用域for 块级内,输出 i is not defined
不允许重复声明

let a = 'JavaScript'
let a = 'JS' // 'a' has already been declared
Const
const 包含let 所有特性, 区别是const声明的变量是一个只读的不可修改的

这里注意,const保证的不是所声明的值不得改动, 而是变量指向的内存不可改动

代码示例

const a = {
    content: 'JavaScript'
}

a.content = 'JS'  // JS

a = {
    content: 'JS' // 这里改变了内存, 所以报错 Assignment to constant variable
}
三句话总结
使用var声明的变量,其作用域为该语句所在的函数内,且存在变量提升现象,后面的覆盖前面的 
使用let声明的变量,其作用域为该语句所在的代码块内,不存在变量提升, 不能重复声明 
使用const声明的是常量,在后面出现的代码中不能再修改该常量的内存

3、如何理解es6中的类?

首先,JS作为一门非面向对象语言,在es6之前,并没有提供对类的支持,我们常用的做法是通过构造函数来模拟类的实现, 通过将属性及方法定义在原型上共享给其实例

简单实现:

function JS(name) {  
    this.name = name
}

JS.prototype.getName = function(){
    console.log(this.name)
}



const child = new JS('测试')

ES6 中的Class
es6中的class只是一个语法糖,class的写法只是让对象原型看起来更加清晰

简单使用:

class JS {
    constructor(name) {    
        this.name = name
    }
    getName() {
        console.log(
            this.name
        )
    }
}



const child = new JS('测试')

每个类中都有一个constructor方法,如果没有显示定义, 会默认添加一个空的constructor,等同于ES5中的构造函数, 类的所有方法都是定义在类的prototype属性上面,二者的主要区别在于Class必须使用new调用, ES5中构造函数不使用new也可以调用, class 中新增静态方法(static)关键字, 静态方法不能被继承只有通过类本身来调用

class JS {
    constructor(name) {     
        this.name = name
    }    
    static
     getName() { 
        // static 方法只有类本身能调用,实例不能继承
        console.log(this.name)
    }
}

Extends 继承
class 也可以通过extends 关键字实现继承

代码示例:

class JS {
    constructor(name) {
        this.name = name
    }
    getName() { 
        console.log(this.name)

    }
}



class Css extends Js{
  constructor() {  
    super();
  }
}



const child = new Css('测试')

child.getName() 
// '测试' 

extends 注意点
使用extends 继承时,子类构造函数中必须调用super(), 代表调用父类的构造函数

super虽然代码父类的constructor,但是返回的子类的实例

super作为函数调用时,代表类的构造函数

super作为对象调用时, 在普通方法中,指向父类的原型对象, 静态方法中指向父类

4、如何理解es6中的Promise?

js是单线程的,也就是说一次只能完成一个任务,为了解决这个问题,js将任务的执行模式分为两种, 同步和异步, 在es5中我们处理异步只能通过的回调的方式进行处理,在多层异步中,回调会一层一层嵌套,也就是所谓的回调地狱,promise就是异步编程的一种解决方案

Promise
特点:

对象的状态不受外界影响, promise对象代表一个异步操作,有三种状态pendding(进行中), fulfilled(成功), rejected(失败)

一旦状态改变,就不会再变, 状态的改变只有两种可能, pendding => fulfilled及pendding => rejected

基本用法:

const promise = new Promise(
    function(resolve,reject){
        // ... some code
        if(/* 异步操作成功 */){
            resolve(value);
            // 将状态从pendding变成fulfilled
        }else{
            reject(error);
            // 将状态从pendding变成rejected
        }
    }
);

promise 生成实例后可以使用then方法接收resolved状态和rejected状态的回调函数

    promise.then(()=>{
        console.log('resolved')

    },()=>{
        console.log('rejected')

    })

promise原型上具有catch方法, catch方法是rejection的别名, 用于指定发生错误时的回调函数

    promise.then(()=>{
        console.log('resolved')

    },()=>{
        console.log('rejected')

    }).catch((err)=>{
        console.log('catch')
})

promise原型上具有finally方法,用于不管promise对象最后的状态如何,都会执行的操作

    promise.then(()=>{
        console.log('resolved')

    },()=>{
        console.log('rejected')
    }).finally((err)=>{
        console.log('end')
})

Promise.all
Promise.all方法用于将多个 Promise 实例,包装成一个新的 Promise 实例

简单使用:

const p = Promise.all([p1,p2,p3]);

特点:

参数都是promise实例,如果不是会调用promise.resolve方法将其转为promise实例

p的奖态由传入的promise实例的状态决定

promise实例状态都变成fulfilled,p状态为fulfilled

promise实例状态一个变成rejected,p状态为rejected

6、如何理解es6中的Proxy?

如何理解es6中的Proxy?

试题解析:对proxy的理解,可能会延伸到vue的双向绑定

Proxy(代理) 定义
可以理解为为目标对象架设一层拦截,外界对该对象的访问,都必须通过这层拦截

简单示例:

 
const obj = new Proxy({}, {
    get: (target, key, receiver) => {
        return 'JS'
        console.log(`get ${key}`)
    },
    set: (target, key, value, receiver) => {
        console.log(`set ${key}`)

     },
 })



 obj.name = 'JS'
 
// set name
// JS 



 obj.name 

 
// 这里进入get的回调函数,所有直接返回 JS 

从上面的示例中可以看出,Proxy存在一种机制,可以对外界的读写操作进行改写

Proxy 实例方法
proxy除了代理get,set操作,还能代理其它的操作,如下

handler.getPrototypeOf()



// 在读取代理对象的原型时触发该操作,比如在执行 Object.getPrototypeOf(proxy) 时。



handler.setPrototypeOf()



// 在设置代理对象的原型时触发该操作,比如在执行 Object.setPrototypeOf(proxy, null) 时。



handler.isExtensible()



// 在判断一个代理对象是否是可扩展时触发该操作,比如在执行 Object.isExtensible(proxy) 时。



handler.preventExtensions()



// 在让一个代理对象不可扩展时触发该操作,比如在执行 Object.preventExtensions(proxy) 时。



handler.getOwnPropertyDescriptor()



// 在获取代理对象某个属性的属性描述时触发该操作,比如在执行 Object.getOwnPropertyDescriptor(proxy, "foo") 时。



handler.defineProperty()



// 在定义代理对象某个属性时的属性描述时触发该操作,比如在执行 Object.defineProperty(proxy, "foo", {}) 时。



handler.has()



// 在判断代理对象是否拥有某个属性时触发该操作,比如在执行 "foo" in proxy 时。



handler.
get
()



// 在读取代理对象的某个属性时触发该操作,比如在执行 proxy.foo 时。



handler.set()



// 在给代理对象的某个属性赋值时触发该操作,比如在执行 proxy.foo = 1 时。



handler.deleteProperty()



// 在删除代理对象的某个属性时触发该操作,比如在执行 delete proxy.foo 时。



handler.ownKeys()



// 在获取代理对象的所有属性键时触发该操作,比如在执行 Object.getOwnPropertyNames(proxy) 时。



handler.apply()



// 在调用一个目标对象为函数的代理对象时触发该操作,比如在执行 proxy() 时。



handler.construct()



// 在给一个目标对象为构造函数的代理对象构造实例时触发该操作,比如在执行new proxy() 时。

为什么要使用Proxy
拦截和监视外部对对象的访问

降低函数或类的复杂度

在复杂操作前对操作进行校验或对所需资源进行管理

7、如何理解es6中的decorator?

Decorator是ES7中的提案,概念借鉴于python, 它作用于一个目标类为其添加属性于方法

我们用一个比喻来理解Decorator, 把孙悟空看成是一个类,那么棒子就是装饰器为其装备的武器

代码理解:

@stick class Monkey{
}



function stick(target){// 第一个参数就是目标类的本身
    target.ATK = 100000
}



Monkey.ATK 
// 为悟空装备了棒子,攻击力提高了100000



// 如果一个参数不够用,可以在装饰器外层再包一层

function stick(atk){
    return function(targt){
        target.ATK = atk

    }
}



@stick(200000)
 
// 这样我们就为悟空增加了200000攻击力

class Monkey{
}

Decorator 不仅能修饰类,也能修饰类的方法

class Monkey{
    @setName name(){
        this.name = '孙悟空'

    }
}

Decorator 只能修饰类及类的方法,不能修饰于函数,因为存在函数提升

Mixin
在修饰器基础上,我们可以实现mixin(混入),意思在一个对象中混入另一个对象的方法

代码示例:

export function mixins(...list){
    return function(target){
        Object.assign(target.prototype,...list)
    }

}



const skill = {
    shapeshifting(){
        console.log('72变')
    }
}



@mixins(skill)

class Monkey{
}



Object.assign(Monkey.prototype, skill)



const swk = new Monkey()

swk.shapeshifting()
 
// 72变

使用Decorator的好处
扩展功能,相对于继承增加了更多的灵活性

代码可读性更高,装饰器正确命名相当于注释

8、Es6中新增的数据类型有哪些?使用场景?

Es6中新增的数据类型有哪些?使用场景?

es6中新增一种原始数据类型Symbol,最大的特点是唯一性,Symbol值通过Symbol函数生成, 在es5中对象的属性都是字符串,我们使用他人定义的对象,然后去新增自己的属性,这样容易起冲突覆盖原有的属性, Symbol也可以看成为一个字符串,不过这个字符能保证是独一无二的

基本示例:

// Object

const obj = {
    name:'JS'
}



obj.name ='JS每日一题'

// Symbol

const name = Symbol('name')
 
// 这里的参数没有特殊意义,可以看成为Symbol加了一个标记



obj[name]='JS每日一题'

Symbol用法
Symbol 目前有多种写法

// 一

const title = Symbol()

const obj = {}

obj[title]='JS每日一题'



// 二

const obj = {
    [title]:'JS每日一题'
}



// 三

Object.defineProperty(obj,title,{value:'JS每日一题'})





obj[title]
 
// 输出的结果都为JS每日一题



这里注意一下,
Symbol
 
做为属性名时,不能用点去读取



obj.title 
// undefined

Symbol作为属性名,只有通过Object.getOwnPropertySymbols 方法返回

const attrs = Object.getOwnPropertySymbols(obj)



// [Symbol[title]]

Symbol.for()
如果我们想要重复Symbol可以使用Symbol.for, Smybol.for()及Smybol()的区别在于Symbol.for()会先去查找全局下有没有声明过,如果有就返回该值,没有就新建一个,Symbol()每一次调用都会新建一个

代码理解:

const title = Symbol.for('JS每日一题')
 



....
Symbol.for('JS每日一题')
 
//调用多次都是使用的第一次声明的值



Symbol.for('JS每日一题')
  
===
 
Symbol.for('JS每日一题')
  
// true



const title =Symbol('JS每日一题')



Symbol('JS每日一题')
 
===
 
Symbol('JS每日一题')
 
// false

总结
Symbol的特点

独一无二

不能隐式转换

不能与其它数据类型做运算

不能使用点运算符进行操作

9、简述一下你为什么要使用vue?


suipa
237 声望16 粉丝

前端程序猿