面试题整理

Hello,everyone !
想以一个轻松愉悦的心情来开始我的每一篇文章。
这是每一次的整理和缩影,希望大家可以发表意见,促进成长。

以下整理是很久之前留存下来的,出处并不记得是在哪里了,尴尬!
面试题很全,请允许我的借鉴哦~ 撒由那拉~
开搞!

html

块级元素和行内元素有哪些?

块级元素:块级元素

行内元素:行内元素

html语义化

参考地址:参考地址

html渲染过程

HTML解析过程:构建DOM树、构建CSSOM树、根据DOM树和CSSOM树构建render树、有了render树就开始布局Layout、最后绘制paint。

1、 构建DOM树

将HTML构建成一个DOM树,也就是构建节点,把所有的节点都构建出来。

2、构建CSSOM

解析css去构建CSSOM树

3、构建render树

DOM已经构建好了,css也有了,浏览器就会根据这两个来构造render树,浏览器就知道了有哪些节点、各个节点的CSS定义以及他们的从属关系。

4、布局

当render树有了,通过render树,浏览器开始计算各个节点的位置和样式。

5、绘制

遍历render树,在页面上绘制每个节点。

6、重排reflow

当render树绘制完成之后,比如JavaScript改变样式或添加节点,这时候render树就需要重新计算。

7、重绘repaint

要点:

1、如果遇到link和style,那就就会去下载这些外部的css资源,但是css跟DOM的构建是并行的,就是说不会阻塞DOM树的构建。

2、如果遇到script,那么页面就会把控制权交给JavaScript,直到脚本加载完毕或者是执行完毕。

3、页面的渲染是依靠render树,也就是说如果css没有加载完成,页面也不会渲染显示。

4、JavaScript执行过程中有可能需要改变样式,所以css加载也会阻塞JavaScript的加载。

5、JavaScript执行过程中如果操作DOM,但是DOM树又是在JavaScript之后才能构建,就会报错,找不到节点。

总结:css不会阻塞dom树的解析构建,但是会阻塞render树的渲染(只要是阻塞了render构建的资源都是可以优化的方向css和js),因为js可以操作dom(不能一边在改变dom同时又在渲染dom),所以当初设计的时候就是js和render树的渲染是互斥的。

当浏览器的HTML解析器遇到一个script标记时会暂停构建DOM,然后将控制权移交至JavaScript引擎,这时引擎会开始执行JavaScript脚本,直到执行结束后,浏览器才会从之前中断的地方恢复,然后继续构建DOM。每次去执行JavaScript脚本都会严重地阻塞DOM树的构建,如果JavaScript脚本还操作了CSSOM,而正好这个CSSOM还没有下载和构建,浏览器甚至会延迟脚本执行和构建DOM,直至完成其CSSOM的下载和构建。显而易见,如果对JavaScript的执行位置运用不当,这将会严重影响渲染的速度。

html渲染参考地址

css

1、如何理解CSS的盒子模型?

在标准模式下的盒模型:盒子总宽度/高度=width/height+padding+border+margin

在怪异模式下的盒模型下,盒子的总宽度和高度是包含内边距padding和边框border宽度在内的,盒子

总宽度/高度=width/height + margin = 内容区宽度/高度 + padding + border + margin;

box-sizing有两个值一个是content-box,另一个是border-box。

当设置为box-sizing:content-box时,将采用标准模式解析计算;

当设置为box-sizing:border-box时,将采用怪异模式解析计算。

2、什么是BFC?

* 什么是 BFC

   BFC(Block Formatting Context)格式化上下文,是 Web 页面中盒模型布局的 CSS 渲染模式,指一个独立的渲染区域或者说是一个隔离的独立容器。
* 形成 BFC 的条件

   * 浮动元素,float 除 none 以外的值
   * 定位元素,position(absolute,fixed)
   * display 为以下其中之一的值 inline-block,table-cell,table-caption
   * overflow 除了 visible 以外的值(hidden,auto,scroll)
* BFC 的特性
   * 内部的 Box 会在垂直方向上一个接一个的放置。
   * 垂直方向上的距离由 margin 决定
   * bfc 的区域不会与 float 的元素区域重叠。
   * 计算 bfc 的高度时,浮动元素也参与计算
   * bfc 就是页面上的一个独立容器,容器里面的子元素不会影响外面元素。

3、如何清除浮动?

不清楚浮动会发生高度塌陷:浮动元素父元素高度自适应(父元素不写高度时,子元素写了浮动后,父元素会发生高度塌陷)
* clear清除浮动(添加空div法)在浮动元素下方添加空div,并给该元素写css样式:   {clear:both;height:0;overflow:hidden;}
* 给浮动元素父级设置高度
* 父级同时浮动(需要给父级同级元素添加浮动)
* 父级设置成inline-block,其margin: 0 auto居中方式失效
* 给父级添加overflow:hidden 清除浮动方法
* 万能清除法 after伪类 清浮动(现在主流方法,推荐使用)

.float_div:after{
	content:".";
	clear:both;
	display:block;
	height:0;
	overflow:hidden;
	visibility:hidden;
}
.float_div{
	zoom:1
} 

4、定位方式有哪些?有什么区别?

static(静态): 没有特别的设定,遵循基本的定位规定,不能通过z-index进行层次分级

relative(相对定位): 对象不可层叠、不脱离文档流,参考自身静态位置通过 top,bottom,left,right 定位,并且可以通过z-index进行层次分级。

absolute(绝对定位):选取其最近一个最有定位设置的父级对象进行绝对定位,如果对象的父级没有设置定位属性,absolute元素将以body坐标原点进行定位,可以通过z-index进行层次分级。

fixed(固定定位):这里所固定的参照对像是可视窗口而并非是body或是父级元素。可通过z-index进行层次分级。

5、用纯CSS创建一个三角形

span {
    width: 0;
    height: 0;
    border-top: 40px solid transparent;
    border-left: 40px solid transparent;
    border-right: 40px solid transparent;
    border-bottom: 40px solid #ff0000;
}
6、css3实现0.5px的细线

/* css */
.line {
    position: relative;
}
.line:after {
    content: "";
    position: absolute;
    left: 0;
    top: 0;
    width: 100%;
    height: 1px;
    background-color: #000000;
    -webkit-transform: scaleY(.5);
    transform: scaleY(.5);
}

/* html */
<div class="line"></div>

7、flex的容器属性有哪些?flex项目属性有哪些?

flex容器属性:

主轴方向:水平排列(默认) | 水平反向排列 | 垂直排列 | 垂直反向排列
flex-direction: row | row-reverse | column | column-reverse;

换行:不换行(默认) | 换行 | 反向换行(第一行在最后面)
flex-wrap: nowrap | wrap | wrap-reverse;

flex-direction属性和flex-wrap属性的简写形式,默认值为row nowrap
flex-flow: <flex-direction> || <flex-wrap>;

主轴对齐方式:起点对齐(默认) | 终点对齐 | 居中对齐 | 两端对齐 | 分散对齐
justify-content: flex-start | flex-end | center | space-between | space-around;

交叉轴对齐方式:拉伸对齐(默认) | 起点对齐 | 终点对齐 | 居中对齐 | 第一行文字的基线对齐
align-items: stretch | flex-start | flex-end | center | baseline;

多根轴线对齐方式:拉伸对齐(默认) | 起点对齐 | 终点对齐 | 居中对齐 | 两端对齐 | 分散对齐
align-content: stretch | flex-start | flex-end | center | space-between | space-around;
Flex项目属性

顺序:数值越小越靠前,默认为0
order: <number>; 

放大比例:默认为0,如果有剩余空间也不放大,值为1则放大,2是1的双倍大小,以此类推
flex-grow: <number>; 

缩小比例:默认为1,如果空间不足则会缩小,值为0不缩小
flex-shrink: <number>;

项目自身大小:默认auto,为原来的大小,可设置固定值 50px/50%
flex-basis: <length> | auto;

flex-grow, flex-shrink 和 flex-basis的简写,默认值为0 1 auto
两个快捷值:auto (1 1 auto) 和 none (0 0 auto)
flex:none | [ <'flex-grow'> <'flex-shrink'>? || <'flex-basis'> ]

项目自身对齐:继承父元素(默认) | 起点对齐 | 终点对齐 | 居中对齐 | 基线对齐 | 拉伸对齐
align-self: auto | flex-start | flex-end | center | baseline | stretch;

8、css实现三栏布局(左右固定,中间自适应)

1.flex方式

2.定位方式

3.浮动方式

9、让一个div水平垂直居中

1、div大小已知的绝对定位

2、div大小未知的绝对定位

3、flex

js

几种基本数据类型、值类型和引用数据类型

基本数据类型:Undefined、Null、Boolean、Number、String

值类型:数值、布尔值、null、undefined。

引用类型:对象、数组、函数。(object、array、function)

判断数据类型

typeof判断除了Object类型的数据

Object.prototype.toString()判断是数据还是对象 Array.isArray()

new一个对象的过程中发生了什么

1. 创建空对象;
var obj = {};
2. 设置新对象的constructor属性为构造函数的名称,设置新对象的__proto__属性指向构造函数的prototype对象;
obj.__proto__ = ClassA.prototype;
3. 使用新对象调用函数,函数中的this被指向新实例对象:
ClassA.call(obj);//{}.构造函数();          
4. 如果无返回值或者返回一个非对象值,则将新对象返回;如果返回值是一个新对象的话那么直接直接返回该对象。

实现一个new操作符

function New(func) {
    var res = {};
    if (func.prototype !== null) {
        res.__proto__ = func.prototype;
    }
    var ret = func.apply(res, Array.prototype.slice.call(arguments, 1));
    if ((typeof ret === "object" || typeof ret === "function") && ret !== null) {
        // 如果构造函数返回的是对象或是函数,且不是null,则返回该对象
        return ret;
    }
    return res;
}
var obj = New(A, 1, 2);
// equals to
var obj = new A(1, 2);

js的执行上下文是什么

每次调用一个函数时,都会创建一个新的执行上下文,在JavaScript的解释器中,执行上下文的调用都有两个阶段:

1、创建阶段【调用函数时,但是在执行里面的代码之前】:

创建作用域链

创建变量,函数和参数

确定this的值

以下是解释器如何评估代码的伪概述:

初始化作用域链

创建变量对象:

创建arguments对象,检查参数的上下文,初始化名称和值并创建引用的副本。 扫描上下文以获取函数声明:

对于找到的每个函数,在变量对象(或活动对象)中创建一个属性,该属性是确切的函数名称,该函数具有指向内存中函数的引用指针。
如果函数名已存在,则将覆盖引用指针值。
扫面上下文以获取变量声明:

对于找到的每个变量声明,在变量对象(或活动对象)中创建一个属性,该属性是变量名称,并将值初始化为undefined。
如果变量名称已存在于变量对象(或活动对象)中,则不执行任何操作并继续扫描(即跳过)。
确定上下文中的this。
2、激活/代码执行阶段

闭包

概念:

能够读取其他函数内部变量的函数。 或简单理解为定义在一个函数内部的
函数,内部函数持有外部函数内变量的引用。

用途

1、读取函数内部的变量

2、让这些变量的值始终保持在内存中。不会再f1调用后被自动清除。

3、方便调用上下文的局部变量。利于代码封装。

原因:f1是f2的父函数,f2被赋给了一个全局变量,f2始终存在内存中,
f2的存在依赖f1,因此f1也始终存在内存中,不会在调用结束后,
被垃圾回收机制回收。

缺点

1、由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,在IE中可能导致内存泄露。解决方法是,在退出函数之前,将不使用的局部变量全部删除。

2、闭包会在父函数外部,改变父函数内部变量的值。所以,如果你把父函数当作对象(object)使用,把闭包当作它的公用方法(Public Method),把内部变量当作它的私有属性(private value),这时一定要小心,不要随便改变父函数内部变量的值。

js任务队列

这里首先需要明白几个概念:同步任务、异步任务、任务队列、microtask、macrotask

同步任务指的是,在主线程上排队执行的任务,只有前一个任务执行完毕,才能执行后一个任务;

异步任务指的是,不进入主线程、而进入"任务队列"(task queue)的任务,等待同步任务执行完毕之后,轮询执行异步任务队列中的任务

macrotask队列 等同于我们常说的任务队列,macrotask是由宿主环境分发的异步任务,事件轮询的时候总是一个一个任务队列去查看执行的,"任务队列"是一个先进先出的数据结构,排在前面的事件,优先被主线程读取。

microtask 即微任务,是由js引擎分发的任务,总是添加到当前任务队列末尾执行。另外在处理microtask期间,如果有新添加的microtasks,也会被添加到队列的末尾并执行。注意与setTimeout(fn,0)的区别:setTimeOut(fn(),0)指定某个任务在主线程最早可得的空闲时间执行,也就是说,尽可能早得执行。它在"任务队列"的尾部添加一个事件,因此要等到同步任务和"任务队列"现有的事件都处理完,才会得到执行。

常见的一些宏任务和微任务:

macrotask:
setTimeout
setInterval
setImmediate
requestAnimationFrame
I/O
UI rendering

常见的一些宏任务和微任务:

microtask:
process.nextTick
Promises
Object.observe
MutationObserver
async function async1(){
    console.log('async1 start')
    await async2()
    console.log('async1 end')
}
async function async2(){
    console.log('async2')
}
console.log('script start')
setTimeout(function(){
    console.log('setTimeout') 
},0)  
async1();
new Promise(function(resolve){
    console.log('promise1')
    resolve();
}).then(function(){
    console.log('promise2')
})
console.log('script end')
>=node10版本是这个结果: script start -> async1 start -> async2 -> promise1 -> script end -> promise2 -> async1 end -> setTimeout
<node10版本是这个结果: script start -> async1 start -> async2 -> promise1 -> script end -> async1 end -> promise2 -> setTimeout

防抖和节流函数

应用场景:

防抖(debounce):就是指触发事件后在 n 秒内函数只能执行一次,如果在 n 秒内又触发了事件,则会重新计算函数执行时间。

search搜索联想,用户在不断输入值时,用防抖来节约请求资源。
window触发resize的时候,不断的调整浏览器窗口大小会不断的触发这个事件,用防抖来让其只触发一次
节流(throttle):就是指连续触发事件但是在 n 秒中只执行一次函数。节流会稀释函数的执行频率。

鼠标不断点击触发,mousedown(单位时间内只触发一次)
监听滚动事件,比如是否滑到底部自动加载更多,用throttle来判断 所谓防抖,就是指触发事件后在 n 秒内函数只能执行一次,如果在 n 秒内又触发了事件,则会重新计算函数执行时间

/**
 * @desc 函数防抖
 * @param func 函数
 * @param wait 延迟执行毫秒数
 * @param immediate true 表立即执行,false 表非立即执行
 */
function debounce(func,wait,immediate) {
    let timeout;

    return function () {
        let context = this;
        let args = arguments;

        if (timeout) clearTimeout(timeout);
        if (immediate) {
            var callNow = !timeout;
            timeout = setTimeout(() => {
                timeout = null;
            }, wait)
            if (callNow) func.apply(context, args)
        }
        else {
            timeout = setTimeout(function(){
                func.apply(context, args)
            }, wait);
        }
    }
}

/**
 * @desc 函数节流
 * @param func 函数
 * @param wait 延迟执行毫秒数
 * @param type 1 表时间戳版,2 表定时器版
 */
function throttle(func, wait ,type) {
    if(type===1){
        var previous = 0;
    }else if(type===2){
        var timeout;
    }
    return function() {
        let context = this;
        let args = arguments;
        if(type===1){
            let now = Date.now();

            if (now - previous > wait) {
                func.apply(context, args);
                previous = now;
            }
        }else if(type===2){
            if (!timeout) {
                timeout = setTimeout(() => {
                    timeout = null;
                    func.apply(context, args)
                }, wait)
            }
        }
    }
}

js原型和原型链

每个对象都会在其内部初始化一个属性,就是prototype(原型),当我们访问一个对象的属性时,如果这个对象内部不存在这个属性,那么他就会去prototype里找这个属性,这个prototype又会有自己的prototype,于是就这样一直找下去,也就是我们平时所说的原型链的概念。

关系:instance.constructor.prototype = instance.proto

特点:JavaScript对象是通过引用来传递的,我们创建的每个新对象实体中并没有一份属于自己的原型副本,当我们修改原型时,与之相关的对象也会继承这一改变。 当我们需要一个属性时,JavaScript引擎会先看当前对象中是否有这个属性,如果没有的话,就会查找它的prototype对象是否有这个属性,如此递推下去,一致检索到Object内建对象。

function Func(){}
Func.prototype.name = "汪某";
Func.prototype.getInfo = function() {
   return this.name;
}
var person = new Func();
console.log(person.getInfo());//"汪某"
console.log(Func.prototype);//Func { name = "汪某", getInfo = function() }
实现一个call或 apply
call
Function.prototype.call2 = function (context) {
    var context = context || window;
    // 当context.fn函数执行的时候,函数里面的this就会指向context
    context.fn = this;

    var args = [];
    for(var i = 1, len = arguments.length; i < len; i++) {
        args.push('arguments[' + i + ']');
    }

    var result = eval('context.fn(' + args +')');

    delete context.fn
    return result;
}
apply
Function.prototype.apply2 = function (context, arr) {
    var context = Object(context) || window;
    context.fn = this;

    var result;
    if (!arr) {
        result = context.fn();
    }
    else {
        var args = [];
        for (var i = 0, len = arr.length; i < len; i++) {
            args.push('arr[' + i + ']');
        }
        result = eval('context.fn(' + args + ')')
    }

    delete context.fn
    return result;
}
实现一个Function.bind
Function.prototype.bind2 = function (context) {
    if (typeof this !== "function") {
      throw new Error("Function.prototype.bind - what is trying to be bound is not callable");
    }
    var self = this;
    var args = Array.prototype.slice.call(arguments, 1);
    var fNOP = function () {};
    var fbound = function () {
        self.apply(this instanceof self ? this : context, args.concat(Array.prototype.slice.call(arguments)));
    }
    fNOP.prototype = this.prototype;
    fbound.prototype = new fNOP();
    return fbound;
}
实现一个继承
function Parent(name) {
    this.name = name;
}

Parent.prototype.sayName = function() {
    console.log('parent name:', this.name);
}

function Child(name, parentName) {
    Parent.call(this, parentName);
    this.name = name;
}

function create(proto) {
    function F() {}
    F.prototype = proto;
    return new F();
}
// 用空对象继承原型,节省内存
Child.prototype = create(Parent.prototype);
Child.prototype.sayName = function() {
    console.log('child name:', this.name);
}
// 将原型的构造函数指向重新知道构造函数本身
Child.prototype.constructor = Child;
var parent = new Parent('汪某');
parent.sayName();// parent name: 汪某
var child = new Child('son', '汪某');
手写一个Promise
简单版本
function myPromise(constructor) {
    let self = this;
    self.status = "pending"
        //定义状态改变前的初始状态
    self.value = undefined;
    //定义状态为resolved的时候的状态
    self.reason = undefined;
    //定义状态为rejected的时候的状态
    function resolve(value) {
        //两个==="pending",保证了状态的改变是不可逆的
        if (self.status === "pending") {
            self.value = value;
            self.status = "resolved";
        }
    }
    function reject(reason) {
        //两个==="pending",保证了状态的改变是不可逆的
        if (self.status === "pending") {
            self.reason = reason;
            self.status = "rejected";
        }
    }
    //捕获构造异常
    try {
        constructor(resolve, reject);
    } catch (e) {
        reject(e);
    }
}

//同时,需要在 myPromise的原型上定义链式调用的 then方法:
myPromise.prototype.then = function(onFullfilled, onRejected) {
    let self = this;
    switch (self.status) {
        case "resolved":
            onFullfilled(self.value);
            break;
        case "rejected":
            onRejected(self.reason);
            break;
        default:
    }
}

//测试一下:
var p = new myPromise(function(resolve, reject) {
    resolve(1)
});
p.then(function(x) {
    console.log(x)
})

高级版本

拷贝

拷贝分为深拷贝和浅拷贝

浅拷贝 es6的Object.assign和{…obj}的结构赋值都是一层的深拷贝和多层的浅拷贝

JSON.parse(JSON.stringify(obj))对于正则函数等一些对象不能进行深拷贝

手写深拷贝简单版本,会有问题(像是正则、函数和循环引用),详细可以参考jq.extend或是lodash.clone

function deepCopy(obj) {
    //判断是否是简单数据类型,
    if (typeof obj == "object") {
        //复杂数据类型
        var result = obj.constructor == Array ? [] : {};
        for (let i in obj) {
            result[i] = typeof obj[i] == "object" ? deepCopy(obj[i]) : obj[i];
        }
    } else {
        //简单数据类型 直接 == 赋值
        var result = obj;
    }
    return result;
}
for in 和 for of的区别

for in
1.一般用于遍历对象的可枚举属性。以及对象从构造函数原型中继承的属性。对于每个不同的属性,语句都会被执行。
2.不建议使用for in 遍历数组,因为输出的顺序是不固定的。
3.如果迭代的对象的变量值是null或者undefined, for in不执行循环体,建议在使用for in循环之前,先检查该对象的值是不是null或者undefined
for of
1.for…of 语句在可迭代对象(包括 Array,Map,Set,String,TypedArray,arguments 对象等等)上创建一个迭代循环,调用自定义迭代钩子,并为每个不同属性的值执行语句

遍历对象

var s = {
    a: 1,
    b: 2,
    c: 3
}
var s1 = Object.create(s);
for (var prop in s1) {
    console.log(prop); //a b c
    console.log(s1[prop]); //1 2 3
}
for (let prop of s1) {
    console.log(prop); //报错如下 Uncaught TypeError: s1 is not iterable 
}
for (let prop of Object.keys(s1)) {
    console.log(prop); // a b c
    console.log(s1[prop]); //1 2 3
}
如何阻止冒泡?

冒泡型事件:事件按照从最特定的事件目标到最不特定的事件目标(document对象)的顺序触发。

w3c的方法是e.stopPropagation(),IE则是使用e.cancelBubble = true

//阻止冒泡行为
function stopBubble(e) {
//如果提供了事件对象,则这是一个非IE浏览器
if ( e && e.stopPropagation )
//因此它支持W3C的stopPropagation()方法
e.stopPropagation();
else
//否则,我们需要使用IE的方式来取消事件冒泡
window.event.cancelBubble = true;
}

如何阻止默认事件

w3c的方法是e.preventDefault(),IE则是使用e.returnValue = false

//阻止浏览器的默认行为 
function stopDefault( e ) { 
    //阻止默认浏览器动作(W3C) 
    if ( e && e.preventDefault ) 
        e.preventDefault(); 
    //IE中阻止函数器默认动作的方式 
    else 
        window.event.returnValue = false; 
    return false; 
}

vue

Vue2.0的双向数据绑定原理是什么?

vue.js 是采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()来劫持各个属性的setter,getter,在数据变动时发布消息给订阅者,触发相应的监听回调。

//vue实现数据双向绑定的原理就是用Object.defineproperty()重新定义(set方法)对象设置属性值和(get方法)获取属性值的操纵来实现的。
//Object.property()方法的解释:Object.property(参数1,参数2,参数3) 返回值为该对象obj
//其中参数1为该对象(obj),参数2为要定义或修改的对象的属性名,参数3为属性描述符,属性描述符是一个对象,主要有两种形式:数据描述符和存取描述符。这两种对象只能选择一种使用,不能混合使用。而get和set属于存取描述符对象的属性。
//这个方法会直接在一个对象上定义一个新属性或者修改对象上的现有属性,并返回该对象。

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
</head>
<body>
    <div id="myapp">
        <input v-model="message" /><br>
        <span v-bind="message"></span>
    </div>
    <script type="text/javascript">
        var model = {
            message: ""
        };
        var models = myapp.querySelectorAll("[v-model=message]");
        for (var i = 0; i < models.length; i++) {
            models[i].onkeyup = function() {
                model[this.getAttribute("v-model")] = this.value;
            }
        }
        // 观察者模式 / 钩子函数
        // defineProperty 来定义一个对象的某个属性
        Object.defineProperty(model, "message", {
            set: function(newValue) {
                var binds = myapp.querySelectorAll("[v-bind=message]");
                for (var i = 0; i < binds.length; i++) {
                    binds[i].innerHTML = newValue;
                };
                var models = myapp.querySelectorAll("[v-model=message]");
                for (var i = 0; i < models.length; i++) {
                    models[i].value = newValue;
                };
                this.value = newValue;
            },
            get: function() {
                return this.value;
            }
        })
    </script>
</body>
</html>
Vue3.0将用原生Proxy替换Object.defineProperty

为什么要替换Object.defineProperty?

在Vue中,Object.defineProperty无法监控到数组下标的变化,导致直接通过数组的下标给数组设置值,不能实时响应
Object.defineProperty只能劫持对象的属性,因此我们需要对每个对象的每个属性进行遍历。
什么是Proxy

Proxy是 ES6 中新增的一个特性,翻译过来意思是"代理",用在这里表示由它来“代理”某些操作。 Proxy 让我们能够以简洁易懂的方式控制外部对对象的访问。其功能非常类似于设计模式中的代理模式。
Proxy 可以理解成,在目标对象之前架设一层“拦截”,外界对该对象的访问,都必须先通过这层拦截,因此提供了一种机制,可以对外界的访问进行过滤和改写。
使用 Proxy 的核心优点是可以交由它来处理一些非核心逻辑(如:读取或设置对象的某些属性前记录日志;设置对象的某些属性值前,需要验证;某些属性的访问控制等)。 从而可以让对象只需关注于核心逻辑,达到关注点分离,降低对象复杂度等目的。

请详细说下你对vue生命周期的理解?

总共分为8个阶段创建前/后,载入前/后,更新前/后,销毁前/后

beforeCreate 创建前执行(vue实例的挂载元素$el和数据对象data都为undefined,还未初始化)
created 完成创建 (完成了data数据初始化,el还未初始化)
beforeMount 载入前(vue实例的$el和data都初始化了,但还是挂载之前为虚拟的dom节点,data.message还未替换。)
mounted 载入后html已经渲染(vue实例挂载完成,data.message成功渲染。)
beforeUpdate 更新前状态(view层的数据变化前,不是data中的数据改变前)
updated 更新状态后
beforeDestroy 销毁前
destroyed 销毁后 (在执行destroy方法后,对data的改变不会再触发周期函数,说明此时vue实例已经解除了事件监听以及和dom的绑定,但是dom结构依然存在)
说一下每一个阶段可以做的事情

beforeCreate:可以在这里加一个loading事件,在加载实例时触发。
created:初始化完成时的事件写这里,如果这里结束了loading事件,异步请求也在这里调用。
mounted:挂在元素,获取到DOM节点
updated:对数据进行处理的函数写这里。
beforeDestroy:可以写一个确认停止事件的确认框。。

附上一张中文解析图

解析图

动态路由定义和获取

在 router 目录下的 index.js 文件中,对 path 属性加上 /:id。

使用 router 对象的 params.id 获取

vue-router 有哪几种导航钩子?

全局导航钩子(跳转前进行判断拦截)

router.beforeEach(to, from, next),

router.beforeResolve(to, from, next),

router.afterEach(to, from ,next)

组件内钩子

beforeRouteEnter

beforeRouteUpdate

beforeRouteLeave

单独路由独享组件

beforeEnter

组件之间的传值通信?

父组件向子组件传值:

子组件在props中创建一个属性,用来接收父组件传过来的值; 在父组件中注册子组件; 在子组件标签中添加子组件props中创建的属性; 把需要传给子组件的值赋给该属性

子组件向父组件传值:

子组件中需要以某种方式(如点击事件)的方法来触发一个自定义的事件; 将需要传的值作为$emit的第二个参数,该值将作为实参传给响应事件的方法; 在父组件中注册子组件并在子组件标签上绑定自定义事件的监听。

vuex

是一个能方便vue实例及其组件传输数据的插件 方便传输数据,作为公共存储数据的一个库

state: 状态中心

mutations: 更改状态,同步的

actions: 异步更改状态

getters: 获取状态

modules: 将state分成多个modules,便于管理

应用场景:单页应用中,组件之间的状态。音乐播放、登录状态、加入购物车。

网上找的一个通俗易懂的了解vuex的例子

公司有个仓库
1.State(公司的仓库)
2.Getter(只能取出物品,包装一下,不能改变物品任何属性)
3.Muitation(仓库管理员,只有他可以直接存储到仓库)
4.Action(公司的物料采购员,负责从外面买东西和接货, 要往仓库存东西,告诉仓库管理员要存什么)
非常要注意的地方:只要刷新或者退出浏览器,仓库清空。
Vue hash 路由和 history 路由的区别

hash模式url里面永远带着#号,我们在开发当中默认使用这个模式。那么什么时候要用history模式呢?如果用户考虑url的规范那么就需要使用history模式,因为history模式没有#号,是个正常的url适合推广宣传。当然其功能也有区别,比如我们在开发app的时候有分享页面,那么这个分享出去的页面就是用vue或是react做的,咱们把这个页面分享到第三方的app里,有的app里面url是不允许带有#号的,所以要将#号去除那么就要使用history模式,但是使用history模式还有一个问题就是,在访问二级页面的时候,做刷新操作,会出现404错误,那么就需要和后端人配合让他配置一下apache或是nginx的url重定向,重定向到你的首页路由上就ok啦。

diff算法

diff算法

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
【优质项目推荐】 1、项目代码均经过严格本地测试,运行OK,确保功能稳定后才上传平台。可放心下载并立即投入使用,若遇到任何使用问题,随时欢迎私信反馈与沟通,博主会第一时间回复。 2、项目适用于计算机相关专业(如计科、信息安全、数据科学、人工智能、通信、物联网、自动化、电子信息等)的在校学生、专业教师,或企业员工,小白入门等都适用。 3、该项目不仅具有很高的学习借鉴价值,对于初学者来说,也是入门进阶的绝佳选择;当然也可以直接用于 毕设、课设、期末大作业或项目初期立项演示等。 3、开放创新:如果您有一定基础,且热爱探索钻研,可以在此代码基础上二次开发,进行修改、扩展,创造出属于自己的独特应用。 欢迎下载使用优质资源!欢迎借鉴使用,并欢迎学习交流,共同探索编程的无穷魅力! 基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip 基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip 基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值