js第二弹
邵预鸿 Lv5

textContent和innerText区别

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<style>
button{
border:1px solid red;
}
</style>
<div class="contain">
北京上海广州<span>深圳厦门</span>陕西西安
<p>台湾香港澳门</p>
</div>
<button onclick="myFunction()">我是按钮</button>
<script>
function myFunction(){
console.log(event.type);
}
let container = document.querySelector("body");
console.log("textContent的内容是:",container.textContent);
console.log("innerText的内容是:",container.innerText);
console.log("innerHTML的内容是:",container.innerHTML);
</script>
</body>
</html>
  • 通过textContent属性可以获取指定节点的文本,以及该指定节点所包含后代节点中文本内容,也包括<script><style>元素中的内容(这里的不是文本而是CSS样式代码和JavaScript代码)

    图片

  • 通过textContent属性可以获取指定节点的文本,以及该指定节点所包含后代节点中文本内容,也包括<script>和<style>元素中的内容(这里的不是文本而是CSS样式代码和JavaScript代码)

  • 通过textContent属性可以获取指定节点的文本,以及该指定节点所包含后代节点中文本内容,也包括<script>和<style>元素中的内容(这里的不是文本而是CSS样式代码和JavaScript代码)

$attrs与$listeners

包含了父作用域中不作为 prop 被识别 (且获取) 的 attribute 绑定 (classstyle 除外)。当一个组件没有声明任何 prop 时,这里会包含所有父作用域的绑定 (classstyle 除外),并且可以通过 v-bind="$attrs" 传入内部组件——在创建高级别的组件时非常有用。

好理解一点就是 在子组件使用this.$attrs可以接收父组件传到子组件的自定义属性,但是this.$attrs不接收class style html自带的两个属性,并且如果子组件某个属性已经使用了props:[‘type’]接收了某个自定义属性,此时this.$attrs将不再接收被props接收的部分

使用v-bind可以快速绑定一个对象 v-bind=”{name:’xxx’,age:22}”

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
//App.vue
<template>
<div id="app">
<!-- <router-view/> -->
<h3>this is app.vue</h3>
<!-- 快速绑定数据的简写 -->
<Hello v-bind="personInfo" class="className" ></Hello>

<!-- 等价于 -->
<Hello :name="personInfo.name" :age="personInfo.age" :school="personInfo.school" class="className" ></Hello>

</div>
</template>

<script>
import Hello from "./components/hello";
export default {
name: "App",
data() {
return {
personInfo:{
name:'shao.yuhong',
age:22,
school:'重庆师范大学'
}
};
},
components: {
Hello,
},
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
//Hello.vue
<template>
<div class="box">
<hr/>
<h3>hello.vue</h3>
<!-- 如果需要将参数传到孙组件,可以采用v-bind=$attrs的方式 -->
<HelloSon v-bind="$attrs"/>
</div>
</template>

<script>
import HelloSon from './helloSon.vue';
export default {
name:'hello',
components:{
HelloSon
},
props:{
name:{
type:String,
default:'xx'
}
},
created(){
console.log(this.$attrs); //{age:22,school:'重庆师范大学'} 由于name已经被props接收,所以this.$attrs不能获取name
}
}

$listeners包含了父作用域中的 (不含 .native 修饰器的) v-on 事件监听器。它可以通过 v-on="$listeners" 传入内部组件——在创建更高层次的组件时非常有用。

好理解一点就是 在子组件使用this.$listeners可以接收父组件传到子组件的自定义方法,但是this.$listeners不接收js原生native自带的事件,如click.native focus.native…

使用v-on可以快速绑定多个自定义事件 如v-on=”$listeners”

使用场景:A组件引入B组件,B组件引入C组件;现在C组件需要调A组件的方法,或者是给A组件传参

  • C组件this.$emit(‘事件’,参数)=>B组件接收后向A组件继续this.$emit()=>A组件接收处理
  • B组件使用v-on=”$listeners” ,C组件直接调A组件数据
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
<!--App.vue -->
<template>
<div id="app">
<!-- <router-view/> -->
<h3>this is app.vue</h3>
<Hello class="className" v-bind="personInfo" @appLog="appLog" @appBgColorRandom="appBgColorRandom"></Hello>
</div>
</template>

<script>
import Hello from "./components/hello";
export default {
name: "App",
data() {
return {
personInfo:{
name:'shao.yuhong',
age:22,
school:'重庆师范大学'
}
};
},
methods:{
appLog(){
console.log('appLog')
},
appBgColorRandom(){
const oApp = document.querySelector("#app");
const colors = `rgb(${~~(Math.random() * 255)},${~~(Math.random() * 255)},${~~(Math.random() * 255)},0.8)`;
oApp.style.backgroundColor=colors;
}
},
components: {
Hello,
},
};
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<!--hello-->
<template>
<div class="box">
<hr/>
<h3>hello.vue</h3>
<h4>使用$attrs接收的参数{{$attrs}}</h4>
<!--将A组件的自定义事件通过 v-on传入$listeners-->
<HelloSon v-bind="$attrs" v-on="$listeners"/>
</div>
</template>

<script>
import HelloSon from './helloSon.vue';
export default {
name:'hello',
components:{
HelloSon
},
props:{
name:{
type:String,
default:'xx'
}
},
created(){
console.log(this.$attrs);
}
}
</script>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<!--helloSon.vue-->
<template>
<div class="box">
<hr />
<h3>hello_son.vue</h3>
<button @click="log">打印log</button>
<button @click="changeBgColor">更改app的背景颜色</button>
</div>
</template>

<script>
export default {
name: "hello",
created() {
console.log(this.$attrs);
},
methods: {
log() {
this.$emit("appLog");//此时,C组件=》A组件 直接调
},
changeBgColor() {
this.$emit("appBgColorRandom"); //此时,C组件=》A组件 直接调
},
},
};
</script>

$props

这个比较好理解,即使用prop接收的参数,如果prop里面没有接收,该自定义参数将不会进入$props

$parent

使用$parent子组件可以获取父组件的data methods等数据 也可以直接调父组件的方法 参数如下 不能获取爷组件的哈

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
$attrs: Object
$children: [VueComponent]
$createElement: ƒ (a, b, c, d)
$el: div#app
$listeners: Object
$options: {parent: Vue, _parentVnode: VNode, propsData: undefined, _parentListeners: undefined, _renderChildren: undefined, …}
$parent: Vue {_uid: 0, _isVue: true, $options: {…}, _renderProxy: Proxy, _self: Vue, …}
$refs: {}
$root: Vue {_uid: 0, _isVue: true, $options: {…}, _renderProxy: Proxy, _self: Vue, …}
$scopedSlots: {$stable: true, $key: undefined, $hasNormal: false}
$slots: {}
$vnode: VNode {tag: 'vue-component-4-App', data: {…}, children: undefined, text: undefined, elm: div#app, …}
appBgColorRandom: ƒ ()
appLog: ƒ ()
personInfo: (...)
test: ƒ ()
_c: ƒ (a, b, c, d)
_data: {__ob__: Observer}
_directInactive: false
_events: {}
_hasHookEvent: false
_inactive: null
_isBeingDestroyed: false
_isDestroyed: false
_isMounted: true
_isVue: true

$data

Vue 实例观察的数据对象。Vue 实例代理了对其 data 对象 property 的访问。

简单点说,就是通过this.$data你能得到当时data{}数据里面的响应数据,this.$data包含props的响应数据

$root

当前组件树的根 Vue 实例。如果当前实例没有父实例,此实例将会是其自己。

$children

当前实例的直接子组件。需要注意 $children 并不保证顺序,也不是响应式的。如果你发现自己正在尝试使用 $children 来进行数据绑定,考虑使用一个数组配合 v-for 来生成子组件,并且使用 Array 作为真正的来源。

父组件使用this.$children时,由于加载的顺序,只能在mounted生命周期中this.$children才能获取成功

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
(2) [VueComponent, VueComponent]
0: VueComponent {_uid: 2, _isVue: true, $options: {…}, _renderProxy: Proxy, _self: VueComponent, …}
1: VueComponent
$attrs: (...)
$children: []
$createElement: ƒ (a, b, c, d)
$el: div.hello
$listeners: (...)
$options: {parent: VueComponent, _parentVnode: VNode, propsData: undefined, _parentListeners: undefined, _renderChildren: undefined, …}
$parent: VueComponent {_uid: 1, _isVue: true, $options: {…}, _renderProxy: Proxy, _self: VueComponent, …}
$refs: {}
$root: Vue {_uid: 0, _isVue: true, $options: {…}, _renderProxy: Proxy, _self: Vue, …}
$scopedSlots: {$stable: true, $key: undefined, $hasNormal: false}
$slots: {}
$vnode: VNode {tag: 'vue-component-3-HelloWorld', data: {…}, children: undefined, text: undefined, elm: div.hello, …}
msg: (...)
_c: ƒ (a, b, c, d)
_data: {__ob__: Observer}
_directInactive: false
_events: {}
_hasHookEvent: false
_inactive: null
_isBeingDestroyed: false
_isDestroyed: false
_isMounted: true
_isVue: true
_renderProxy: Proxy {_uid: 4, _isVue: true, $options: {…}, _renderProxy: Proxy, _self: VueComponent, …}
_routerRoot: Vue {_uid: 0, _isVue: true, $options: {…}, _renderProxy: Proxy, _self: Vue, …}
_self: VueComponent {_uid: 4, _isVue: true, $options: {…}, _renderProxy: Proxy, _self: VueComponent, …}
_staticTrees: (2) [VNode, VNode]

v-pre

  • 跳过这个元素和它的子元素的编译过程。可以用来显示原始 Mustache 标签。跳过大量没有指令的节点会加快编译。

  • 示例

    1
    <span v-pre>{{ this will not be compiled }}</span>  <!--页面输出{{ this will not be compiled }} --> 

flex的问题

主轴不一定就是水平的,主轴取决于弹性布局的方向flex-direction,

row横向)布局时主轴就是水平的那条,同时交叉轴就是换行flex-wrap时产生交叉的那一条

交叉轴为flex-wrap换行时,如果对齐为flex-start,则是flex-start对齐的那条线

如果布局中没有存在换行,就不存在交叉轴

图片

  • flex:0 0 340px = flex-grow:0, flex-shirk:0;flex-basis:340px

  • align-self:flex-start; 可以对单个纵向对齐设置,参照下图

  • 同理 justify-self也可以对单个左右对齐单独设置

  • ** flex-flow属性是flex-direction属性和flex-wrap属性的简写形式,默认值为row nowrap**

XSS

Cross-Site Scripting(跨站脚本攻击)简称 XSS,是一种代码注入攻击。攻击者通过在目标网站上注入恶意脚本,使之在用户的浏览器上运行。利用这些恶意脚本,攻击者可获取用户的敏感信息如 Cookie、SessionID 等

XSS 的本质是:恶意代码未经过滤,与网站正常的代码混在一起;浏览器无法分辨哪些脚本是可信的,导致恶意脚本被执行。

类型 存储区* 插入点*
存储型 XSS 后端数据库 HTML
反射型 XSS URL HTML
DOM 型 XSS 后端数据库/前端存储/URL 前端 JavaScript

存储型和反射型 XSS 都是在服务端取出恶意代码后,插入到响应 HTML 里的,攻击者刻意编写的“数据”被内嵌到“代码”中,被浏览器所执行。

预防这两种漏洞,有两种常见做法:

  • 改成纯前端渲染,把代码和数据分隔开。
  • 对 HTML 做充分转义。

纯前端渲染的过程:

  1. 浏览器先加载一个静态 HTML,此 HTML 中不包含任何跟业务相关的数据。
  2. 然后浏览器执行 HTML 中的 JavaScript。
  3. JavaScript 通过 Ajax 加载业务数据,调用 DOM API 更新到页面上。

在纯前端渲染中,我们会明确的告诉浏览器:下面要设置的内容是文本(.innerText),还是属性(.setAttribute),还是样式(.style)等等。浏览器不会被轻易的被欺骗,执行预期外的代码了。

转义 HTML

如果拼接 HTML 是必要的,就需要采用合适的转义库,对 HTML 模板各处插入点进行充分的转义。

在使用 .innerHTML.outerHTMLdocument.write() 时要特别小心,不要把不可信的数据作为 HTML 插到页面上

如果用 Vue/React 技术栈,并且不使用 v-html/dangerouslySetInnerHTML 功能,就在前端 render 阶段避免 innerHTMLouterHTML 的 XSS 隐患。

对于不受信任的输入,都应该限定一个合理的长度。虽然无法完全防止 XSS 发生,但可以增加 XSS 攻击的难度。

HTTP-only Cookie: 禁止 JavaScript 读取某些敏感 Cookie,攻击者完成 XSS 注入后也无法窃取此 Cookie。

尽量不要使用 onLoad="onload('{{data}}')"onClick="go('{{action}}')" 这种拼接内联事件的写法。在 JavaScript 中通过 .addEventlistener() 事件绑定会更安全。

XSRF

CSRF(Cross-site request forgery跨站请求伪造

  • 可以在 HTTP 请求中以参数的形式加入一个随机产生的 token,并在服务器端建立一个拦截器来验证这个 token,如果请求中没有token或者 token 内容不正确,则认为可能是 CSRF 攻击而拒绝该请求
  • 检查 Referer 来源
  • 在http请求头中添加自定义头部

UDP与TCP区别

  • udp是非连接的协议,发送数据前不需要进行TCP三次连接握手,TCP需要进行三次握手连接
  • TCP传输数据可靠,UDP只能尽最大努力交付,但不能保证数据能成功送达
  • 由于UDP传输数据前不需要建立连接,所以UDP速度上比TCP更快
  • TCP保证数据顺序,UDP不保证

全双工半双工单工

  • 【单工】发送方=》接收方,发送方只能发,接收方只能收,如广播、收音机
  • 【半双工】同一时间,发的时候不能收,收的时候不能发,如对讲机
  • 【全双工】发送的时候可以收,接收的时候也可以发,如电话 TCP采用的就是这个

TCP三次握手

三次握手:
第一次握手:客户端发送syn包(syn=x)到服务器,并进入SYN_SEND状态,等待服务器确认;
第二次握手:服务器收到syn包,必须确认客户的SYN(ack=x+1),同时自己也发送一个SYN包(syn=y),即SYN+ACK包,此时服务器进入SYN_RECV状态;
第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=y+1),此包发送完毕,客户端和服务器进入ESTABLISHED状态,完成三次握手。
握手过程中传送的包里不包含数据,三次握手完毕后,客户端与服务器才正式开始传送数据。理想状态下,TCP连接一旦建立,在通信双方中的任何一方主动关闭连接之前,TCP 连接都将被一直保持下去。
————————————————
版权声明:本文为CSDN博主「ronety」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/ronety/article/details/89140053

TCP四次挥手

四次挥手
与建立连接的“三次握手”类似,断开一个TCP连接则需要“四次握手”。
第一次挥手:主动关闭方发送一个FIN,用来关闭主动方到被动关闭方的数据传送,也就是主动关闭方告诉被动关闭方:我已经不 会再给你发数据了(当然,在fin包之前发送出去的数据,如果没有收到对应的ack确认报文,主动关闭方依然会重发这些数据),但是,此时主动关闭方还可 以接受数据。
第二次挥手:被动关闭方收到FIN包后,发送一个ACK给对方,确认序号为收到序号+1(与SYN相同,一个FIN占用一个序号)。
第三次挥手:被动关闭方发送一个FIN,用来关闭被动关闭方到主动关闭方的数据传送,也就是告诉主动关闭方,我的数据也发送完了,不会再给你发数据了。
第四次挥手:主动关闭方收到FIN后,发送一个ACK给被动关闭方,确认序号为收到序号+1,至此,完成四次挥手。
————————————————
版权声明:本文为CSDN博主「ronety」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/ronety/article/details/89140053

【问题1】为什么连接的时候是三次握手,关闭的时候却是四次握手?
答:因为当Server端收到Client端的SYN连接请求报文后,可以直接发送SYN+ACK报文。其中ACK报文是用来应答的,SYN报文是用来同步的。但是关闭连接时,当Server端收到FIN报文时,很可能并不会立即关闭SOCKET,所以只能先回复一个ACK报文,告诉Client端,"你发的FIN报文我收到了"。只有等到我Server端所有的报文都发送完了,我才能发送FIN报文,因此不能一起发送。故需要四步握手

原型与原型链

原型

原型定义了公共的属性和方法,通过原型创建的实例对象,将共享拥有原型上的属性和方法

B是通过Log类创建的,所以B共享拥有了Log类的属性和方法,这个时候Log就是B类的原型, 此时B类的隐式原型===Log的显式原型,即B.__proto__===Log.protype

原型链主要解决的是继承问题

在Javascript中如果访问一个对象本身不存在的属性或是方法,就首先在它的原型对象上去寻找,如果原型对象上也不存在,就继续在原型对象的原型对象上去寻找,直到找到为止。那么原型对象有尽头么?所有对象的原型尽头是Object.prototype,那么Object.prototype这个对象的proto指向啥呢?答案是null。我们日常开发中用到的绝大多数对象的proto基本不会直接指向Object.prototype,基本都是指向另一个对象。比如所有的函数的proto都会指向Function.prototype,所有数组的proto都会指向Array.prototype


简单点来说就是 如果访问一个对象本身不存在的属性或是方法,就首先在它的原型对象上去寻找,如果原型对象上也不存在,就继续在原型对象的原型对象上去寻找,直到找到为止

每一个实例对象的创建(除NULL外),都会有一个隐式对象__proto__,每一个函数的创建都会有一个prototype,__proto__指向的原型上的prototype,并继承原型上的属性和方法


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class A {
constructor(name = 'shao.yuhong',age = 24) {
(this.name =name), (this.age = age);
}
render(){
console.log('this is render,name='+this.name+',age='+this.age)
}
}
class Log extends A {
constructor(name, age) {
super(name, age);
}
log() {
console.log(this.name + "/" + this.age);
}
}

const B = new Log('liming',30);
console.log(B.__proto__ === Log.prototype); //true
B.log();
B.render();

B类的数据打印参考

1
2
3
4
5
6
7
8
9
10
Log {name: 'liming', age: 30}
age: 30
name: "liming"
[[Prototype]]: A
constructor: ƒ Log(name, age)
log: ƒ log()
[[Prototype]]: Object
constructor: ƒ A()
render: ƒ render()
[[Prototype]]: Object

事件循环机制

event loop分为宏任务微任务

宏任务:setInterval 、setTimeout 、I/O 、 UI render

微任务:Object.observe mutationObserve promise

事件处理时,会先执行整体代码、遇见微任务会将它加入到微任务队列、遇见宏任务会将宏任务加入宏任务队列。

等整体代码执行完成后,再搜索微任务、最后执行宏任务

需要注意的是 这里面的promise指的是**.then**里面的是微任务方法,promise里面的正常执行

1
2
3
4
5
6
7
8
9
10
11
setTimeout(()=>{
console.log('d');
},0);
console.log('a');
new Promise(resolve=>{
console.log('b');
resolve();
}).then(res=>{
console.log('c');
});

结果:abcd

数据加密方式

Md5 base64 AES DES sha1

vue render函数与component的对比

参考链接:URL

vue中使用render函数创建模板有两个方式,使用createElement或者JSX语法

  • createElement语法 该语法不适合复杂情况,不作讨论

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    props: ['items'],
    render: function (createElement) {
    if (this.items.length) {
    return createElement('ul', this.items.map(function (item) {
    return createElement('li', item.name)
    }))
    } else {
    return createElement('p', 'No items found.')
    }
    }
  • jsx语法 使用react的jsx语法,更简单 完全与react语法相似

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    export default {
    props:['arr'],
    data(){
    return {
    count:100
    }
    },
    methods:{
    countHanle(val,ev){
    console.log(ev);
    this.count+=val;
    }
    },
    render: function (h) {

    return (<div>
    <h1>内容</h1>
    <ul>
    {
    this.arr.map((item)=>{
    return <li key={item}>{item}</li>
    })
    }
    <li></li>
    </ul>
    <hr/>
    <div>
    <button class={['button','el-button'].join(' ')} onClick={e=>this.countHanle(-1,e)}>-</button>
    <span>{this.count}</span>
    <button onClick={e=>this.countHanle(1,e)}>+</button>
    </div>
    </div>);
    }
    }

以上render使用时

1
2
import List from './components/list';
<List></List>

slot

  • 使用slot插入的样式,子组件样式高于父组件

  • 使用slot插入,默认使用的是父组件里面的值

    1
    2
    3
    4
    5
    6
    7
    8
    9
      <template #h3>
    <h2>这是h1的v-slot:h3 slot---name:{{dataName}}</h2>
    </template>
    data(){
    return {
    dataName:'name is app.vue'
    }
    }
    //dataName ='name is app.vue'
  • 使用slot插入,如果需要<template>{{name}}</templateslot里面的值不需要父组件而是使用子组件的话,需要两个走

    1. <template #h1="作业域名称"></template> , 注意#h1===v-slot="h1",一种简写

    2. 作用域有了后,需要在<slot name="h1" :data="子组件数据"></slot>

      1
      2
      3
      4
      5
      6
      7
      <!--父组件 -->
      <template #h2="shao">
      <h2>这是h1的v-slot:h2 slot---name:{{shao.dataName}}</h2>
      </template>

      <!--子组件-->
      <slot name="h2" :dataName="dataName"></slot>

      参考链接:https://blog.csdn.net/weixin_45432736/article/details/108552978

普通函数、箭头函数、构造函数的区别

箭头函数

箭头函数是普通函数的简写,可以更优雅的定义一个函数,和普通函数相比,有以下几点差异:

1、函数体内的 this 对象,就是定义时所在的对象,而不是使用时所在的对象。

2、不可以使用 arguments 对象,该对象在函数体内不存在。如果要用,可以用 rest 参数代替。

3、不可以使用 yield 命令,因此箭头函数不能用作 Generator 函数。

4、不可以使用 new 命令,因为:

  • 没有自己的 this,无法调用 call,apply。
  • 没有 prototype 属性 ,而 new 命令在执行时需要将构造函数的 prototype 赋值给新的对象的 proto

普通函数

  1. this指向的调用的实例

  2. 有arguments

  3. 使用普通函数定义时,如果函数没有返回值,打印该函数会是undefind

    1
    2
    function fn(){ }
    console.log(fn);//undefind

构造函数

  1. 使用普通函数定义时,如果函数没有返回值,打印该函数会是实例
  2. this指针指向的是当前构造函数实例
1
2
3
function fn(){}
const fnMethod = new Fn();
console.log(fnMethod); //[object Object]
  • localStorage生命周期是永久,这意味着除非用户显示在浏览器提供的UI上清除localStorage信息,否则这些信息将永远存在。sessionStorage生命周期为当前窗口或标签页,一旦窗口或标签页被永久关闭了,那么所有通过sessionStorage存储的数据也就被清空了。
  • 在浏览器中,如果A标签页打开了当前项目,localStorage能在B标签页中获取已经存储的数据。而在sessionStorage中,只在当前窗口或者使用js a标签触发的跳转页面能获取已经存储的数据
  • localStorage和sessionStorage的存储数据大小一般都是:5MB,不同浏览器可能存在一些差异
  • localStorage和sessionStorage都保存在客户端,不与服务器进行交互通信。
  • cookie的大小被限制在4KB
  • 缓存解析上的不同:localStorage sessionStorage直接由浏览器解析。cookie session的解析需要通过http发送给服务端,由服务端解析后返回给客户端
  • cookie session默认生命周期都是在当前页面被关闭后,与localStorage sessionStorage不同的是,cookie session可以设置过期时间,而localStorage sessionStorage是不能直接设置的,但可以配合存入过期时间,页面进入入口 文件时,判断当前系统时间与过期时间,从而决定是否需要清除localStorage sessionStorage
  • 安全性:session的安全性大于cookie。原因是session存储在服务器、而cookie是存储在客户端。在早期前后端未分离时,后端通过session存储登陆状态

BFC块级上下文

BFC(Block formatting context)直译为”块级格式化上下文”,它是一个独立的渲染区域,内部渲染不影响外面

形成BFC的条件

  • 1、float:left
  • 2、position的值为fixed; absolute;
  • 3、display的值是inline-block、table-cell、flex、table-caption或者inline-flex
  • 4、overflow的值是hidden/auto/scoll

使用BFC可以直接margin重叠问题

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<html>
<style>
p{
margin: 20px 0;
background-color: red;
overflow: hidden;
}
</style>
<body>

<p>1</p>
<p>2</p>
<div>
<p>3</p>
</div>

<p>请仅仅把标题标签用于标题文本。不要仅仅为了产生粗体文本而使用它们。请使用其它标签或 CSS 代替。</p>

</body>
</html>

效果图

上面代码运行后,明显可以发现p的margin-top:20px,margin-bottom:20px; pp之前应该是40,而实际上只有20,发生了margin重叠;

现在用BFC的思想,在div上加上overflow:hidden后,重叠的问题就解决了,效果如下

== (|) 垂直margin为什么会重叠?

找到了一个很好的解释:margin的定义不是让元素移动xxpx,而是这个元素的旁边必须有xxxpx的的空白。

vue react jquery对比

  • jquery的思想是操作dom节点实现视图上的更新,这与vue react是最大的区别,而vue react思想是数据驱动视图更新 并且使用vNode虚拟Dom映射到真实DOM,通过diff算法实现视图上更新
  • jquery采用大量操作dom的方式,性能上没有vue/react好
  • jquery主要面向的项目是普通html单个页面,且兼容性好,在考虑IE8的浏览器兼容时,react vue没有他的优势,因为vue/react最低浏览器要求ie9以上.而vue/react面向的是一个应用型
  • 使用vue/react最大的缺点是不利于seo,搜索引擎不能抓取相关数据,原因是页面中的数据是后续加载的。而jquey的单个页面不存在这个问题
  • 最后vue /react采用了Vnode虚拟DOM,需要在内存中生成dom树的备份节点,所以会消耗部分内存
  • vue通过diff算法,局部更新页面。而react的更新将是整个页面,包含子孙组件。所以react提供了shouldComponentUpdate(nextProps,nextState)方法,决定是否需要更新子组件
  • vue在扩展上使用minxs混入、react采用的是HOC高阶组件的方式

HTTP状态码

502 网关或者代理服务器错误
500 内部服务器错误
404 资源不存在
403 服务器收到客户的请求,但是拒绝执行
302 资源临时移动,302浏览器下次会依然尝试着请求该资源
301 资源永久移动,301浏览器下次不会再请求该资源
304 资源使用缓存资源
200 请求成功

HTTP缓存机制

缓存机制分为强缓存协商缓存

强缓存:不需要通过服务端判断,直接使用本地资源

协商缓存:由服务器判断,资源使用服务器资源还是本地资源

响应头 (常用)值 说明
Cache-Control no-cache, no-store, must-revalidate, max-age, public, private 强制缓存
Last-Modified 请求的资源最近更新时间 协商缓存
ETag string 协商缓存、资源版本号

协商缓存时,首次会通过http响应资源时返回资源的同时,设置更新时间或者资源版本号,下次请求该资源时,http请求状况会添加If-Modified-Since | If-None-Match头部信息,服务器收到该头部信息后,通过比对,判断是否使用缓存资源还是服务器资源

请求头
If-None-Match 缓存响应头中的 ETag 值
If-Modified-Since 缓存响应头中的 Last-Modified 值

参考网站

for…in 和 for…of

  • forEach和map,针对await不生效;使用break或continue会报错;使用return 无效;

  • for循环、for…in,for…of,支持await,for和for…of中可以使用break和continue;for…in会忽略continue和break

    for…in循环:主要为遍历对象而设计,不适用于遍历数组。

    遍历数组缺点:

    • 数组的键名是数字;
    • 不仅遍历数字键名,还会遍历手动添加的其他键,甚至包括原型链上的键;
    • 某些情况下,for…in循环会以任意顺序遍历键名。

    for …of:

    • es6 中添加的循环遍历语法;
    • 支持遍历数组,类数组对象(DOM NodeList),字符串,Map 对象,Set 对象,Generator 对象;
    • 不支持遍历普通对象
    • 遍历后输出的结果为数组元素的值;
    • 可搭配实例方法 entries(),同时输出数组的内容和索引;

点击劫持漏洞

定义

点击劫持是一种视觉欺骗的攻击手段,攻击者将需要攻击的网站通过 iframe 嵌套的方式嵌入自己的网页中,并将 iframe 设置为透明,在页面中透出一个按钮诱导用户点击。

防御

X-Frame-Options HTTP 响应头是用来给浏览器指示允许一个页面可否在 <frame>, <iframe> 或者 <object>中展现的标记。网站可以使用此功能,来确保自己网站的内容没有被嵌到别人的网站中去,也从而避免了点击劫持 (clickjacking) 的攻击。

1
2
3
4
X-Frame-Options有三种可配置值
X-Frame-Options: deny [dɪ'naɪ]
X-Frame-Options: sameorigin
X-Frame-Options: allow-from https://example.com/

deny
表示该页面不允许在 frame 中展示,即便是在相同域名的页面中嵌套也不允许。
sameorigin
表示该页面可以在相同域名页面的 frame 中展示。
allow-from uri
表示该页面可以在指定来源的 frame 中展示。
注: 在网页中设置meta标签是无用的!例如,<meta http-equiv="X-Frame-Options" content="deny"> 是没有效果的。不要使用这种方式。需要在下面的配置实例中配置HTTP Header的方式来进行配置,X-Frame-Options才会起作用。

视频讲解参考

点击劫持:https://www.bilibili.com/video/BV1ve411p7qt?p=4

URL跳转漏洞

定义

通过可信网址后添加重定向的地址实现的跳转,如:http://www.baiud.com?redirect = http://www.shaoyuhong.cn

常见于活动链接,将上述URL发给其它人,打开这个链接后后台代码执行重定向时,跳转到对应的恶意网站

跳转方式主要有三种:Meta标签、JS跳转、Header跳转

防御

视频讲解参考

URL跳转漏洞:https://www.bilibili.com/video/BV1ve411p7qt?p=5

sql注入漏洞

输入用户名: admin’空格–空格 密码随意

php写后台例

$user = $_POST[‘user’];

$pwd = $_POST[‘pwd’];

$pdo->query(‘select * from ‘tb_user’ where user=”$user” and pwd =”$pwd” ‘);

传入密码后,sql变成了

select * from ‘tb_user’ where user=’admin’ – ‘…….’

文件上传漏洞

获取文件后缀名

1
2
3
4
5
6
7
8
9
10
var str  = '个人计划书.2022.excel.md'

/** 方法1 **/
const names = str.split('.');
const fileType = names[names.length-1];


/** 方法2 **/
const endIndex = str.lastIndexOf('.');
const fileType = str.substring(endIndex+1);

encodeURI,encodeURIComponent 有什么区别?

encodeURI 是对整个 URI 进行转义,将 URI 中的非法字符转换为合法字符,所以对于一些在 URI 中有特殊意义的字符不会进行转义。

encodeURIComponent 是对 URI 的组成部分进行转义,所以一些特殊字符也会得到转义。

谈谈你对 webpack 的看法

我当时使用 webpack 的一个最主要原因是为了简化页面依赖的管理,并且通过将其打包为一个文件来降低页面加载时请求的资源
数。

我认为 webpack 的主要原理是,它将所有的资源都看成是一个模块,并且把页面逻辑当作一个整体,通过一个给定的入口文件,webpack 从这个文件开始,找到所有的依赖文件,将各个依赖文件模块通过 loader 和 plugins 处理后,然后打包在一起,最后输出一个浏览器可识别的 JS 文件。

  • Webpack 具有四个核心的概念,分别是 Entry(入口)、Output(输出)、loader 和 Plugins(插件)。

  • Entry 是 webpack 的入口起点,它指示 webpack 应该从哪个模块开始着手,来作为其构建内部依赖图的开始。

  • Output 属性告诉 webpack 在哪里输出它所创建的打包文件,也可指定打包文件的名称,默认位置为 ./dist。

  • loader 可以理解为 webpack 的编译器,它使得 webpack 可以处理一些非 JavaScript 文件。在对 loader 进行配置的时候,test 属性,标志有哪些后缀的文件应该被处理,是一个正则表达式。use 属性,指定 test 类型的文件应该使用哪个 loader 进行预处理。常用的 loader 有 css-loader、style-loader 等。

  • 插件可以用于执行范围更广的任务,包括打包、优化、压缩、搭建服务器等等,要使用一个插件,一般是先使用 npm 包管理器进行安装,然后在配置文件中引入,最后将其实例化后传递给 plugins 数组属性。

什么是 rest 参数?

rest 参数(形式为…变量名),用于获取函数的剩余参数。

1
2
3
4
function fn(a,...b){
//b= [2,3,4]
}
fn(1,2,3,4);

哪些操作会造成内存泄漏?

  • 第一种情况是我们由于使用未声明的变量,而意外的创建了一个全局变量,而使这个变量一直留在内存中无法被回收。

  • 第二种情况是我们设置了 setInterval 定时器,而忘记取消它,如果循环函数有对外部变量的引用的话,那么这个变量会被一直留
    在内存中,而无法被回收。

  • 第三种情况是我们获取一个 DOM 元素的引用,而后面这个元素被删除,由于我们一直保留了对这个元素的引用,所以它也无法被回
    收。

  • 第四种情况是不合理的使用闭包,从而导致某些变量一直被留在内存当中。

数组的 fill 方法?

fill() 方法用一个固定值填充一个数组中从起始索引到终止索引内的全部元素。不包括终止索引。
fill 方法接受三个参数 value,start 以及 end,start 和 end 参数是可选的,其默认值分别为 0 和 this 对象的 length 属性值。

最全的Vue 组件间的参数传递方式?

(1)父子组件间通信

  • 第一种方法是子组件通过 props 属性来接受父组件的数据,然后父组件在子组件上注册监听事件,子组件通过 emit 触发事
    件来向父组件发送数据。

  • 第二种是通过 ref 属性给子组件设置一个名字。父组件通过 $refs 组件名来获得子组件,子组件通过 $parent 获得父组
    件,这样也可以实现通信。

  • 第三种是使用 provider/inject,在父组件中通过 provider 提供变量,在子组件中通过 inject 来将变量注入到组件
    中。不论子组件有多深,只要调用了 inject 那么就可以注入 provider 中的数据。

(2)兄弟组件间通信

  • 第一种是使用 eventBus 的方法,它的本质是通过创建一个空的 Vue 实例来作为消息传递的对象,通信的组件引入这个实
    例,通信的组件通过在这个实例上监听和触发事件,来实现消息的传递。

  • 第二种是通过 $parent.$refs 来获取到兄弟组件,也可以进行通信。

(3)任意组件之间

  • 使用 eventBus ,其实就是创建一个事件中心,相当于中转站,可以用它来传递事件和接收事件。

如果业务逻辑复杂,很多组件之间需要同时处理一些公共的数据,这个时候采用上面这一些方法可能不利于项目的维护。这个时候
可以使用 vuex ,vuex 的思想就是将这一些公共的数据抽离出来,将它作为一个全局的变量来管理,然后其他组件就可以对这个
公共数据进行读写操作,这样达到了解耦的目的。

vue-router 中的导航钩子函数共6个

(1)全局的钩子函数 beforeEach 和 afterEach

beforeEach 有三个参数,to 代表要进入的路由对象,from 代表离开的路由对象。next 是一个必须要执行的函数,如果不传参数,那就执行下一个钩子函数,如果传入 false,则终止跳转,如果传入一个路径,则导航到对应的路由,如果传入 error ,则导航终止,error 传入错误的监听函数。

(2)单个路由独享的钩子函数 beforeEnter,它是在路由配置上直接进行定义的。

(3)组件内的导航钩子主要有这三种:beforeRouteEnter、beforeRouteUpdate、beforeRouteLeave。它们是直接在路由组
件内部直接进行定义的。

获取url参数通用方法

1
2
3
4
5
6
7
8
9
10
11
12
function GetQueryString(name) {
var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)", "i");
var r = window.location.search.substr(1).match(reg); //获取url中"?"符后的字符串并正则匹配
var context = "";
if (r != null)
context = r[2];
reg = null;
r = null;
return context == null || context == "" || context == "undefined" ? "" : context;
}
alert(GetQueryString('handle'));
//需要获取什么,就传入属性名

Nodejs解决跨域

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
server.on('request', (request, response) => {

response.setHeader('Access-Control-Allow-Origin', '*');
response.setHeader("Access-Control-Allow-Headers", "X-Requested-With");
response.setHeader("Access-Control-Allow-Methods", "PUT,POST,GET,DELETE,OPTIONS");
response.setHeader("Access-Control-Allow-Headers","Content-Type,XFILENAME,XFILECATEGORY,XFILESIZE");

const subIndex = request.url.indexOf('?');
let path = request.url;
if(subIndex !== -1){
path = request.url.substring(0,subIndex);
}

if (path ==='/test') {
response.end(JSON.stringify({code:200}));
return;
}

response.end(JSON.stringify({code:200}));
})
server.listen('18002');
  • 本文标题:js第二弹
  • 本文作者:邵预鸿
  • 创建时间:2021-12-21 10:23:18
  • 本文链接:/images/logo.jpg2021/12/21/js第二弹/
  • 版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!