javascript运行机制:只要主线程空了,就会读取任务队列
属于单线程,但是有同步任务和异步任务
同步任务:在主线程排队执行任务,只有当一个任务执行完毕,才执行下一个任务
异步任务:不见入主线程,而进入任务队列,只有任务队列通知主线程,某个异步任务可以执行了,任务队列才进入主线程
console.log("1");
while(true){};
console.log("2")
// 结果打印 1
// 这是同步任务 , while 进入死循环 ,所以导致先忙不能执行
console.log("1");
setTimeout(function(){
console.log("2")
},0);
while(true){};
// 结果打印 1
// 这是异步任务,当执行第二个时,进入队列,但是执行第三个是死循环,所以导致setTimeout不能执行
异步执行的运行机制
1.所有同步都在主线程上执行,形成一个执行栈
2.主线程上也有一个任务队列,只要异步有了结果,就在任务队列放置一个事件
3.一旦执行栈所有同步执行完毕,系统就会读取任务队列,看看有哪些事件,哪些对应的异步任务,于是结束等待,进入执行栈,开始执行。
4.主线程不断执行这三步
有四种情况会放入异步队列
1.setTimeout 和 setInterval
2.DOM事件
3.es6 Promise
4.ajax
javascript 的运行分两个阶段
1.预解析,把所有的函数定义提前,所有的变量提前声明,变量赋值不提前
2.从上到下执行
for(var i=0;i<5;i++){
setTimeout(function(){
console.log(i) // 5 5 5 5 5
},0)
}
// 写后感:setTimeout会进入异步任务队列,所以当for循环执行完毕得到(5)才执行setTimeout结果是5个5
参考地址:https://baijiahao.baidu.com/s?id=1615713540466951098&wfr=spider&for=pc
javascript 声明提前
console.log(scope); // 得到undefined
var scope
scope = 100;
console.log(scope) // 100
// 写后感:会将var声明的变量和function声明的函数预读到当前作用域的顶部,所以var是全局可以访问,导致变量声明提前
得到undefined
function add(){
console.log(111111);
}
add();
function add(){
console.log(3333333);
}
add();
// 后一个add覆盖前一个add,所以得到永远是第一个
javascript 由什么组成:ECMAScript / DOM / BOM
javascript 引入
1.在html引入
2.通过script脚本引入
3.(script defer):延迟加载,元素解析后完成
4.(script async):异步加载,但执行时会阻塞元素渲染
javascript 原始类型:
string number boolean null undefined object
'11', 11, true , null, undefined, let obj = {}
基本类型:名和值存储在栈内存中
string ,number,boolean,null,undefined,symbol,BigInt
'11', 11, true ,null undefined,
引用类型:名存储在栈内存中,值存储在堆内存中,栈内存有个地址指向堆内存的值
Object,function
javascript undefined null的区别
一、undefined:
1.声明变量,没有赋值
var a
cosole.log(a) // undefined
2.函数参数,在调用时,没有带参
function add (id){
console.log(id)// undefined
}
add() // 调用没有带参
3.对象没有赋值的属性
let o = {}
console.log(o.p) // undefined
let a = new Object();
console.log(a.x) // undefined
4.函数没有返回值时
function too(x=11){
console.log(x)
}
let x = too();
console.log(x) // undefined
//以下是 一个有返回值的demo
function foo(x=11){
return x
}
let y = foo();
console.log(y) // 11
null:表示被定义了,但是这个值为空
javascript 隐式转换:false : 0 , true :1 , " " : 0
let t = true
if(t==1){
alert("我是true但是我转换成1") // 我是true但是我转换成1
}
let t = false
if(t==0){
alert("我是false但是我转换成0") // 我是false但是我转换成0
}
// 字符串
let b = ""
if(b==0){
alert("我是空但是我转换成0") // 我是空但是我转换成0
}
// 对象和布尔比较
let t = [];
if(t==false){
// 对象转换成空字符串 ,然后再转成数字0 ,false 转换成0再做比较
alert("我是一个对象,但是我先转换为空(' ')在转换成数字")
// 我是一个对象,但是我先转换为空(' ')在转换成数字
}
// 对象和字符串比较
let t = [1,2,3]
if(t=="1,2,3"){
alert("对象和字符串比较,先把对象转换成字符串'1,2,3' ,然后再做比较")
}
// 对象和数字比较
let t = [1];
if(t==1){
alert("我是先转成'1'再比较")
// 字符串和数字比较
}
'1' == 1 // true
// 字符串布尔
'1' == true // true
'0' == false // true
// 特殊比较
undefined == null // true
let t = 444;
let yy = {a:0,b:5};
console.log(t+yy)// 444[object Object]
// 题目:
console.log(1+'true') // 1true
console.log(1+true) // 2
console.log(1+undefined) // NaN
console.log(1+null) // 1
什么事编程面向对象:是一种设计思想,简称:OOP,把公共的事物抽象成属性和方法进行编程
原型链和作用域链有什么区别:
原型链:针对构造函数;例如:我们创建一个函数,这个函数通过__proto__ 或 prototype 绑定属性,然后通过new这个函数,那么这个被new 出来的新函数就会继承该函数的属性。
通过新函数访问,但是新函数没有这个属性,所以要通过链式向上查找,这就是原型链
作用:用来修改和查找属性
function Add () {}
Add.prototype.id = "1111"
let a = new Add()
console.log(a.id) // "1111"
作用域链:是针对变量;分有全局和局部,如果局部没有就向全局查找
let a = "你这个老头坏滴狠";
function too(){
console.log(a) // "你这个老头坏滴狠";
}
javascript 多态继承:
同一个事物:发出不同的形态
继承:同一个事物,继承相同的形态,
javascript 闭包:
1.读取其他函数内部变量的函数
2.子函数调用父函数的变量,变量不会被释放
javascript 类
function Person(name) // 共用属性
this.name = name;
// 共用实例
this.userName = function(){
console.log(this.name+'是我的爱人');
}
this.totalNum = function(){
console.log("我共用")
}
}
Person.prototype.Add = function(){
console.log(this.name+"我添加了");
}
let b = new Person("LING");
b.userName();
b.Add();
// 想要继承类通过prototype new一个新的类
function ClassNameTest(){}
// 例子
ClassNameTest.prototype = new Person();
const tt = new ClassNameTest();
tt.totalNum();
/**
* 获得的思想
* 创建一个类,首字母要大写
* 可以把共同的可复用性的放在类里面
* 独立状态的可用portotype 点来继承
* 使用类可以用new 一个变量来使用
*
* 子类继承父类可以用通过prototype来实现
* 也要new 一个新的类通过变量调用类的方法
* 缺点:无法继承多个类
*
* **/
javascript 变量提升:
var a = "1";
function foo(){
let a = "44"
console.log(a) // 44
return a
}
foo()
javascript let const var 的区别:
1.let 是一个块级作用域,在函数内定义,对外部无影响;
let a = "444";
function foo(){
let a = "我是谔谔"
console.log(a)// "我是谔谔"
}
console.log(a)// "444"
2.const 是一个常量,定义后不能修改
3.var 是一个全局,可以修改,不初始化会得到undefined
javascript proto protoType的关系:

function Person (){}
let person = new Person();
console.log(person.__proto__ == Person.prototype); // true
console.log(Person.prototype.constructor==Person); // true
javascript 手写实现一个xhr:
// 创建一个xhr对象
var xhr = new XMLHttpRequest()
xhr.open ("get","文件名地址","布尔,false表示同步请求,true表示异步请求")
xhr.onreadystatechange = function(){
// readystate
// 0 表示未初始化,xhr对象已调用,open方法没有执行
// 1表示初始化,send方法没有执行
// 2表示发送数据,http请求头未知
// 3表示数据发送中,但是http请求头不全,导致responseBody和responseText报错
// 4表示数据接收完毕,responseBody和responseText回应请求的数据
console.log(xhr.readystate)
if(xhr.readystate==4 && xhr.status==200){
// 表示数据接收完毕 ,http状态200
}
}
xhr.send()
post 请求
let xhr = new XMLHttpResquest();
xhr.open('post','aa.text?parmes=1&id=2');
xhr.onreadystatechange = function(){
if(xhr.readystate==4 && xhr.status==200){
alert("成功")
}
}
xhr.setRequsetHeader ('Content-Type','applicaiton/x-www-form-urlencoded');
xhr.send("?parmes=1&id=2");
使用promise 封装ajax
let fetch = (method,url)=>{
rerurn new Promise((reject,resolve)=>{
let xhr = new XMLHttpRequest();
xhr.open(method,url);
xhr.responseType = "json";
xhr.setRequsetHeader ("Accept","application/json");
xhr.readystatechange = function(){
if(xhr.readystate==4 && xhr.status==200){
resolve(this.response)
}else{
reject(this.response)
}
}
xhr.send();
})
}
fetch('get','https://www.baidu.com').then(({code,msg,res})=>{
console.log(code,msg,res)
}).catch(()=>{});
https:
get和post请求的区别
get和post都没有长度限制,长度限制是web浏览器的url限制
get可以是获取用户数据,所以不用每次和数据库连接,
post 是用户操作交互,删除和修改,所以每次都需要请插入和删除数据库
http请求状态码:
2.101 Switching Protocols 服务器将遵从客户的请求转换到另外一种协议
3.200 OK 一切正常,对GET和POST请求的应答文档跟在后面。
4.302 Found 类似于301,但新的URL应该被视为临时性的替代,而不是永久性的。
5.303 See Other 类似于301/302,不同之处在于,如果原来的请求是POST,Location头指定的重定向目标文档应该通过GET提取
6.304 Not Modified 客户端有缓冲的文档并发出了一个条件性的请求(一般是提供If-Modified-Since头表示客户只想比指定日期更新的文档)。服务器告诉客户,原来缓冲的文档还可以继续使用。
7.305 Use Proxy 客户请求的文档应该通过Location头所指明的代理服务器提取
8.307 Temporary Redirect 和302(Found)相同。许多浏览器会错误地响应302应答进行重定向,即使原来的请求是POST,即使它实际上只能在POST请求的应答是303时才能重定向。由于这个原因,HTTP 1.1新增了307,以便更加清除地区分几个状态代码:当出现303应答时,浏览器可以跟随重定向的GET和POST请求;如果是307应答,则浏览器只能跟随对GET请求的重定向。
9.400 Bad Request 请求出现语法错误。
10.401 Unauthorized 客户试图未经授权访问受密码保护的页面。应答中会包含一个WWW-Authenticate头,浏览器据此显示用户名字/密码对话框,然后在填写合适的Authorization头后再次发出请求。
11.403 Forbidden 资源不可用。
12.404 Not Found 无法找到指定位置的资源
13.405 Method Not Allowed 请求方法(GET、POST、HEAD、Delete、PUT、TRACE等)对指定的资源不适用。
14.500 Internal Server Error 服务器遇到了意料不到的情况,不能完成客户的请求 、
15.501 Not Implemented 服务器不支持实现请求所需要的功能。例如,客户发出了一个服务器不支持的PUT请求
16.502 Bad Gateway 服务器作为网关或者代理时,为了完成请求访问下一个服务器,但该服务器返回了非法的应答
17.503 Service Unavailable 服务器由于维护或者负载过重未能应答。例如,Servlet可能在数据库连接池已满的情况下返回503。服务器返回503时可以提供一个Retry-After头
18.504 Gateway Timeout 由作为代理或网关的服务器使用,表示不能及时地从远程服务器获得应答
19.505 HTTP Version Not Supported 服务器不支持请求中所指明的HTTP版本
javascript section cookies localStorage sessionStorage:
/*
* 保存状态:cookie 存在浏览器端,session 存在服务端,
*
* 1、使用方式:
* cookie 分两种:
* 1.如果没有设置过时间,随着浏览器的关闭而消失
* 2.如果设置过期时间,过期时间到,cookie会自动消失
* cookie 是以文本方式保存在客户端,每次请求都带上它
*
* session 有没有sessionId 有这个返回一个session对象,没有这个创建一个新的session对象
* 分三种情况:禁用cookie则重写response.encodeURL(url)
* 不支持cookie 将会重写url把sessionId拼接搭到url后面
* 支持则url不做任何处理
*
*
* 2、存储内容:
* cookie 以文本格式存储, session 类似hashtable数据格式存储,
可以存储多个对象(session)
*
* 3、存储的大小
* cookie 单个不能超过4kb, session 没有大小限制
*
*4、 安全性
* cookie 容易被拦截,欺骗, session 的sessionId是保存在cookie里的,所以安全大于cookie
*
* 应用场景:
* cookie 用户登陆过,下次可以记住用户信息,方便登陆;
保存上次的登录时间;
保存上次查看的页面;统计查看次数
*
*缺点:
* cookie 大小限制,不安全
* session 不利于用户量多使用,占服务器内存
*
*
*localStorage:存在本地,永久性存储,大小5mb,没有跟服务器接触
*
*sessionStorage:仅在当前会话,浏览器关闭就结束,大小5mb,没有跟服务器接触
*
*
* */
模块化
作用:提高了可扩展、可维护、可协作性
1.ES6 :import / 对应的是 exports
2.common.js: require / export.module exports
3.amd:rquire / defined
import 和 require 的区别
import是异步,require是同步
import指向内存地址,所以导入值会随着导出值而改变
require是值拷贝,导出值变化不会改变导入值
javascript 重绘和回流,防抖,节流
重绘:不改变布局大小,只改变样式和文本
回流:改变页面布局,重新计算文档元素
防抖:多次触发事件,事件之执行一次,并且是在事件结束后执行
应用场景:比如按钮,多次点击,将多次操作合并成一次操作
节流:在规定时间内,只执行一次,一定时间内只触发一次
应用场景:滚动条,缩放页面
// 防抖
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
#container {
width: 100%;
height: 80px;
line-height: 80px;
background-color: black;
color: #fff;
text-align: center;
}
</style>
</head>
<body>
<div id="container"></div>
<script>
const container = document.getElementById("container");
let count = 1;
function add(e){
console.log(e,"getHtml")
container.innerText = count++;
}
function getHtml(func,wait,isflag) {
let time,result;
return function () {
time && clearTimeout(time);
let context = this;
let arg = arguments;
if(isflag){
let callnow = !time;
time = setTimeout(()=>{
time = null
},wait);
if(callnow) result=func.apply(context,arg)
}else {
time = setTimeout(()=> {
func(context, arg)
}, wait)
}
return result;
}
}
container.onclick = getHtml(add,300);
</script>
</body>
</html>
// 节流
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>节流</title>
<style>
#content{
width:20px;
height: 20px;
background-color: black;
overflow: auto;
}
</style>
</head>
<body>
<div id="content">留图不留种,菊花万人捅;留种不留图,菊花万人服</div>
<script>
let content = document.getElementById('content');
let falg = true;
content.onscroll = function () {
if(!falg) return;
falg = false;
setTimeout(function () {
console.log("函数节流");
falg = true
},300)
}
</script>
</body>
</html>
javascript DOM有哪些api
nodeType:
html:<div id="container"></div>
let container = document.getEleMentById('container');
container.nodeType // 判断是什么元素
/**
1.表示标签元素
2.表示元素属性
3.表示文本
8.表示注释
9.表示文档 (document)
11.表示轻量级文档 (DocumentFragment)
nodeValue:获取内容
创建api:
createElement 创建标签元素
createTextNode 创建文本
cloneNode 复制一个节点副本
**/
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="content">
<span>我可以复制哦</span>
</div>
<button id="btn">复制</button>
<script>
let content = document.getElementById('content');
let btn = document.getElementById("btn");
btn.onclick = function () {
let content1 = content.cloneNode(true);
content1.id="content1";
document.body.appendChild(content1);
}
/**
* 获取id
* 通过点击事件触发
* id.cloneNode(true) // 复制节点副本
* 添加id
* 使用appendChild 插入到body
*
*
* **/
</script>
</body>
</html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<ul id="list"></ul>
<input type="button" value="点我" onclick="handleClick()"/>
<input type="button" value="爱我" onclick="handleBtn()"/>
<script>
let listID = document.getElementById("list");
// function handleBtn(){
// console.time("antzone");
// for (let i =0;i<10;i++){
// let lis = document.createElement('li');
// lis.textContent = i;
// listID.appendChild(lis);
//
// }
// console.timeEnd("antzone");
//
// }
let Fragment = document.createDocumentFragment();
function handleClick() {
console.time("antzone");
for(let i =0;i<10;i++){
let list = document.createElement('li');
list.textContent = i;
// 先放进片段
Fragment.appendChild(list)
}
// 后面一次性再加入片段
listID.appendChild(Fragment);
console.timeEnd("antzone"); //antzone:
}
/**
* 获取id
* 通过点击事件处理
* 使用createElement创建元素
* textContent 文本内容
* 性功能要求:
* 第一个方案:每次都会创建一个新的元素,然后添加到文档树中,造成浏览器回流
* 第二个方案:每次先添加到Fragment,然后再一次性添加到ul中
*
*
* **/
</script>
</body>
</html>
// appendChild 在后插入
// inserBefor 在前面插入
// removeChild 删除
// replaceChild 替换一个元素
查找api:
getElementById() // 查找id
getElementsClassName() // 查找class
getElementsByTagName() // 查找标签元素
querySelectorAll() // 通过class 查找所有
querySelector() // 查找一个
修改属性:
setAttribute ('name',value) // 修改属性
getAttribute('name') // 获取属性
javascript mvc mvvm mvp的区别
mvc:module-view-controller
用户操作(view)=>业务逻辑处理(controller)=>数据持久化(module)=>用户视图(view)

mvp:module-view-Presenter
用户视图(view)=>Presenter=>数据持久化(module)

mvvm:module-view-viewModule
用户视图(view)<=>viewModule<=module(数据持久化)
好处:可实现数据绑定

参考地址:https://www.cnblogs.com/guwei4037/p/5591183.html
javascript 浅拷贝和深拷贝
浅拷贝:
基本类型:名和值存储在栈内存中
引用类型:名存储在栈内存,值存在堆存中,栈内存提供一个引用地址指向堆内存,
a = b
a改变b也跟着改变,其实就是引用地址一样
let a = [1,2,3,4,5,6];
b = a;
//a [1, 2, 3, 4, 5, 6]
//b [1, 2, 3, 4, 5, 6]
a[0] = 1;
//a [1, 2, 3, 4, 5, 6]
//b [1, 2, 3, 4, 5, 6]
a[0] = "11";
// a ["11", 2, 3, 4, 5, 6]
// b ["11", 2, 3, 4, 5, 6]
深拷贝:
a = b
但是a不受b影响
let aa ={a:'1',b:'2'};
let bb = {};
let dd = Object.assign(bb,aa);
//dd {a: "1", b: "2"} bb {a: "1", b: "2"}
//aa {a: "1", b: "2"}
aa.name="333"
// aa {a: "1", b: "2", name: "333"}
// aa修改了,但是bb和dd没有修改
// bb {a: "1", b: "2"}
// dd {a: "1", b: "2"}
javascript alert的调用
alert([1,2,3,[4,5,6]]); //输出的结果是1,2,3,4,5,6
alert([1,2,3]); //输出的结果是1,2,3
javascript 跨域问题
什么是跨越:不同协议,域名,端口的访问
(不是跨域)
www.aaa.com/index.html 调用 www.aaa.com/home.php
(跨域,域名不同)
www.aaa.com/index.html 调用 www.bbb.com/index.html
(跨域,协议不同)
www.aaa.com/index.html 调用 http:// www.aaa.com/index.html
(跨域,端口不同)
调用
为什么浏览器要限制跨域:当用用户访问一个页面时,用户的信息会存储在浏览器端,如果用户访问其他网站,就会泄露该用户信息
为什么要跨域:有安全问题,也有的公司有很多不同域名,所以要访问公共资源就要用到跨域
解决跨域的方法:
1、CORS资源共享:只需要在后台中加上响应头来允许域请求!在被请求的Response header中加入以下设置,就可以实现跨域访问了!
//指定允许其他域名访问
'Access-Control-Allow-Origin:*'//或指定域
//响应类型
'Access-Control-Allow-Methods:GET,POST'
//响应头设置 'Access-Control-Allow-Headers:x-requested-with,content-type'
2、jsonp:就是用javascript脚本回调一个方法,获取到相应的数据
<script src="https://www.aaa.com/index.html?callback=jsonpFunc"></script>
<scirpt>
function jsonpFunc(jsonpData){
console.log("获取到的数据:",jsonpData)
}
</script>
3、 通过修改documment.domain
a.html
<iframe
src="https://www.baidu.com/b.html"
id="iframe"
onload="test()"
frameborder="0"
/>
document.domain = "hdq.com"// 设置主域名
function test() {
console.log(document.getElementById('iframe').contentWindow);
}
b.html
document.domain = "hdq.com"// 设置主域名
4、使用window.name来进行跨域
window对象有个name属性,该属性有个特征:即在一个窗口(window)的生命周期内,窗口 载入的所有的页面都是共享一个window.name的,每个页面对window.name都有读写的权限,window.name是持久存在一个窗口载入过的所有页面中的,并不会因新页面的载入而进行重置。
5、使用html5 window.postMessage跨域
a.html
// 打开a.html会打印{a:'333',b:'bbb',c:'444'};
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<iframe src="./b.html" frameborder="0" id="iframe" onload="test()"></iframe>
<script>
let obj = {a:'333',b:'bbb',c:'444'};
function test() {
let iframe = document.getElementById('iframe');
let win = iframe.contentWindow;
win.postMessage(obj,'*')
}
</script>
</body>
</html>
b.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<script>
window.onmessage = function (e) {
let event = e || event ;
console.log(event.data)
}
</script>
</body>
</html>
6、使用web sockets
什么是web sockets:浏览器提供的一种api,它的目标是给一个单独持久的链接上提供双工、双向通信
sockets原理:js创建sockets后,会有一个http请求发送到浏览器已发起链接,取得响应后,由http升级http协议转换成web sockets协议
let socket = new WebSockt('ws://www.aaa.com');//http->ws; https->wss
socket.send('你好我是web sockets');
socket.onmessage = function(event){
let data = event.data;
}
7、nginx反向代理解决跨域
修改nginx.conf
server
{
#监听端口
listen 80;
#服务访问域名
server_name localhost;
location /api/ {
# 反向代理的地址
proxy_pass http://localhost:8888/;
# 对发送给客户端的URL进行修改
proxy_redirect off;
# 后端的Web服务器可以通过X-Forwarded-For获取用户真实IP
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# 允许客户端请求的最大单文件字节数
client_max_body_size 10m;
# 缓冲区代理缓冲用户端请求的最大字节数
client_body_buffer_size 128k;
# 表示使nginx阻止HTTP应答代码为400或者更高的应答。
proxy_intercept_errors on;
# nginx跟后端服务器连接超时时间
proxy_connect_timeout 90;
# 后端服务器数据回传超时时间
proxy_send_timeout 90;
# 连接成功后,后端服务器响应超时时间
proxy_read_timeout 90;
# 设置代理服务器(nginx)保存用户头信息的缓冲区大小
proxy_buffer_size 4k;
# 设置用于读取应答(来自被代理服务器)的缓冲区数目和大小
# 默认情况也为分页大小,根据操作系统的不同可能是4k或者8k
proxy_buffers 4 32k;
# 高负荷下缓冲大小(proxy_buffers*2)
proxy_busy_buffers_size 64k;
# 设置在写入proxy_temp_path时数据的大小,
#预防一个工作进程在传递文件时阻塞太长
proxy_temp_file_write_size 64k;
}
}
}
//常见配置
location /api/ {
proxy_pass http://localhost:8888/;
proxy_pass_request_headers on;
proxy_set_header Connection "";
client_max_body_size 30m;
client_body_buffer_size 128k;
proxy_redirect off;
proxy_connect_timeout 300;
proxy_send_timeout 300;
proxy_read_timeout 300;
proxy_buffer_size 4k;
proxy_buffers 4 32k;
proxy_busy_buffers_size 64k;
proxy_temp_file_write_size 64k;
proxy_next_upstream http_502 http_504 error invalid_header;
}
server {
listen 80; #监听80端口,可以改成其他端口
server_name localhost; # 当前服务的域名
#charset koi8-r;
#access_log logs/host.access.log main;
location / {
proxy_pass http://localhost:81;
proxy_redirect default;
}
location /apis { #添加访问目录为/apis的代理配置
rewrite ^/apis/(.*)$ /$1 break;
proxy_pass http://localhost:82;
}
#以下配置省略
// 使用
<h2>Index</h2>
<div id="show"></div>
<script type="text/javascript">
$(function () {
$.get("/apis/api/values", {}, function (result) {
$("#show").html(result);
})
})
</script>
8、proxyTable解决跨域
proxyTable: {
'/api': {
target: 'http://localhost:8080',
changeOrigin: true,
pathRewrite: {
'^/api': ''
}
}
}
axios.get('/api/list').then((res)=>{
console.log('success')
}).catch((res)=>{
console.log('error')
})
javascript 当在浏览器输入url发生了什么
1、解析url
2、DNS解析(实际上是域名和ip对应的数据库)
3、浏览器与tcp建立三次握手
4、请求和传输数据
5、页面渲染
javascript tcp三次握手
1、客户端向服务器发送请求
2、服务器端接收到请求,返回一个指令
3、客户端接收到服务端回复指令并返回确认
浏览器渲染页面:
1、解析html,创建dom树
2、解析css,创建style Rule
3、合并dom树和style Rule,计算每个节点样式
4、绘制完成显示在屏幕上
渲染优化:
1.HTML文档结构层次尽量少,最好不深于六层;
2.脚本尽量后放,放在前即可;
3.少量首屏样式内联放在标签内;
4.样式结构层次尽量简单;
5.在脚本中尽量减少DOM操作,尽量缓存访问DOM的样式信息,避免过度触发回流;
6.减少通过JavaScript代码修改元素样式,尽量使用修改class名方式操作样式或动画;
7.动画尽量使用在绝对定位或固定定位的元素上;
8.隐藏在屏幕外,或在页面滚动时,尽量停止动画;
9.尽量缓存DOM查找,查找器尽量简洁;
10.涉及多域名的网站,可以开启域名预解析
javascript 数组和对象的方法
数组:
forEach,map,fillter,find,join,shift,unshift,push,concat,replase,sort,slice,reduer,indexOf,some,reverse(数组反转[1,2,3] =>[3,2,1])
对象:
let a = new Object();
javascript splice和concat
array.splice(start,deteleCount,item,item1)
start 相当于length,
deteleCount 删除多少位
splice 实现删除,替换,插入
let b = ['a','1','b','2','c','3','d','4']
b.splice(1,2) // ["1", "b"]
b // ["a", "2", "c", "3", "d", "4"]
b.splice(4,2) // ["d", "4"]
slice
let c = [1,2,3,4,5,6];
c.slice(4) // [5, 6]
c // 没有改变 [1,2,3,4,5,6]
concat 将参数添加到数组
react 高阶组件
属性代理:高阶组件通过被包裹的React组件来操作props
反向继承:高阶组件继承于包裹的React组件
属性代理:
import React,{Component} from "react"
const MyContainer = (wrappedComponent)=>
class extends Component {
render(){
return(
<wrappedComponent {...this.props}/>
)
}
}
class MyContent extends Component{
render(){
return(
<div>dddd</div>
)
}
}
export default MyContainer(MyContent);
// 相等于
// 使用decorator转换
@MyContainer
class myContent extends Component{
render(){}
}
export default myContent;
手册题
[1,2,3].map(parseInt) // [1,'NaN','NaN']
parseInt([1,2,3]) // 1
parseInt('1', 0); // 1 (parseInt的处理方式,这个地方item没有以"0x"或者"0X"开始,
8和10这个基数由实现环境来定,ES5规定使用10来作为基数,因此这个0相当于传递了10)
parseInt('2', 1); // NaN (因为parseInt的定义,超出了radix的界限)
parseInt('3', 2); // NaN (虽然没有超出界限,但是二进制里面没有3,因此返回NaN)
// 程序中会有几种值转换false
console.log(Boolean(undefined)) // false
console.log(Boolean("")) // false
console.log(Boolean(0)) // false
console.log(Boolean(null)) // false
console.log(Boolean(-0)) // false
console.log(Boolean(NaN)) // false
async function async1() {
console.log("a");
await async2();
console.log("b");
}
async function async2() {
console.log('c')
}
console.log("d");
setTimeout(function () {
console.log("e");
},0)
async1();
new Promise(function (resolve) {
console.log("f");
resolve();
}).then(function () {
console.log("g");
})
console.log("h");
// 输出的结果是 d=>a=>c=>f=>h=>b=>g=>e
for (var i=0;i<5;i++){
console.log(i); // 0, 1, 2, 3, 4,
setTimeout(function () {
console.log(i) // 5 5 5 5 5
},0)
}
for (let i=0;i<5;i++){
console.log(i); // 0, 1, 2, 3, 4
setTimeout(function () {
console.log(i);// 0, 1, 2, 3, 4
},0)
}
function fn(){
for(var i =0;i<5;i++){
setTimeout(()=>{
console.log(i) // 5
},2000)
}
}
fn() //
function fn(){
for(let i =0;i<5;i++){
setTimeout(()=>{
console.log(i) // 0,1,2,3,4
},2000)
}
}
fn() //