前端面试高阶

响应式布局

媒体查询

输出页面最大可见宽度

@media screen and (min-width:100px) and (max-width: 300px) {
    div {
        background-color:lightblue;
    }
}

弹性盒子

.fu{
    display: flex;
    flex-direction:row/column;主轴方向横向
    justify-content:space-around;主轴对齐方式
    align-items:center;交叉轴对齐方式
    align-content:space-around;将所有子项看作一个整体交叉轴对齐方式
}
.zi{
    flex:1;
}

九宫格布局

弹性盒子实现

<div class="box">
    <div class="r">
        <div class="c"></div>
        <div class="c"></div>
        <div class="c"></div>
    </div>
    <div class="r">
        <div class="c"></div>
        <div class="c"></div>
        <div class="c"></div>
    </div>
    <div class="r">
        <div class="c"></div>
        <div class="c"></div>
        <div class="c"></div>
    </div>
</div>
.box {
    width: 100vw;
    height: 100vh;
    display: flex;
    flex-direction: column;
}
.r {
    flex: 1;
    display: flex;
}
.c{
    flex:1;
}

网格布局实现

<div id="container">
  <div>1</div>
  <div>2</div>
  <div>3</div>
  <div>4</div>
  <div>5</div>
  <div>6</div>
  <div>7</div>
  <div>8</div>
  <div>9</div>
</div>
#container{
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
  grid-template-rows: 1fr 1fr 1fr;
}

web安全

xss攻击

往 Web 页面里插入恶意可执行网页脚本代码

解决方案:

  1. 将< >进行转义为&lt;&gt;
  2. node.js中通过escape库解决。escape(data)

sql注入

利用服务端拼接sql字符串,拼接处各种sql,在服务端执行。使服务端数据泄漏。一般出现在登录页面。

在密码框输入1'or'1'=='1'

select*from tablename where username=''or true

解决方案:sql预编译

CSRF攻击

跨站请求伪造,它利用用户已登录的身份,在用户毫不知情的情况下,以用户的名义完成非法操作。

解决方案:

  1. 使用post请求(不能完全解决)
  2. 加入验证码(确定为用户行为而不是黑客行为)
  3. 验证ReFerer(验证发起请求的网页的地址)
    • 也不能完全解决,因为网页地址也可以篡改伪装
  4. 请求时附带验证信息Anti CSRF Token

http协议

HTTP 是一种无状态 协议(本身不会对请求保存),由于HTTP是无状态协议,所以必须引入一些技术来记录管理状态,例如Cookie

http请求消息

  1. 请求行
    • 请求方法+空格+URL+空格+协议版本
  2. 请求头
    • 头部字段名+:+值
  3. 空行
  4. 请求数据

http响应消息

  1. 状态行
    • 协议版本+状态码+状态消息
  2. 消息报头
    • 头部字段名+:+头部字段值
  3. 空行
  4. 响应正文

常见状态码

1字头:信息,服务器收到请求,需要请求者继续执行操作

2字头:成功,操作被成功接收并处理

3字头:重定向,需要进一步的操作以完成请求

4字头:客户端错误,请求包含语法错误或无法完成请求

5字头:服务器错误,服务器在处理请求的过程中发生了错误

101:切换协议。

200:请求成功。一般用于GET与POST请求

203:非授权信息。请求成功。但返回的meta信息不在原始的服务器,而是一个副本

204:无内容。服务器成功处理,但未返回内容。

301:永久移动。请求的资源已被永久的移动到新URI,返回信息会包括新的URI,浏览器会自动定向到新URI。

302:临时移动。

304:未修改。所请求的资源未修改,服务器返回此状态码时,不会返回任何资源。

305:使用代理。所请求的资源必须通过代理访问

307:临时重定向。

400:客户端请求的语法错误,服务器无法理解

404:服务器无法根据客户端的请求找到资源(网页)

405:客户端请求中的方法被禁止

500:服务器内部错误,无法完成请求

502:作为网关或者代理工作的服务器尝试执行请求时,从远程服务器接收到了一个无效的响应

503:由于超载或系统维护,服务器暂时的无法处理客户端的请求。

505:服务器不支持请求的HTTP协议的版本,无法完成处理

http原理

从输入url到页面解析

排序算法

冒泡排序

function fun(arr) {
    for (let i = 0; i < arr.length; i++) {
        for (let j = 0; j < arr.length - 1 - i; j++) {
            // 把最小的放到最后面
            if (arr[j] < arr[j + 1]) {
                let temp = arr[j]
                arr[j] = arr[j + 1]
                arr[j + 1] = temp
            }
        }
    }
    return arr
}

快速排序

function fun(arr) {
    if (arr.length <= 1) {
        return arr
    }
    let left = []
    let right = []
    let k = arr.splice(0, 1)[0]
    for (let i = 0; i < arr.length; i++) {
        if (arr[i] < k) {
            left.push(arr[i])
        } else {
            right.push(arr[i])
        }
    }
    return fun(left).concat([k], fun(right))
}

Vue 初始化页面闪动问题如何解决?

出现该问题是因为在 Vue 代码尚未被解析之前,尚无法控制页面中 DOM 的显示,所以会看见模板字符串等代码。
解决方案是,在 css 代码中添加 [v-cloak] { display: none; } 规则,同时在待编译的标签上添加 v-cloak属性:

<div v-cloak>
 {{ message }}
</div>

双向数据绑定源码

/*
1.定义Vue的类
2.实现数据劫持
3.属性代理:将this.$data上面的所有的属性,代理到Vue实例上,方便取值,设置
4.模板编译:先把节点导入文档碎片中,文档碎片替换,将文档碎片放回去 【还没有处理替换操作】
5.文本替换:
    {{}}的内容已经放上去了,但是,当vm上的数据变了,页面不会再次渲染。
6.发布订阅模式:data---》view 单向数据已经实现
    1.Dep:收集订阅者
    2.Watcher:订阅者
    3.有个节点满足条件,就立刻实例化Watcher
    4. Watcher构造函数中,取值,调用了getter,准备将watcher添加到subs中 
    5.实例化dep
    6.getter添加订阅者
    7.修改了值,会调用setter,发布订阅
    8.在watcher的update中,取出新值,传给回调函数,进行更新
7.实现input的单向数据绑定
8.实现双向数据绑定
*/

// 1.定义Vue的类
class Vue {
  constructor(options) {
    //options={el:"#app",data:{ name:"妲己", age:20, info:{  a:"aa",  b:"bb" }}}
    this.$data = options.data;

    // 2.调用数据劫持的函数
    Observe(this.$data);

    // 3.属性代理
    Object.keys(this.$data).forEach((key) => {
      Object.defineProperty(this, key, {
        enumerable: true,
        configurable: true,
        get() {
          //this.name  返回:this.$data["name"]
          return this.$data[key];
        },
        set(newValue) {
          //this.name=123 this.$data.name=123
          this.$data[key] = newValue;
        },
      });
    });

    // 4.调用模板编译的函数
    Compile(options.el, this);
  }
}

// 2.实现数据劫持
function Observe(obj) {
  // obj={ name:"妲己", age:20, info:{  a:"aa",  b:"bb" }}

  //2.4终止递归
  if (!obj || typeof obj !== "object") {
    return;
  }

  //   6.5实例化dep
  let dep = new Dep();

  //2.1获取到所有的key值,循环,给所有的属性加getter和setter
  Object.keys(obj).forEach((key) => {
    let value = obj[key];

    //2.3递归
    Observe(value);

    //2.2加getter和setter
    Object.defineProperty(obj, key, {
      enumerable: true,
      configurable: true,
      get() {
        //   6.6添加订阅者
        Dep.target && dep.addSub(Dep.target);
        return value;
      },
      set(newValue) {
        value = newValue;
        //2.4后面设置的新值,也需要加setter和getter
        Observe(value);

        //6.7发布订阅
        dep.notify();
      },
    });
  });
}

// 4.实现模板编译的函数
function Compile(el, vm) {
  // 4.1 获取节点
  vm.$el = document.querySelector(el);

  // 4.2 创建文档碎片
  let fragment = document.createDocumentFragment();

  // 4.3 将节点放入文档碎片中
  while ((childNode = vm.$el.firstChild)) {
    fragment.appendChild(childNode);
  }

  // 4.4数据替换
  // 5.调用文本替换函数
  replace(fragment);

  // 4.5 将文档碎片放回去
  vm.$el.appendChild(fragment);

  // 5.实现文本替换
  function replace(node) {
    // 5.1 插值表达式的正则 {{  name }}  \s空格 *(0个或者多个) \S非空字符 +(1个或者多个)
    let reg = /\{\{\s*(\S+)\s*\}\}/;

    //纯文本节点判断
    if (node.nodeType === 3) {
      let text = node.textContent; // ""  "name:{{name}}"  "123"

      let execResult = reg.exec(text); //如果不满足条件,返回null;满足,返回数组,而且数组的第二项是 "info.a"
      //满足插值表达式
      if (execResult) {
        let value = execResult[1].split(".").reduce((obj, k) => obj[k], vm);
        node.textContent = text.replace(reg, value);

        //6.3实例化Watcher
        new Watcher(vm, execResult[1], (newValue) => {
          node.textContent = text.replace(reg, newValue);
        });
      }

      return;
    }

    // 7.实现input的单向数据绑定
    if (node.nodeType === 1 && node.nodeName === "INPUT") {
      let attrs = Array.from(node.attributes);
      let attrObj = attrs.find((item) => item.nodeName === "v-model");
      if (attrObj) {
        let key = attrObj.value; //"name" "info.a"
        let value = key.split(".").reduce((obj, k) => obj[k], vm);
        node.value = value;

        //添加订阅者
        new Watcher(vm,key,(newValue)=>{
            node.value = newValue;
        })

        //8.实现双向数据绑定
        node.addEventListener("input",(e)=>{
            // e.target.value  123
            //key:"info.a" -["info","a"] vm  
            //obj=vm["info"] obj["a"]=123

            let arr=key.split(".");//["info","a"]
            let obj=arr.slice(0,arr.length-1).reduce((val,k)=>val[k],vm)
            obj[arr[arr.length-1]]=e.target.value;

        },false)

      }

      return;
    }

    //查看node的子节点是不是文本
    node.childNodes.forEach((item) => replace(item));
  }
}

// 6.1 收集依赖的类
class Dep {
  constructor() {
    //存放订阅者
    this.subs = [];
  }
  //添加订阅者
  addSub(watcher) {
    this.subs.push(watcher);
  }
  //发布订阅
  notify() {
    this.subs.forEach((watcher) => watcher.update());
  }
}

// 6.2订阅者类
class Watcher {
  //cb:更新的时候的回调
  //key:关联的属性  name
  //vm:所有的数据来源都是vm
  constructor(vm, key, cb) {
    this.vm = vm;
    this.key = key;
    this.cb = cb;

    //非常难理解6.4 准备将watcher添加到subs中
    Dep.target = this;
    this.key.split(".").reduce((obj, k) => obj[k], this.vm); //这句话并不是真的要取值
    Dep.target = null;
  }
  update() {
    // 在watcher的update中,取出新值,传给回调函数,进行更新
    let value = this.key.split(".").reduce((obj, k) => obj[k], this.vm);
    this.cb(value);
  }
}

EventBus原理

class EventBus {
    constructor() {
        this.subs = [];
    }
    $on(event, handle) {
        this.subs.push({
            event,
            handle
        });
        return this;
    }
    $emit(event, param) {
        this.subs.forEach(item => {
            if (item.event === event) {
                item.handle(param);
            }
        })
        return this;
    }
}
const eventBus = new EventBus();
// eventBus
//     .$on('aaa', n => {
//         console.log(n);
//     })
//     .$on('aaa', n => {
//         alert(n);
//     })
//     .$on('bbb', n => {
//         console.log(n);
//     })
//     .$on('bbb', n => {
//         alert(n);
//     });
// eventBus.$emit('aaa', 5);
// eventBus.$emit('bbb', 3);

js的继承方法

1.原型链继承

如果继承的属性是引用数据类型,一个实例化对象改变,则另一个实例化对象也会改变(缺点)

function Person(name) {
    this.name = name
}
Person.prototype.sey = function () {
    console.log("你好,我是" + this.name);
}
function Student() { }
Student.prototype = new Person("妲己")
let fun = new Student
fun.sey()
console.log(fun);

2.构造函数继承

原型链上的方法和属性不能继承

function Person(name) {
    this.name = name
}
Person.prototype.sey = function () {
    console.log("你好,我是" + this.name);
}
function Student(name) {
    Person.call(this, name)
}
let fun = new Student("妲己")
console.log(fun);

3.组合继承

function Person(name) {
    this.name = name
}
Person.prototype.sey = function () {
    console.log("你好,我是" + this.name);
}
function Student(name) {
    Person.call(this, name)
}
Student.prototype = Person.prototype

let fun = new Student("妲己")
fun.sey()
console.log(fun);

ES6定义一个类

class Student {
    constructor(name, age) {
        this.name = name;
        this.age = age
    }
    sey() {
        console.log(`你好,我叫${this.name},我${this.age}岁了`);
    }
}
let student = new Student("小明", 18)

ES6继承一个类

// 提取共同属性name,封装成父类
class Person {
    constructor(name) {
        this.name = name
    }
    // 也可以继承方法
    drink(){
        console.log("喝水");
    }
}
// 继承父类
class Student extends Person {
    constructor(name, age) {
        // 调用父类Person构造函数
        super(name)
        this.age = age
    }
    sey() {
        console.log(`你好,我叫${this.name},我${this.age}岁了`);
    }
}
let student = new Student("小明", 18)
console.log("student", student);
student.sey()
student.drink()

class Teacher extends Person {
    constructor(name, age) {
        super(name)
        this.age = age
    }
    teach() {
        console.log(`你好,我叫${this.name},我${this.age}岁了`);
    }
}
let teacher = new Teacher("王老师", 46)
console.log("teacher", teacher);
teacher.teach()
teacher.drink()

vue异步组件

const AsyncComponent = () => ({
  // 需要加载的组件 (应该是一个 `Promise` 对象)
  component: import('./MyComponent.vue'),
  // 异步组件加载时使用的组件
  loading: LoadingComponent,
  // 加载失败时使用的组件
  error: ErrorComponent,
  // 展示加载时组件的延时时间。默认值是 200 (毫秒)
  delay: 200,
  // 如果提供了超时时间且组件加载也超时了,
  // 则使用加载失败时使用的组件。默认值是:`Infinity`
  timeout: 3000
})
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值