荐 前端面试题
程序员文章站
2022-06-25 09:09:38
来源:尚硅谷公开视频目录面试题1、作用域2、值类型和引用类型的传递3、封装函数进行字符串驼峰命名的转换4、冒泡排序5、反转数组6、数组元素去重7、1物理像素8、元素水平垂直居中9、CSS实现三角形10、移动端rem适配11、背景图片距离12、JS综合面试题13、节流和防抖14、跨域15、node.js事件轮询机制16、从url输入网址17、闭包18、变量提升 和 执行上下文19、宏任务 & 微任务20、React vs Vue21、Redux管理状态的机制22、Vue组件间通信方式23、Vuex管...
来源:尚硅谷公开视频
目录
面试题
1、作用域
var num1 = 55;
var num2 = 66; // 100 在函数内部被改变成100
function f1(num, num1) {
// 2个形参相当于
// var num = 55;
// var num1 = 66;
num = 100; // 100 将形参num传入的值改为100
num1 = 100; // 100 将形参num1传入的值改为100
num2 = 100; // 100 修改了全局中的num2
console.log(num); // 100
console.log(num1); // 100
console.log(num2); // 100
}
// 55 66
f1(num1, num2);
console.log(num1); // 55
console.log(num2); // 100
console.log(num); // 报错 函数由作用域,外部不能访问函数内部,而全局又没有 num 变量
2、值类型和引用类型的传递
function Person(name, age, salary) {
this.name = name;
this.age = age;
this.salary = salary;
}
function f1(person) {
// 形参 person 相当于
// var person = p;
person.name = "ls"; // 修改的是传入的 p实例
person = new Person("aa", 18, 10); // 在堆内存中创建一个新的Person对象,和传入的p实例没有关系
}
var p = new Person("zs", 18, 1000); // 创建p实例
console.log(p.name); // zs 此时的name属性并没有被修改,仍然是 zs
f1(p); // 将p实例传入,并执行相应的修改
console.log(p.name); // ls 这里打印的是 p实例的 name属性,且p实例被作为参数传入f1并将p实例的name属性改为 "ls",因此打印的是 ls。而f1中的 person = new Person("aa", 18, 10); 是创建一个新的实例,与已经存在的 p实例 没有关系,两者互不影响。
3、封装函数进行字符串驼峰命名的转换
// 已知有字符串foo='get-element-by-id',写一个function将其转化成驼峰表示法”getElementById”
// 自定义函数
function toString(foo) {
// 根据 "-" 字符进行切割
var arr = foo.split('-');
// 获取每个元素中的第一个字符并转换成大写 字符串本身也是个数组
for(var i=1; i<arr.length; i++) {
arr[i] = arr[i].charAt(0).toUpperCase() + arr[i].substr(1, arr[i].length-1)
}
// 根据某个字符将数组转成字符串
return arr.join('');
}
console.log(toString('get-element-by-id')); // getElementById
4、冒泡排序
var arr = [32,4,67,82,21,11];
/// 轮数
for(var i=0; i<arr.length-1; i++){
// 次数
for(var j=0; j<arr.length-1-i; j++){
// 前一个大于后一个数时进行交换
if(arr[j]>arr[j+1]) {
// 交换两个变量的值
var temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
}
}
}
console.log(arr); // [4, 11, 21, 32, 67, 82]
5、反转数组
var arr = [1,2,3,4,5,6,7,8];
for(var i = 0;i<arr.length/2;i++){
// arr[0] arr[arr.length-1-0];
// arr[1] arr[arr.length-1-1];
// arr[2] arr[arr.length-1-2];
// arr[3] arr[arr.length-1-3];
// 交换两个变量的值
var temp = arr[i];
arr[i] = arr[arr.length-1-i];
arr[arr.length-1-i] = temp;
}
console.log(arr); // [8, 7, 6, 5, 4, 3, 2, 1]
6、数组元素去重
/*
* 1.创建一个新数组,把原数组中的第一个元素插入到新数组中
* 2.遍历原数组中的每一个元素分别和新数组中的每一个元素进行比较
*/
//原数组
var arr = [8,11,20,5,20,8,0,2,4,0,8];
// 新数组
var t = []; // 创建一个新数组
t[0] = arr[0]; // 把原数组中的第一个元素插入到新数组中
// 遍历arr数组中的每个元素
for(var i=0; i<arr.length; i++){
// 新数组t中的每个元素
for(var k=0; k<t.length; k++){
// 当原数组中的值和新数组中的值相同的时候,就没有必要再继续比较了,跳出内循环
if(t[k] == arr[i]){
break;
}
// 拿原数组中的某个元素比较到新数组中的最后一个元素还没有重复
if(k == t.length-1){
t.push(arr[i]); // 将数据插入新数组
}
}
}
7、1物理像素
像素比 = 物理像素 / CSS像素 。 不同屏幕的像素比是不同的。
方式一
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<!-- 移动端标签 -->
<meta name="viewport" content="width=device-width,initial-scale=1,user-scalable=no" />
<title></title>
<style type="text/css">
*{
margin: 0;
padding: 0;
}
#box{
width: 8rem; // 缩放比改变,不能再全部使用px,凡是以rem为单位的元素,都按照缩放比进行缩放
height: 8rem;
border: 1px solid #000000;
}
</style>
</head>
<body>
<div id="box"></div>
</body>
<script type="text/javascript">
var box = document.getElementById('box');
// 获取设备像素比
var dpr = window.devicePixelRatio;
// 缩放比例
var scale = 1/dpr;
// 获取屏幕宽度
var width = document.documentElement.clientWidth;
// 获取meta标签
var metaNode = document.querySelector('meta[name="viewport"]');
// 操作meta标签中的属性
metaNode.setAttribute('content', 'width=device-width,initial-scale='+ scale +',user-scalable=no')
// 元素比例重新乘回来
var htmlNode = document.querySelector('html');
htmlNode.style.fontSize = width/16*dpr + 'px';
</script>
</html>
方式二
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1,user-scalable=no" />
<title></title>
<style type="text/css">
*{
margin: 0;
padding: 0;
}
#box{
width: 200px;
height: 200px;
position: relative;
}
#box:after{
content: '';
position: absolute;
left: 0;
bottom: 0;
width: 100%;
height: 1px;
background: #000000;
}
// 通过媒体选择器根据不同的缩放比进行不同的缩放
@media screen and ( -webkit-min-device-pixel-ratio:2 ) {
#box:after{
transform: scaleY(0.5);
}
}
@media screen and ( -webkit-min-device-pixel-ratio:3 ) {
#box:after{
transform: scaleY(0.333333333333);
}
}
</style>
</head>
<body>
<div id="box"></div>
</body>
</html>
8、元素水平垂直居中
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style type="text/css">
* {
margin: 0;
padding: 0;
}
#wrap {
width: 500px;
height: 500px;
background: grey;
position: relative;
}
/* 方式一 */
#box{
position: absolute;
top: 0;
left: 0;
bottom: 0;
right: 0;
margin: auto;
width: 200px;
height: 200px;
background: deeppink;
}
/* 方式二 */
#box{
position: absolute;
top: 50%;
left: 50%;
margin-top: -100px;
margin-left: -100px;
width: 200px;
height: 200px;
background: deeppink;
}
/* 方式三 */
#box{
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%,-50%);
width: 200px;
height: 200px;
background: deeppink;
}
</style>
</head>
<body>
<div id="wrap">
<div id="box"></div>
</div>
</body>
</html>
采用flex布局
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style type="text/css">
* {
margin: 0;
padding: 0;
}
#wrap {
width: 500px;
height: 500px;
background: grey;
/* 新版本flex */
display: flex;
justify-content: center;
align-items: center;
/* 老版本flex */
display: -webkit-box;
-webkit-box-pack: center;
-webkit-box-align: center;
}
#box{
width: 200px;
height: 200px;
background: deeppink;
}
</style>
</head>
<body>
<div id="wrap">
<div id="box"></div>
</div>
</body>
</html>
9、CSS实现三角形
当一个矩形随着4条border不断变大,呈现如上图所示,此时,元素的宽高即为中间空白矩形的宽高,因此,当 width: 0px; height: 0px;
,就会变为下图:
出现我们需要的三角形,然后我们再将需要的4个三角形中需要的那个颜色保持不变,余下三个变为透明即可。或者将4个三角形中的需要的那几块设为某颜色,不需要的则设为透明,即可任意组合出我们需要的形状,例如:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style type="text/css">
* {
margin: 0;
padding: 0;
}
#box {
width: 0px;
height: 0px;
border: 100px solid transparent;
border-top-color: red;
border-left-color: green;
border-right-color: transparent;
border-bottom-color: transparent;
}
</style>
</head>
<body>
<div id="box"></div>
</body>
</html>
10、移动端rem适配
rem适配就是让html根元素字体大小设置成屏幕区域的宽,以适应不同屏幕宽度的设备。
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<!-- 移动端标签 -->
<meta name="viewport" content="width=device-width,initial-scale=1,user-scalable=no" />
<title></title>
<style type="text/css">
*{
margin: 0;
padding: 0;
}
#box{
width: 8rem;
height: 8rem;
background: deeppink;
}
</style>
</head>
<body>
<div id="box"></div>
</body>
<script type="text/javascript">
// 获取屏幕宽度
var width = document.documentElement.clientWidth;
// 获取html
var htmlNode = document.querySelector('html');
// 设置html字体大小
htmlNode.style.fontSize = width/16 + 'px';
</script>
</html>
11、背景图片距离
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title> 求背景图片左边到#box盒子左边框外侧的距离 </title>
<style type="text/css">
* {
margin: 0;
padding: 0;
}
#box{
width: 100px;
height: 200px;
background: pink;
padding: 100px;
border: 80px solid blue;
background-image: url("img/1.png");
background-repeat: no-repeat;
background-origin: content-box; // 相对于内容框来定位背景图像
background-position: -50px 0;
}
/* 答案:180px - 50px = 130px */
</style>
</head>
<body>
<div id="box"></div>
</body>
</html>
12、JS综合面试题
// 分析前
function Foo() { // 函数提升
getName = function () { alert (1); };
return this;
}
Foo.getName = function () { alert (2); };
Foo.prototype.getName = function () { alert (3); };
var getName = function () { alert (4); }; // 变量提升,可以看成分为2步:var getName;
function getName() { alert (5); } // 函数提升
/* ---------------------分割线--------------------------- */
// 分析后
// 注意:变量提升只是变量的提升,值为undefined,而函数提升的将赋值的结果随着定义的函数一起提升的,如果函数的定义与变量的定义冲突,则保留函数的定义
function Foo() {
getName = function () { alert (1); }; // 没有用var定义,因此沿着作用域链找到外面的getName函数并重新赋值
return this; // 这里的this是window
}
// var getName; // 变量名称与下面一行的函数名称冲突,优先保留函数
function getName() { alert (5); }
// 以上的代码为变量提升、函数提升后的结果
Foo.getName = function () { alert (2); };
Foo.prototype.getName = function () { alert (3); };
getName = function () { alert (4); }; // 函数重新赋值
/* ---------------------分割线--------------------------- */
// 请写出下列的输出结果
Foo. getName(); // 2
getName(); // 4
Foo().getName(); // 1 .的优先级是最高的,相当于(Foo()).getName() Foo()将外面的getName方法的alert (4);重新赋值为alert (1); 而Foo()返回的this是window,因此,相当于 window.getName(),而此时window的getName()已经被Foo()方法重新赋值为alert (1);
getName(); // 1 此时因为 Foo().getName();的操作 ,getName()已经被赋值成 alert (1);
new Foo.getName(); // 2 .的优先级是最高的,相当于 new (Foo.getName)() --> new (function () { alert (2); };)() 打印输出 2 ,同时生成一个实例对象,只是这个实例对象我们并没有使用
new Foo().getName(); // 3 .的优先级是最高的,但是.不能被()调用,因此会先把()前的结果求出,相当于(new Foo()).getName() --> foo.getName() 【foo为生成的实例对象】,实例对象找属性现在自身查找,如果找不到则沿着原型链__protpo__查找的,最终找到Foo.prototype.getName
new new Foo(). getName(); // 3 相当于 new ((new Foo()).getName)() --> new (foo.getName)() --> new (function () { alert (3); };)() ,结合上面2行代码的执行结果,可知最终结果为3
13、节流和防抖
// 节流:一个函数执行一次后,只有大于设定的执行周期后才会执行第二次。
function throttle(fn, delay) { // fn 要被节流的函数 delay 规定的时间
var lastTime = 0; // 记录 上一次函数触发的时间
return function () {
var nowTime = Date.now(); // 记录当前函数触发的时间
if (nowTime - lastTime > delay) {
fn.call(this); // 修正this指向问题
lastTime = nowTime; // 同步时间
}
}
}
// 防抖:一个需要频繁触发的函数,在规定时间内,只让最后一次生效,前面的不生效。
function debounce(fn, delay) {
var timer = null; // 记录上一次的延时器
return function () {
clearTimeout(timer); // 清除上一次延时器
timer = setTimeout(function() { // 重新设置新的延时器
fn.apply(this);
}, delay);
}
}
14、跨域
/*
1.同源策略
- 是浏览器安全策略
- 协议名、域名、端口必须完全一致
2.跨域
违背同源策略就会产生跨域
3.解决跨域
jsonp cors 服务器代理 ...
*/
// 创建script标签
var script = document.createElement( 'script');
// 设置回调函数
function getData(data) {
// 数据请求回来会被触发的函数
console.log(data);
}
// 设置script的src属性,设置请求地址
script.src = 'http://localhost:3000?callback=getData';
// lscript生效
document.body.appendChild(script);
15、node.js事件轮询机制
/*
node.js的事件轮询机制是借助libuv库实现的
概括事件轮询机制,分为6个阶段:
1. timers 定时器阶段
计时和执行到点的定时器回调函数
2. pending callbacks
某些系统操作(例如TCP错误类型)的回调函数
3. idle,prepare
准备工作
4. poll轮询阶段(轮询队列)
如果轮询队列不为空,依次同步取出轮询队列中第一个回调函数执行,直到轮询队列为空或者达到系统最大的限制
如果轮询队列为空
如果之前设置过setImmediate函数
直接进入下一个
如果之前没有设置过setImmediate函数
在当前poll阶段等待,直到轮询队列添加回调函数,就去第一个情况执行,如果定时器到点了,也会去下一个阶段
5. check 查阶段
执行setImmediate设置的回调函数
6. close callbacks 关闭阶段
执行close事件回调函数
process. nextTick能在任意阶段优先执行
*/
setTimeout(function() {
console.log('setTimeout()');
}, 0)
set Immediate(function () {
console.log('setImmediate()');
})
process.nextTick(function() {
console.log('process.nextTick()');
})
// 执行顺序:process.nextTick()、setTimeout()、setImmediate()
16、从url输入网址
面试题:从一个url地址到最终页面渲染完成,发生了什么?
1. DNS解析: 将域名地址解析为ip地址
- 浏览器DNS缓存
- 系统DNS缓存
- 路由器DNS缓存
- 网络运营商DNS缓存
- 递归搜索: blog. baidu. com
- .com域名下查找DNS解析
- .baidu域名下查找DNS解析
- blog域名下查找DNS解析
- 出错了
2. TCP连接: TCP三次握手
- 第一次握手:由浏览器发起,告诉服务器:我要发送请求,你那边可以接收请求吗?
- 第二次握手:由服务器发起,回应浏览器:我这边可以接收请求
- 第三次握手:由浏览器发送,告诉服务器:我马上就发,准备接受吧
3. 发送请求
- 请求报文: HTTP协议的通信内容
4. 接受响应
- 响应报文
5. 渲染页面
- 遇见HTML标记,浏览器调用HTML解析器解析成Token并构建成dom树
- 遇见style/link标记, 浏览器调用css解析器,处理css标记并构建cssom树
- 遇到script标记,调用javascript解析器,处理script代码(绑定事件,修改dom树/cssom树)
- 将dom树和csson树合并成一个渲染树
- 根据渲染树来计算布局,计算每个节点的几何信息(布局)
- 将各个节点颜色绘制到屏幕上(渲染)
注意:
这个五个步骤不一定按照顺序执行,如果dom树或cssom树被修改了,可能会执行多次布局和渲染
在实际页面中,这些步骤往往都会执行多次的。
6. 断开连接
第一次挥手:由浏览器发起,告诉服务器:我东西发送完了(请求报文),你准备关闭吧
第二次挥手:由服务器发起,告诉浏览器:我东西接受完了(请求报文),我准备关闭了,你也准备吧
第三次挥手:由服务器发起,告诉浏览器:我东西发送完了(响应报文),你准备关闭吧
第四次挥手:由浏览器发起,告诉服务器:我东西接受完了,我准备关闭了(响应报文),你也准备吧
17、闭包
/*
什么是闭包?
1. 密闭的容器,类似于set,map容器,存储数据的
2. 闭包是一个对象,存放数据的格式: key: value
形成的条件:
1. 函数嵌套(一个函数的内部存在另一个函数即可)
2. 内部函数引用外部函数的局部变量
闭包的优点:
延长外部函数局部变量的生命周期
闭包的缺点:
容易造成内存泄漏
注意点:
1. 合理的使用闭包
2. 用完闭包要及时清除(销毁)
*/
// 闭包的应用场景
function foo() {
var count = 1;
return function () {
count++;
console.log(count);
}
}
var foo2 = foo();
foo2(); // 2
foo2(); // 3
/* 面试题 */
function fun(n, o) {
// 形参相当于 var n, o;
console.log(o)
return {
fun: function(m) {
// 形参相当于 var m;
return fun(m, n) // 第2个参数n传入的是外部函数的第1个参数n
// 返回外部函数,即再次执行外部函数,此时相当于将外部函数的第1个参数的值传给外部函数的第2个参数
}
}
}
// var a = fun(0) // undefined 只有1个参数传入,因此n被赋值为0,o没有被赋值即为undefined
// // fun(0)的返回值即a是return的对象,a.fun()调用的内部函数fun
// a.fun(1) // 0
// a.fun(2) // 0
// a.fun(3) // 0
// // var a = fun(0) 将外部函数的第1个参数n赋值为0,o为undefined,然后第一次执行内部函数时,外部函数的第1个参数n变为内部函数的第一个参数m传入的值,n=0作为内部函数的第2形参传入,使得外部函数的第2个形参o也变为0,此后无论m传入何值,改变的都是外部函数的第1个参数n,o始终没有改动,因此恒为0
var b = fun(0).fun(1).fun(2).fun(3).fun(50).fun(22) // undefined, 0, 1, 2, 3, 50
// fun(0) 与 fun(0).fun(1) 两者返回的对象是不同的,因此两者所对应的闭包也是不同的
var c = fun(0).fun(1) // undefined, 0
c.fun(2) // 1
c.fun(3) // 1
18、变量提升 和 执行上下文
// 变量提升
/*
js引擎在代码正式执行之前会做一个预处理的工作:
1.收集变量
2.收集函数
变量提升只是变量的提前定义,值为undefined,并没有进行赋值,而函数提升的将赋值的结果随着定义的函数一起提升的,如果函数的定义与变量的定义冲突,则保留函数的定义
*/
console.log(username); // undefined
var username = 'kobe'; // 变量进行赋值
console.1og(username); // kobe
fun(); // fun 函数正常执行
function fun() {
console.1og('fun');
}
// 执行上下文 执行上下文对象(this)
/*
执行上下文(execute context) EC
理解:代码执 行的环境
时机:代码正式执行之前会进入到执行环境
工作:
1.创建变量对象(变量提升)
1) 变量
2) 函数及函数的参数
3) 全局:window
4) 局部:抽象的但是确实存在
2.确认this(执行上下文对象)的指向
1) 全局:this --> window
2) 局部:this --> 调用的对象
3.创建作用域链
父级作用域 +(关联) 当前的变量对象
4.扩展:所说的 执行上下文 可以理解为是一个大的对象
ECobj = {
变量对象: {变量, 函数, 函数的形参}
scopeChain: 父级作用域 + 当前的变量对象
this: {window || 调用的对象}
}
*/
19、宏任务 & 微任务
/*
宏任务
分类: setTimeout setInterval requrestAnimationFrame
1. 宏任务所处的队列就是宏任务队列
2. 宏任务队列可以有多个
3. 第一个宏任务队列中只有一个任务:执行主线程的js代码
4. 当宏任务队列的中的任务全部执行完以后,查看是否有微任务队列,如果有先执行微任务队列中的所有任务,如果没有就查看是否有宏任务队列
微任务
分类: new Promise().then(回调) process.nextTick
1. 微任务所处的队列就是微任务队列
2. 微任务队列只有一个
3. 在上一个宏任务队列执行完毕后如果有微任务队列就会执行微任务队列中的所有任务
*/
console.log('start');
setTimeout(() => {
console.log('setTimeout');
}, 0) // 虽然设置的时间是0秒,但定时器是回调,不会立即执行,会被放入宏任务队列
new Promise((resolve, reject) => {
for(var i=0; i<5; i++) {
console.log(i);
}
resolve(); // 修改promise实例对象的状态为成功的状态
}).then(() => {
console.log('promise实例成功回调执行');
})
console.log('end');
/* 打印顺序
start
0
1
2
3
4
end
promise实例成功回调执行
setTimeout
*/
20、React vs Vue
相同点:
1) 都有组件化开发和Virtual DOM
2) 都支持props进行父子组件间数据通信
3) 都支持数据驱动视图,不直接操作真实DOM,更新状态数据界面就自动更新
4) 都支持服务器端渲染
5) 都有支持native的方案:React的React Native、Vue的Weex
不同点:
1) 数据绑定:vue实现了数据的双向绑定,react数据流动是单向的
2) 组件写法不一样,React推荐的做法是JSX,也就是把HTML和CSS全都写进JavaScript了,即'all in js';Vue推荐的做法是webpack+vue-loader的单文件组件格式,即html、css、js写在同一个文件
3) state对象在react应用中不可变的,需要使用setState方法更新状态;在vue中,state对象不是必须的,数据由data属性在vue对象中管理
4) virtual DOM不一样,vue会跟踪每一个组件的依赖关系,不需要重新渲染整个组件树。而对于React而言,每当应用的状态被改变时,全部组件都会重新渲染,所以react中会需要shouldComponentUpdate这个生命周期函数方法来进行控制
5) React严格上只针对MVC的view层,Vue则是MVVM模式
21、Redux管理状态的机制
对Redux基本理解:
1) redux是一个独立专门用于做状态管理的JS库, 不是react插件库
2) 它可以用在react, angular, vue等项目中, 但基本与react配合使用
3) 作用: 集中式管理react应用中多个组件共享的状态和从后台获取的数据
Redux使用扩展:
1) 使用react-redux简化redux的编码
2) 使用redux-thunk实现redux的异步编程
3) 使用Redux DevTools实现chrome中redux的调试
22、Vue组件间通信方式
通信种类
1) 父组件向子组件通信
2) 子组件向父组件通信
3) 隔代组件间通信
4) 兄弟组件间通信
实现通信方式
1) props
2) vue自定义事件
3) 消息订阅与发布
4) vuex
5) slot
方式1: props
1) 通过一般属性实现父向子通信
2) 通过函数属性实现子向父通信
3) 缺点: 隔代组件和兄弟组件间通信比较麻烦
方式2: vue自定义事件
1) vue内置实现, 可以代替函数类型的props
a. 绑定监听: <MyComp @eventName="callback"
b. 触发(分发)事件: this.$emit("eventName", data)
2) 缺点: 只适合于子向父通信
方式3: 消息订阅与发布
1) 需要引入消息订阅与发布的实现库, 如: pubsub-js
a. 订阅消息: PubSub.subscribe('msg', (msg, data)=>{})
b. 发布消息: PubSub.publish(‘msg’, data)
2) 优点: 此方式可用于任意关系组件间通信
方式4: vuex
1) 是什么: vuex是vue官方提供的集中式管理vue多组件共享状态数据的vue插件
2) 优点: 对组件间关系没有限制, 且相比于pubsub库管理更集中, 更方便
方式5: slot
1) 是什么: 专门用来实现父向子传递带数据的标签
a. 子组件
b. 父组件
2) 注意: 通信的标签模板是在父组件中解析好后再传递给子组件的
23、Vuex管理状态的机制
对Vuex基本理解
1) 是什么: Vuex 是一个专为 Vue.js 应用程序开发的状态管理的vue插件
2) 作用: 集中式管理vue多个组件共享的状态和从后台获取的数据
24、Vue的MVVM实现原理
Vue作为MVVM模式的实现库的2种技术
a. 模板解析
b. 数据绑定
模板解析: 实现初始化显示
a. 解析大括号表达式
b. 解析指令
数据绑定: 实现更新显示
a. 通过数据劫持实现
本文地址:https://blog.csdn.net/earthOLtainanwan/article/details/107379357