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='JS每日一题'
// 二
const obj = {
:'JS每日一题'
}
// 三
Object.defineProperty(obj,title,{value:'JS每日一题'})
obj
// 输出的结果都为JS每日一题
这里注意一下,
Symbol
做为属性名时,不能用点去读取
obj.title
// undefined
Symbol作为属性名,只有通过Object.getOwnPropertySymbols 方法返回
const attrs = Object.getOwnPropertySymbols(obj)
// [Symbol]
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?