#### 各大框架里面的核心内容
**vue**
* vue-cli 3.0 (2.0向3.0的过渡)
* 配置
* 优化
* vue基础知识
* 双向数据绑定
* template模板渲染语法和原理(vue-loader 、 虚拟DOM)
* 指令和自定义指令
* methods computed watch filters
* class / style
* 条件和循环渲染
* 事件处理
* 表单处理
* 组件(属性)
* ref
* 生命周期
* 插槽
* transition
* 渲染函数和jsx
* 插件编写
* 混入
* devtools
* ……
* vue-router
* 基础知识
* 动态路由
* 编程式导航
* 命名路由和命名容器
* 导航守卫
* HASH和BROWSER路由
* 路由原理
* ……
* vuex
* state
* getter
* mutation
* action
* module
* mapXxx
* 实现原理
* ……
* 单元测试
* SSR服务器渲染 nuxt.js
* UI组件库
* ……
**react**
* create-react-app
* 配置
* 优化
* react基础
* JSX语法(虚拟DOM)
* 状态
* 属性
* ref
* 组件
* 生命周期
* PureComponent
* Hooks
* ……
* react-router-dom
* redux
* redux
* react-redux
* 中间件
* ……
* dva
* umi
* typescript
* UI组件
* SSR服务器渲染 next.js
* ……
第二天作业讲解
~~~
// TO-STRING
/* var a = {
i: 0,
toString() { //或者valueOf
return ++this.i;
}
};
if (a == 1 && a == 2 && a == 3) {
console.log('条件成立');
} */
/* var a = [1, 2, 3];
a.toString = a.shift;
if (a == 1 && a == 2 && a == 3) {
console.log('条件成立');
} */
/* 数据劫持实现 */
/* var i = 0;
Object.defineProperty(window, 'a', {
get() {
return ++i;
}
});
if (a == 1 && a == 2 && a == 3) {
console.log('条件成立');
} */
/* var a = 0;
Object.defineProperty(window, 'a', {
get() {
// Uncaught TypeError: Cannot redefine property: a
// defineProperty GETER拦截器中不能再次获取当前属性
return ++a;
}
});
console.log(a); */
~~~
==
1、对象和字符串,对象转为字符串;
2、null和undefined相等,和其他都不等;
3、NaN和任何都不相等,包含和自己不相等;
4、剩下的都转为数字;
## 1. Vue2.0/3.0双向数据绑定的实现原理
~~~
ES5:Object.defineProperty
<body>
姓名:<span id="spanName"></span>
<br>
<input type="text" id="inpName">
<!-- IMPORT JS -->
<script>
let obj = {
name: ''
};
let newObj = {
...obj
};
// let newObj = JSON.parse(JSON.stringify(obj));
Object.defineProperty(obj, 'name', {
get() {
return newObj.name;
},
set(val) {
newObj.name = val;
observe();
}
});
function observe() {
spanName.innerHTML = newObj.name;
}
inpName.oninput = function () {
obj.name = this.value;
};
</script>
</body>
~~~
~~~
/* let obj = {
name: ''
};
let newObj = JSON.parse(JSON.stringify(obj));
Object.defineProperty(obj, 'name', {
get() {
return newObj.name;
},
set(val) {
if (val === newObj.name) return;
newObj.name = val;
observer();
}
});
function observer() {
spanName.innerHTML = obj.name;
inpName.value = obj.name;
}
setTimeout(() => {
obj.name = "珠峰培训";
}, 1000);
inpName.oninput = function () {
obj.name = this.value;
}; */
/*
* 1. 对原始数据克隆
* 2. 需要分别给对象中而定每一个属性设置监听
*/
~~~
~~~
let obj = {};
obj = new Proxy(obj, {
get(target, prop) {
return target[prop];
},
set(target, prop, value) {
target[prop] = value;
observer();
}
});
function observer() {
spanName.innerHTML = obj.name;
inpName.value = obj.name;
}
setTimeout(() => {
obj.name = "珠峰培训";
}, 1000);
inpName.oninput = function () {
obj.name = this.value;
};
~~~
## 2. MVC和MVVM的区别
![](https://img.kancloud.cn/16/9e/169e58828f4d8ff30bc7ee7db264575d_321x163.png)
![](https://img.kancloud.cn/54/c7/54c76b9bcab8923ced41f2eb50bb4f8c_386x181.png)
~~~
import React from 'react';
import ReactDOM from 'react-dom';
import axios from './axios';
class A extends React.Component {
state = {
name: ''
};
render() {
let { name } = this.state;
return <>
姓名:<span>{name}</span>
<br />
<input type="text" value={name} onChange={ev => {
this.setState({
name: ev.target.value
});
}} />
</>;
}
async componentDidMount() {
setTimeout(_ => {
this.setState({
name: '珠峰培训'
});
}, 1000);
let data = await axios.get('/product/banner');
console.log(data);
}
}
ReactDOM.render(<>
<A />
</>, document.getElementById('root'));
~~~
## 3\. 跨域问题的解决方案和实现原理
**跨域问题的产生及其价值意义**
前后端分离导致出现跨域
**JSONP跨域解决方案的底层原理** 只能get请求,不安全
客户端
![](https://img.kancloud.cn/c6/b3/c6b3c31eef2333a24586a6ddae78fcb3_849x433.png)
~~~javascript
<script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script>
<script>
$.ajax({
url: 'http://127.0.0.1:8001/list',
method: 'get',
dataType: 'jsonp',
success: res => {
console.log(res);
}
});
</script>
~~~
后台
~~~javascript
let express = require('express'),
app = express();
app.listen(8001, _ => {
console.log('OK!');
});
app.get('/list', (req, res) => {
let {
callback = Function.prototype
} = req.query;
let data = {
code: 0,
message: '珠峰培训'
};
res.send(`${callback}(${JSON.stringify(data)})`);
});
~~~
**基于iframe的跨域解决方案**
* window.name
* document.domin
* location.hash
* post message
**CORS跨域资源共享**
客户端
~~~javascript
import axios from 'axios';
import qs from 'qs';
axios.defaults.baseURL = "http://127.0.0.1:3000";
axios.defaults.timeout = 10000;
axios.defaults.withCredentials = true;
/*
* 设置请求传递数据的格式(看服务器要求什么格式)
* x-www-form-urlencoded
*/
axios.defaults.headers['Content-Type'] = 'application/x-www-form-urlencoded';
axios.defaults.transformRequest = data => qs.stringify(data);
/*
* 设置请求拦截器
* TOKEN校验(JWT):接收服务器返回的token,存储到vuex/本地存储中,每一次向服务器发请求,我们应该把token带上
*/
axios.interceptors.request.use(config => {
let token = localStorage.getItem('token');
token && (config.headers.Authorization = token);
return config;
}, error => {
return Promise.reject(error);
});
/*
* 响应拦截器
*/
axios.interceptors.response.use(response => {
return response.data;
}, error => {});
export default axios;
~~~
服务器端
~~~javascript
app.use((req, res, next) => {
res.header("Access-Control-Allow-Origin", "";
res.header("Access-Control-Allow-Credentials", true);
res.header("Access-Control-Allow-Headers", "PUT,POST,GET,DELETE,OPTIONS,HEAD");
res.header("Access-Control-Allow-Methods", "Content-Type,Content-Length,Authorization, Accept,X-Requested-With");
req.method === 'OPTIONS' ? res.send('CURRENT SERVICES SUPPORT CROSS DOMAIN REQUESTS!') : next();
});
~~~
**基于http proxy实现跨域请求**
webpack 在package.js中有proxy:"http://127.0.0.1:9999"
开发的时候用这个,但是服务器还要nginx反向代理
**nginx反向代理**
4.Vue/React框架中关于组件信息通信引发的面试题
* vue
属性传递
发布订阅(EventBus):$on / $emit
Provide / inject
slot
$parent / $children
vuex
* react
属性
发布订阅
React.createContext
redux / react-redux / mobix / dva
本地存储,redux存在虚拟内存中了,redux不光能状态管理,还能存储数据。
> 服务器设置session,服务器返回给客户端的信息,在响应头中带着set-cookie = ‘connect.sid’ 客户端会把信息种植到本地的cookie中的HTTPonly,客户端再次向服务器发送请求的时候,会默认在请求头中cookie把connect.sid传递发给服务器。
![](https://img.kancloud.cn/03/4e/034e9f2a314f282a04cf8facd0bd41da_246x123.png)
![](https://img.kancloud.cn/05/4c/054ca75e91201c5425fc39d3a6105e6d_833x450.png)