KevinSwift

  • 首页
  • 关于
  • 标签
  • 分类
  • 相册

伪数组和promise,async,await的关系

发表于 2019-07-19 | 分类于 js相关

何为伪数组
如果一个对象的所有键名都是正整数或者0,并且具有Length属性,那么这个对象就很像数组,语法上就非常像伪数组。

1
2
3
4
5
6
7
8
9
var obj = {
0:'a',
1:'b',
2:'c',
length:3
};
obj[0] //'a'
obj[1] //'b'
obj.length //3

对象obj是一个类似数组的对象,但是类似数组的对象并不是数组,因为它们不具备数组的方法,对象obj没有数组的push方法。
典型的”类似数组的对象”是函数的arguments对象,以及大多数DOM元素集,还有字符串/
数组的slice方法可以将类似数组的对象转变成真正的数组

1
2
3
4
5
function doSomething() {
console.log(arguments);
var args = Array.prototype.slice.call(arguments);
return args;
}

ES6提供了array.from方法,将伪数组转化成真正的数组

1
2
3
4
5
let btns = document.getElementByTagName("button");
console.log(btns);
Array.from(btns).forEach(item => {
console.log(item);
})

将伪数组转化成真正的数组
扩展运算符(…)也可以将某些数据结构转化为数组。只不过需要在背后调用遍历器接口Symbol.iterator
值得注意的是如果一个对象没有部署遍历器接口,使用扩展运算符是无法将类似数组对象转换成数组的

1
2
3
4
function doSomething(){
return [...arguments];
}
doSomething('a','b','c');

Array.of相当于Array的构造器,会创建一个包含所有传入参数的数组,而不管参数的数量与类型:

1
2
3
items = Array.of(2); 
console.log(items[0]); //2
console.log(items.length); //2

promise相关

异步编程模式在前端开发中,显得越来越重要,从最开始的XHR到封装后的ajax都在试图解决异步编程中的问题,
传统ajax中,当异步请求之间的数据存在依赖关系的时候,就可能产生出多层的回调嵌套问题。俗称”回调地狱”,
promise的出现让我们告别了回调函数,写出了更加优雅的代码。
async/await的到来使得异步代码看起来像同步代码的替代方法。
promise的原理:
对一种异步操作的封装,可以通过独立的接口添加在异步操作执行成功,失败时执行的方法,主流的规范是promise/a+
promise的状态:pending初始状态,fulfilled成功,rejected失败.
promise实例必须实现then这个方法 then必须返回2个函数作为参数(resolve,reject)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
var promise = new Promise(function(resolve,reject){
var img = document.createElement("img");
img.onload = function() {
resolve(img);
};
img.onerror = function(){
reject("图片加载失败");
}
});
result.then(
function(img){
console.log();
}.then(function(img){
console.log();
})
)

promise的级联操作
result1.then(function(img){

}).then(function(img){

}).catch(function(ex){
console.log();
})
promise的all方法,可以并行执行所有任务。

1
2
3
4
5
6
7
8
9
var p1 = new Promise(function(resolve,reject){
setTimeout(resolve,500,'p1');
})
var p2 = new Promise(function(resolve,reject){
setTimeout(resolve,600,'p2');
})
promise.all([p1,p2]).then(function(results){
console.log(results);
})

promise.race接收一个包含多个promise对象的数组,只要一个完成,就执行success.
async/await是写异步代码的新方式,优于回调函数和promise.
async/await基于promise实现的。不能用于普通的回调函数。
。。。。。。。与promise是一样的,是非阻塞的。
。。。。。。。使得异步代码看起来像同步代码一样,没有回调函数。但是改变不了js单线程,异步的本质。

1
2
3
4
const load = async function(){
const result1 = await loading(src1);
console.log(result1);
}

async,await相关

async/await较promise有诸多好处
1.简洁。使用async/await明显节约了不少代码。不需要写.then()方法。
2.中间值。调用promise1,使用promise1返回的结果去调用promise2

1
2
3
4
5
const makeRequest = async () => {
const value1 = await promise1();
const value2 = await promise2(value1);
return promise3(value1,value2);
}

vue视频学习笔记

发表于 2019-07-16 | 分类于 js相关 , vue相关

每个vue实例在被创建时候都要经历一系列的初始化过程,
设置数据监听,编译模板,将实例挂载到DOM并在数据变化时更新DOM,
同时这个过程会运行一些生命周期函数钩子,
created:实例被创建
mouted,updated,destroyed.
计算属性的使用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
var vm = new Vue({
el:"example",
data:{
message:"hello
},
computed:{
vm.reverseMessage依赖于message,所以message一旦变化 reverseMessage就会变化
reverseMessage:function() {

return this.message.split('').reverse().join('');
},
fullName:{
//get和set方法
get:function(){
return this.firstName
}
set:function(newValue){
this.firstName = "ckq"
}
}
}
})

计算属性是基于它们的响应式依赖进行缓存的,只有相关响应式发生了变化,才会重新求值。
message没变化,多次访问reverseMessage。计算属性还是返回之前计算的结果。
而不必再次执行函数。
侦听属性,利用watch:

1
2
3
4
5
watch:{
firstName:function(val){
this.fullName = val + this.lastName;
}
}

通过class和style绑定属性的时候,可以通过对象或者是数组

1
<div v-bind:class = "{active:isActive}"></div>

active这个class是否加载决定于isActive属性是否为true

1
2
3
4
5
6
data:{
classObj:{
active:true,
'text-danger':false
}
}

数组的方法

1
<div v-bind:class = "[active,error]">

内联样式的绑定

1
<div v-bind:style = "{color:active}"></div>

v-if用于条件渲染
v-if与v-else联合使用 v-else-if联合使用

1
2
3
4
<template v-if = "ok">
<h1>title</h1>
<p>p1</p>
</template>

v-if与v-show的区别
v-if是真正的条件渲染,当为false时会删除dom
而v-show是是会修改其css属性来展现与否。
当不存在的时候,v-if是从dom中移除,v-show为隐藏,不从dom中移除。
v-for的使用

1
2
3
4
<li v-for = "(item,index) in items">
<li v-for = "(value,name,index) in object">
{{index}} --{{item.message}}
</li>

当vue正在更新使用v-for渲染的元素列表时,使用”就地跟新”原则,
如果数据项的顺序被改变,vue将不会移动dom元素来匹配数据项的顺序,而是就地跟新每个元素,并且确保在每个索引位置都被
正确的渲染。类似于vue 1.x中的track-by = “$index”
可以使用key进行绑定

1
2
<div v-for = "item in items" v-bind:key = "item.id">
</div>

利用响应式
Vue.set(vm.items,indexOfItems,value);
当处于同一个节点时,v-for的优先级比v-if更高,这意味着v-if将分别重复运行于每个v-for循环中,当你只想为部分项渲染节点时,这种优先级机制十分有用。

1
<li is = "todo-item" v-for = "(todo,index) in todos">

的 is=”todo-item” 属性。这种做法在使用 DOM 模板时是十分必要,这么做实现的效果与

1
<todo-item>

相同。
但是可以避开一些潜在的浏览器解析错误。
v-on:click.stop = “doThis”
v-on:submit.prevent = “on
v-on:keyup.13 = “submit”
@click.ctrl = “onclick”
v-model在表单input,textarea以及select上创建数据的双向绑定
v-model本质上还是语法糖,负责监听用户的输入事件并且更新数据。并对一些极端场景进行一些特殊处理。
会忽略所有表单的check,value,select值。
总是将vue实例的数据作为数据来源。应该通过js在组件中data选项声明初始值。
vue自定义组件

1
2
3
4
5
6
7
8
9
//vue自定义组件
Vue.component('button-counter',{
data:function () {
return{
count:0
}
},
template:'<button v-on:click = "count++">'
})

与new Vue接收相同的选项 例如data,computed,watch,methods等以及生命周期函数钩子
data必须是一个函数。而不是一个对象,因此每个实例可以维护一份被返回对象的独立的拷贝

1
2
3
4
5
data:function(){
return{
count:0
}
}

Vue.component是全局注册的
通过props向子组件传递数据
一个值传递给props,就变成了组件实例的一个属性

1
2
3
4
Vue.component('blog',{
props:['title'],
template:'<h3>{{title}}</h3>'
})

就像访问data中的数据是一样的

1
<blog-post :key = 'post.id' :title = 'post.title'>

每个组件必须要有一个根元素,可以将模板的内容包裹在一个根元素内。

1
2
3
4
<div>
<h3>{{title}}</h3>
<div v-html = "content"></div>
</div>

component的is属性来切换组件

1
<component v-bind:is="currentTabComponent"></component>

vue组件注册通过

1
2
3
4
5
vue.component('my-comment-name',{

})
//使用时候
<my-component-name></my-component-name>

全局注册往往不理想,局部注册

1
2
3
4
5
6
7
8
var ComponentA = {};
new Vue({
el:"#app",
components:{
'component-a':ComponentA,

}
});

导入组件

1
2
3
4
5
6
import ComponentA from './ComponentA';
export default{
components:{
ComponentA
}
}

props传递对应的值类型

1
2
3
4
props:{
title:String,
likes:Number
}

提供了类型检测 在使用时。
任何类型的值都可以传递给props

1
2
3
4
5
6
7
8
9
<blog-post v-bind:likes = "42"></blog-post>
<blog-post v-bind:is-publish = "false"></blog-post>
<blog-post v-bind:comment-ids="[234, 266, 273]"></blog-post>
<blog-post
v-bind:author="{
name: 'Veronica',
company: 'Veridian Dynamics'
}"
></blog-post>

props都是单向数据流的传递 父级props的跟新会向下流动到子组件中,但是反过来是不会的。
这样可以阻止子组件意外改变父组件的状态
每次父组件发送变化,子组件props都会刷新为最新的值
注意:js中对象和数组都是通过引用传入的,所以对于一个数组或者对象类型的props,在子组件中改变这个对象或数组本身将会影响在父组件中的状态。
注意prop会在一个组件实例创建之前进行验证,所有实例的属性,例如data,computed等在函数中是不可用的。
事件名:事件名不存在任何自动化的大小写转换。而是触发的事件名必须匹配这个事件所用的名称
触发事件

1
this.$emit("myEvent")

随后在组件上绑定事件

1
<my-component v-on:my-event = "doSomthing">

自定义事件重点看
自定义指令,在页面打开后,应该自动聚焦到输入框上

1
2
3
4
5
Vue.directive('focus',{
inserted:function(el){
el.focus();
}
})

指令的钩子函数

bind:只调用一次,指令第一次绑定到元素时调用,在这里可进行一次性的初始化操作。
inserted:被绑定元素插入到父节点时调用,(仅保证父节点存在,但不一定已被插入到文档中)
updated:所有组件的VNode更新时调用,但是可能发生在其子 VNode 更新之前。指令的值可能发生了改变,也可能没有。但是你可以通过比较更新前后的值来忽略不必要的模板更新 (详细的钩子函数参数见下)。
componentUpdated:指令所在组件的VNode及其子VNode全部跟新后调用
unbind:只调用一次,指令与元素解绑时调用。
尝试使用render函数来做渲染

1
2
3
4
5
6
7
8
9
10
11
12
13
14
Vue.component('anchor',{
render:function(createElement){
return createElement(
'h' + this.level, //标签名称
this.$slots.default//子节点数组
)
},
props:{
level:{
type:Number,

}
}
})

createElement返回的是createNodeDescription,因为它所包含的信息会告诉vue页面上需要渲染什么节点。包括其子节点的描述信息。
插件的使用
通过全局的方法Vue.use()来加载使用插件
需要在new Vue()之前使用

1
2
3
var Vue = require('vue');
var vueRouter = require('vue-router');
Vue.use(vueRouter);

过滤器
双括号插值

1
2
3
4
5
6
7
8
9
{{message | capitalize}}
filters:{
capitalize:function(value){
if(!value)
return '';
value = value.toString();
return value.charAt(0);
}
}

过滤器的连续使用

1
{{message | filterA | filterB}}

将过滤器A执行完的结果传递给过滤器B
vue单文件的预处理器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<template lang = "jade">
<div>
ccc
</div>
<script>
export default{
data() {

}.
components:{
otherComponents
}
}
</script>

vue进行异步跟新DOM的情况,一些依赖DOM更新结果的断言必须在
vue.nextTick中回调中进行。

1
2
3
4
5
6
Vue.nextTick(() => {
expect(vm.$el.textContent).toBe('foo');
done();
});

process.env.NODE_ENV

vue源码根据process.env.NODE_ENV决定是否启用生产环境模式,默认为开发环境模式。

服务端渲染

通过nuxt.js搭建服务端渲染。nuxt是一个基于vue生态的更高层的框架,为开发服务端渲染的 Vue 应用提供了极其便利的开发体验。更酷的是,你甚至可以用它来做为静态站生成器。推荐尝试。
this.$nextTick保证元素被挂载到dom中才触发

1
2
3
4
5
mounted: function () {
this.$nextTick(function () {
// 代码保证 this.$el 在 document 中
})
}

vue中slot的使用

vue中slot的使用

1
2
3
4
5
6
7
8
9
10
11
12
<div id = "app">
<child>
<span>1111</span>
</child>
</div>
<script>
Vue.component("child",{
template:"<div>这是一个div标签</div>"
});
new Vue({
el:"#app"
})

child内部的span等标签会被div等所有的覆盖掉 没有slot的情况

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<div id = "app">
<computer>
<div slot = "CPU">ddd</div>
<div slot = "GPU">GPU</div>
</computer>
</div>
<script>
Vue.component("computer",{
template:`<div>
<slot name = "CPU">CPU插槽</slot>
<slot name = "GPU">GPU插槽</slot>
</div>
`,
});
new Vue({
el:"#app"
})

根据name进行绑定 将slot具体渲染成对应组件

单个slot的情况
简单来说,使用slot标签,可以将1111放到子组件中想让他显示的地方

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<div id = "app">
<child>
<span>1111</span>
</child>
</div>
<script>
Vue.component("child",{
template:`<div>
这是<slot></slot>
一个div
</div>
`,
});
new Vue({
el:"#app"
})

子组件内部的slot标签会被渲染成1111所以可以将父组件中的传过来
有多个标签的时候也会被插入,被当成一个slot来看待
具名slot(有名称的slot)
将放在子组件里的不同html标签放在不同的位置
父组件在要分发的标签里面添加slot = “name名”的属性
子组件在对应的分发位置的slot标签里面,添加name = “name”属性,
然后会将对应的标签放在位置里

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<div id = "app">
<child>
<span slot = "one">one</span>
<span slot = "two">two</span>
</child>
</div>
<script>
Vue.component("child",{
template:`<div>
这是<slot name = "two"></slot>
一个div
<br>
这是<slot name = "one"></slot>
一个div
</div>
`,
});
new Vue({
el:"#app"
})

将父标签里的two渲染到子组件里的第一个,将父标签里的one渲染到子组件李的第二个
没有slot的话,将会显示默认的值。
也就是没有将父组件中的slot插入到子组件中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<div id = "app">
<child>
<span slot = "one">one</span>

</child>
</div>
<script>
Vue.component("child",{
template:`<div>
这是<slot name = "two">no two</slot>
一个div
<br>
这是<slot name = "one"></slot>
一个div
</div>
`,
});
new Vue({
el:"#app"
})

slot = two 没有标签,因此显示内部的no two
作用域插槽是一种特殊类型的插槽,用作一个(能被传递数据的)可重用模板,来代替已经渲染好的元素,
在子组件中,只需要将数据传递到插槽,就想你将prop传递给组件一样,
在父级中,具有特殊属性slot-scope的template的元素必须存在,表明它是作用域插槽的模板。
slot-scope的值被用作一个临时变量,此变量收集从子组件传递过来的props

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<div id = "app">
<child>
<template slot-scope = "props">

<p>hello from parent</p>
<p>{{props.tt}}</p>
</template>


</child>
</div>
<script>
Vue.component("child",{
template:`<div>
<slot tt = "hello from child"></slot>
</div>
`,
});
new Vue({
el:"#app"
})

将子组件的传递到父组件中,如下示例,当子组件循环的时候,某一部分dom结构由外部传递进来,
使用作用域插槽,子组件可以向父组件插槽传递数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<div id = "root">
<child>
<template slot-scope = "props">
<p>{{props.item}}</p>
</template>
</child>
</div>


<script>
Vue.component('child',{
data:function () {
return{
list:[1,2,3,4,5]
}
},
template:`
<div>
<slot v-for='item of list' :item = item></slot>
`
})
var vm = new Vue({
el:"#root"
})

作用域插槽,统一为渲染的模板。为不同的渲染添加值

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
<div id="components-demo">
<my-list title="caokaiqiang" :items="shapes">
<div slot-scope="vv">{{vv.name}}<small>({{vv.sides}}条边)</small></div>
</my-list>

<my-list title="颜色" :items="colors">
<div slot-scope="ad">
<div class="colorbox" :style="{background:ad.hex}">{{ad.name}}</div>
</div>
</my-list>

</div>

<script>

Vue.component('my-list', {
props:["title","items"],
template: `
<div class="my-list">
<h3 class="title">{{title}}</h3>
<div class="list">
<slot v-bind="item" v-for="item in items"></slot>
</div>
</div>
`
})

new Vue({
el: '#components-demo',
data:{
shapes:[{ name:'正方形', sides:4},{ name:'六边形', sides:6},{ name:'三角形', sides:3}],
colors:[{ name: '黄色', hex: '#f4d03f' },{ name: '绿色', hex: '#229954' },{ name: '紫色', hex: '#9b59b6' }]
}
})

两个组件中相同的slot的for循环放到子组件中slot来代替,随后通过slot-scope和绑定:item来从父组件中传递数据到子组件中
vue子组件向父组件中传递值,通过触发事件

1
this.$emit('parent-show');

在组件中绑定事件

1
2
3
4
5
6
<component1 @parent-show = 'show'>
methods:{
show:function() {
console.log("父组件中的方法");
}
}

在vue中,通过ref属性获取DOM元素的值

1
2
<h3 id = "myH3" ref = "myTitle"></h3>
console.log(this.$refs.myTitle.innerText);

vuex使用笔记

state是统一状态的管理,对state的改变只能通过action来改变

1
2
3
4
5
6
7
8
9
var store = {
debug:true,
state:{
message:"hello"
},
setMessage(newValue){
this.state.message = newValue;
}
}

组件不允许直接修改属于store实例的state,而应该执行action来分发(dispatch)事件通知store去改变,我们最终也达成了flux架构,这样约定的好处,我们能够记录所有store中发生的state改变,同时实现能做到记录变更(mutation),保存状态快照,历史回滚等。

应用遇到多个组件共享状态时,需要多个组件依赖同一个状态,或是来自不同视图的行为来修改同一个状态。
vuex是一个专门为vue.js开发的状态管理模式,采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方法发生变化,对vue中多个组件的共享状态进行集中式的管理
全局拥有一个state存放数据,组件修改state中的数据时,必须通过mutation进行,mutation同时提供了订阅者模式提供外部插件调用来获取state数据的更新,当所有的异步操作结束后,常见于action操作后,action通过mutation来修改state的数据,最后state通过渲染再呈现到html上。
dispatch:操作行为触发方法,唯一执行action的方法
action:操作行为处理模块,组件中的$store.dispatch(‘action’,detail)来触发
然后通过commit交给mutation,mutation通过同步操作来修改state中的值。
store.js文件的创建,里面来存储相应的state,mutation,action和getter函数

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
38
39
40
import Vue from 'vue';
import Vuex from 'vuex';
Vue.use(Vuex);

//创建store
const store = new Vuex.Store({
state:{
count:0
},
//mutation来修改store
mutations:{
INCREMENT(state){
state.count = state.count + 1;
},
DECREMENT(state){
state.count = state.count - 1;
}
},
getters:{
//通过读取属性自动调用并返回属性值
evenOrOdd(state){
return state.count % 2 == 0 ? "偶数" : "奇数";
}
},
actions:{
//包含了多个异步操作 包含了多个直接更新state函数的对象
incrementIfOdd({commit,state}){
if(state.count % 2 === 1)
commit('INCREMENT');
},
incrementAsync({commit}){
setInterval(() => {
commit('INCREMENT')
},2000);
}
}

})
//导出
export default store;

习惯于mutation中的函数名称是大写的,而action中是小写的。
随后在main.js中使用创建好的store.js文件

1
2
3
4
5
import store from './store';
new Vue({
render: h => h(App),
store,
}).$mount('#app')

在helloWorld.vue中使用

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
38
39
40
<template>
<div class="hello">
<p>click{{count}} times,count is {{evenOrOdd}}</p>
<button @click="increment">+</button>
<button @click="decrement">-</button>

<button @click="incrementIfOdd">increment if odd-</button>
<button @click="incrementAsync">increment async-</button>
</div>
</template>
<script>
export default {
name:"HelloWorld",
computed:{
count(){
return this.$store.state.count;
},
evenOrOdd(){
//计算型属性来计算值 通过state来获取
return this.$store.getters.evenOrOdd;
}
},
methods:{
//同步加载
increment(){
this.$store.commit('INCREMENT');
},
decrement(){
this.$store.commit("DECREMENT");
},
incrementIfOdd(){
//通过dispatch触发action
this.$store.dispatch('incrementIfOdd');
},
incrementAsync(){
this.$store.dispatch('incrementAsync');
}
}
}
</script>

如果想直接使用mutation,通过this.$store.commit(“INCREMENT”)来直接使用,
如果想通过异步,则通过dispatch触发action,再通过action来触发mutation
this.$store.dispatch(“incrementAsync”);
通过简便的方法来缩写action,mutation,getter和state

1
2
3
4
5
6
7
8
9
10
import { mapActions, mapGetters, mapState, mapMutations } from "vuex";
...
computed: {
...mapState(["count"]),
...mapGetters(["evenOrOdd"])
}
methods: {
...mapActions(["incrementIfOdd", "incrementAsync"]),
...mapMutations(["increment", "decrement"])
}

注意的是mapMutation中的和methods中的方法名称必须保持一致。
getters可以看做在获取数据前对数据进行的进一步加工
action和mutation的区别,action是异步跟新,mutation是同步跟新
同步的意义在于每一个mutation的跟新都对应一个新的状态,可以看到mutation是如何改变的。
mutation传递参数

1
2
3
4
5
this.$store.commit('INCREMENT',2);
随后在mutation中添加
INCREMENT(state,n){
state.count = state.count + n;
},

vue直播课

provide & inject 类似react中的上下文
provide在父组件中注入,在子组件中就可以进行获取
inject:[‘title’] 祖先元素提供的 不需要通过props 来一个个传值
但是provider和inject不是响应式的,如果子孙元素想要通知祖先,就需要hack一下,vue1中有dispatch和boardcast2个方法,但是vue2中被干掉了。我们可以自己模拟一下。
原理就是可以通过this.parent和boradcast获取子元素,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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
dispatch(eventName,data){
let parent = this.$parent;
parent = parent.$parent;
borardcast.call(child,eventName,data);
}
//全局挂载的方法
Vue.prototype.$dispatch = function(eventName,data){
//向上传递 一直不停的获取$parent
let parent = this.$parent;
while(parent){
parent.$emit(eventName,data);
parent = parent.$parent;
}
}
//子元素
Vue.prototype.$boardcast = function(eventName.data){
//通知递归所有子元素
boardcast.call(eventName,data);
}
function boardcast(eventName,data){
this.$children.forEach(child => {
child.$emit(eventName,data);
if(child.$children.length){
boardcast.call(child,eventName,data);
}
})
}
this.$on("boardcast",msg => {
console.log();//通过监听
})
eventBus全局实现
class Bus{
constructor(){
this.callBacks ={

}
//监听 触发
$on(name,fn){
this.callBacks[name] = this.callBacks[name] || [];
this.callBacks[name].push(fn);
}
$emit(name,args){
if(this.callbacks[name]){
this.callbacks[name].forEach(cb => cb(args));
}
}
}
}
Vue.prototype.$bus = new Vue();

$bus触发所有的事件
自定义input监听on和input事件即可

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<input :type = "type" :value = "value" @input = "onInput">
methods:{
onInput(e){
this.$emit("input",e.target.value);
this.$parent.$emit("validate");
}
}
v-model的语法糖
k-form-item 负责显示label 执行校验,和显示校验结果 插槽作组件扩展
form进行全局校验
能够获取全部的规则
inject:["form"];
models:{"username":"","password":""},
rules:{
username:[
{required:true,message:"请输入用户名"}
]
};
schema来做校验
import Schema from 'async-validator'
每个item都有validate方法
单元测试:站在外层来进行测试,期望获取的结果是想要的

vue router在实现前端应用时,使用hash模式和history模式
默认hash模式:使用URL的hash来模拟一个完整的URL,于是当URL改变时,页面不会重新加载。
hash(#)是URL中的锚点,代表的是网页中的位置,单改变#后面的值,不会重新加载网页,只会滚动到相应的位置。
hash出现在URL中,但不会出现在http中,不会对后端请求发生影响。
同时改变hash,会在浏览器访问历史中增加一个记录,使用后退按钮,就会回到上一个位置。
history模式:url像正常的url,例如http://www.baidu.com/user/id;
不过这种模式要弄好,还需要后台配置支持。因为我们的应用是SPA,如果后台没有正确的配置,用户访问时就会出现404,
要在服务端增加一个覆盖所有情况的候选资源,如果URL匹配不到任何静态资源,则应该返回同一个index.html的页面。

属性,事件和插槽3个vue基础概念。
属性:自定义属性props,原生属性attrs,特殊属性class,style。
props:称为静态数据,vue是单向数据流,数据传递时不能改变数据类型,而且不允许子组件中直接操作。
.sync实现双向绑定

1
2
3
4
5
6
7
8
9
10
11
12
<demo :show.sync = "show" :msg.sync = "msg" :arr = "arr>
props: {
msg: {
type: String
},
show: {
type: Boolean
},
arr: {
type: Array //在子组件中改变传递过来数组将会影响到父组件的状态
}
},

通过props从父组件传递到子组件中
vue中是由数据驱动的,是指视图是由数据驱动生成的。
对视图的修改,不是直接操作DOM,而是修改对应数据。
用户执行某个操作 -> 反馈到VM处理(可以导致model变动) -> VM层改变,通过绑定关系直接更新页面对应位置的数据。
.lazy事件,以往通常是input中一旦键入键盘就触发change事件,现在可以转变为当输入完所有内容后,光标离开才跟新视图的场景。
render和template都定义,执行render
Vue.use函数 插件和事情
plugin.install 是方法.
plugin.install.apply(plugin,args);
plugin都会执行
vuex刷新就没了 localStorage还存储在数据中
强类型 typescript
vuex源码!!!typescript和docker

1
2
3
4
5
6
7
8
9
10
11
12
13
<script lang = "ts">
export default Vue.extend({

})
</script>
import Hello form "./components/Hello.vue
@Component({
components:{
HelloWorld,Hello
}
})

export default class App extends Vue{};

1.vue-cli
2.数据mock,跨域,假数据
3.工作流 githook eslint
4.webpack 模块化原理
5.vuex源码
6.router 看了源码
7.jwt中的具体操作
登录 网络拦截器 token 路由权限 addRoutes
token是一段加密字符串 加密函数(用户id + 随机数 + 过期时间)
解密token token放在header之上 token 1.注销登录 2.过期了 对称加密

npm run build dist包
线上机器有一个nginx目录
1.前端有一个部署机jekins 跑build copy代码,上线
2.push之后,jekins点按钮,打包ssh到机器上 解压
3.push之后,github或者gitlab的webhook 重新发布docker.
devops自动运维。
SSR服务端渲染,后端把vue或者react解析成DOM标签,首屏就能直接渲染dom.
nuxt就是SSR的最佳实践框架。
cloc ./ 看代码有几行
nginx和proxy区别,本地使用webpack-dev-serve的proxy做转发
线上没有webpack,有nginx,由nginx做转发。
vuex存储的变量什么时候销毁
缓存策略 LRU last recent use
队列:谁用得多留下来 谁用得少慢慢销毁
权限 网络拦截 性能优化 热重载 扩展 原理

编译 模板 -> render函数 runtime
源码顺序
package.json
main 和 module
版本 不同方式引入
core -> instance -> init.js
initState,$mount 虚拟dom _render,_update,
整个的入口
web/entry-runtime-with-compiler.js
compiler 将template 编译成render函数 返回虚拟dom createElement
如果没有compile模块 文件变小,但只支持render
core 核心
platforms 平台 web weex
server 服务端渲染相关
sfc .vue文件解析 单页面解析 script style template
shared 公用的方法和常量
new Vue({
template:


})
编译成
render:h => {
return h(‘div’,{attrs:{id:app}},this.name);
}
每一个依赖放到watcher里面
watcher放到dep里面 dep放到defineReactive里面去收集
observer观察dep
解析dom内容 k-model事件
this.$compile = new Compile()
vue vuex vue-router全家桶代码
node 最佳实践 eggjs 1.1mvc分层 约定大于配置 nginx+docker部署
mixin 是自己的 extend给儿子了 是继承
react推荐用umi 脚手架
auth2第三方登录 微信 微博登录
虚拟dom就是object对象123 createElement({div,id:app,123}),大的object对象,模拟树形结构
{
type:div,
props:{id:div},
children[
{type:组件}
]
}
ast抽象语法树 super-tiny-compiler 前端编译
codegen
vue的生命周期函数
在newVue后 首先初始化事件event和生命周期lifecycle等
实际就是往上面挂载一些函数
这里到达的是beforeCreate
随后是初始化provide和inject中的一些实例
这里data和props都已经加载完毕 可以调用
随后将el元素挂载上去,如果有模板编译的话,首先执行模板编译生成render函数 这里是挂在前beforeMount
随后根据render函数产生虚拟dom,真正的渲染到dom上,触发mouted,在update的时候,根据不同情况产生不同的虚拟dom进行对比,利用patch算法进行对比和渲染,到真正的dom上。在销毁的时候触发beforeDestroy方法。将监听组件等全部取出,随后触发destroy方法
生命周期链接
生命周期最好的回答
性能优化
文件更快加载 文件执行次数更少
很多dom都是可以重用的 整个dom的元素就这么多
整个3屏 整个的dom元素是不会增加的,上面去除的拿到下面来添加上 上面的屏幕都放到下面来 骨架屏
SSR 服务端渲染

笔试笔记

发表于 2019-07-16 | 分类于 js相关 , css相关 , html相关

1.实现如下布局

注意header,footer,content的划分和命名规范,flex布局,和当容器设置为父容器的百分号时,注意设置body和html的 body html{margin:0;height:100%}
代码如下

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
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
body{
height: 100%;
display: flex;
flex-direction: column;
}
html {

margin:0 auto;

padding:0;

height: 100%;

}
.header{

border: solid 1px green;
height:100px;
display: flex;
justify-content: space-between;
}
.leftLogo{
margin: 10px 0px 10px 10px;
width: 80px;
border: solid 1px red;


}
.rightUserName{
border: solid 1px black;
text-align: right;
width: 100px;
margin: 60px 10px 0px 0px;
height: 20px;
}

.content{
margin-top: 10px;
display: flex;
flex-grow: 1;

}
.leftContent{
flex-grow:1 ;
border: solid 1px red;
margin-right: 10px;
}


.aside{
width:200px;
height: 20px;
border: solid 1px red;
text-align: left;
}
.footer{
margin-top: 10px;
border:solid 1px black;
text-align: center;
height: 20px;
}
.triangle-down{
width:0;
height: 0;
border-left: 5px solid transparent;
border-right: 5px solid transparent;
border-bottom: 5px solid black;
}
</style>
</head>
<body>
<div class="triangle-down"></div>
</body>
</html>

参考网站
html body设置宽高
flex布局
2.实现如下函数:
uniqueryfy([1,0,0]) 返回[1,0]
uniquerfy([{id:1,name:1},{id:1,name:2}],a => a.id)返回[{id:1,name:1}]
后面是过滤的规则 或者为 a => a.sex + a.name
方法:使用set的方法来做

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
function uniquery(arr,rules) {
if(rules == null){ //判断rule为空的情况下
var set = new Set();
arr.forEach(function (item,index,arr) {
if(!set.has(item))
set.add(item);
})
return Array.from(set);//伪数组的转变 将set转化为数组
}else{
//保存key 新的数组来保存所有的key和value
var set = new Set();
var newArr = [];
arr.forEach(function (item,index,arr) {
var key = rules(item);
if(!set.has(key)){
set.add(key);
newArr.push(item);
}

})
return newArr;
}
}

3.

三角形的绘制可以通过border来 transparent设置两边为透明即可了。
三角形绘制参考网站
代码如下:

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
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
<style>
.total{
width:100px;
}
.top{
background: black;
color: white;
width: 100px;
display: flex;

}
.trangle-down{
width: 0;
height: 0;
border-top: 5px solid white;
border-left: 5px solid transparent;
border-right: 5px solid transparent;
margin-top: 10px;
}
.content-top{
background: white;
color: red;
display: flex;
width: 100px;
}
.trangle-up{
width: 0;
height: 0;
border-bottom: 5px solid red;
border-left: 5px solid transparent;
border-right: 5px solid transparent;
margin-top: 10px;
}
.content{
display: none;
}
</style>

<body>
<div class="total" onmouseleave="closeMenu()">
<div class="top" onmouseenter="opemMenu()">
客户服务
<div class="trangle-down"></div>
</div>
<div class="content">
<div class="content-top">
客户服务
<div class="trangle-up"></div>
</div>

<div>联系客户</div>
<div>帮助中心</div>
<div>联系客户</div>
<div>联系客户</div>

</div>
</div>

<script>
function opemMenu() {
(document.getElementsByClassName("content")[0]).style.display = "block";
}
function closeMenu() {
(document.getElementsByClassName("content")[0]).style.display = "none";
}
</script>
</body>
</html>

4.实现如下函数,今天是小明生日,他希望知道余下还剩下多少时间,

要求:
1.使用原生js
2.时间格式 时:分:秒
3.自动补全2位,06:06:06
4.过了凌晨12点,时钟自动停止
代码如下:

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
<body>
<span id = "clock"></span>
<script>
function PrefixInteger(num, n) {
return (Array(n).join(0) + num).slice(-n);
}

var interval = setInterval(function () {
var curDate = new Date(); //获取当前时间
var nextDate = new Date(curDate.getTime() + 24 * 60 * 60 * 1000); //获取下一天
var next = new Date(nextDate.getFullYear(),nextDate.getMonth(),nextDate.getDate());//获取下一天的0时刻
var time = next - curDate; //求得时间差
var hours =(parseInt((time %(1000 * 60 * 60 * 24)) / (1000 * 60 * 60)));
var minutes = parseInt((time % (1000 * 60 * 60)) / (1000 * 60));
var seconds = parseInt((time % (1000 * 60)) / 1000);
if(hours == 0 && minutes == 0 && seconds == 0) //如果都为0了 说明到头了 就清除
clearInterval(interval);
var str = "";
str += PrefixInteger(hours, 2) + ":"; //补全
str += PrefixInteger(minutes, 2) + ":";
str += PrefixInteger(seconds, 2);

document.getElementById("clock").innerText = str;
},1000);
</script>
</body>

5.实现如下页面布局
已知header,footer高度为48px,宽度为100%,aside宽度均为320px,实现该布局

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
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>

html {

margin:0;

padding:0;

height: 100%;

}
body{
height: 100%;
display: flex;
flex-direction: column;
}
.header{
background-color: blue;

display: flex;
justify-content: center;
align-items: center;
height: 48px;
flex-grow: 0;
}
.footer{
background-color: blue;

display: flex;
justify-content: center;
align-items: center;
height: 48px;
flex-grow: 0;
}
.main{

display: flex;
flex-grow: 1;
}
.aside{
display: flex;
justify-content: center;
align-items: center;
background-color: blue;
flex-grow: 0;
width: 320px;
}
.content{
flex-grow: 1;
display: flex;
justify-content: center;
align-items: center;
background-color: rebeccapurple;
}
</style>
</head>
<body>
<div class="header">
header
</div>
<div class="main">
<div class="aside">
aside
</div>
<div class="content">
content
</div>
<div class="aside">
aside
</div>
</div>
<div class="footer">
footer
</div>
<script>

</script>
</body>
</html>

6.将函数fn的执行上下文改为obj,返回fn执行后的结果

1
2
3
4
5
6
7
8
9
function HelloWorld(fn,obj) {
return fn.call(obj);
}
HelloWorld(
function() {
return this.firstname + '' + this.lastname + '|';
},
{firstname:"hello",lastname:"world"}
)

7.实现如下布局

关键是三角形冒泡的实现

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
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
.tag{ width:500px; position:relative;border-radius: 5px}
.tag em{display:block; border-width:20px; position:absolute; bottom:150px; left:500px;border-style:solid ; border-color: transparent transparent transparent white;font-size:0; line-height:0;}

</style>
</head>
<body style="background-color: #666666">
<div style="display: flex">
<div class="tag" style="width: 500px;background-color: white"><h1>《倩女幽魂2.0》来看看我的<br>最新梦岛动态!</h1>
<em></em>
<div style="display: flex">
<p style="font-size: 25px;color: #999999">上大神,发梦岛,不进游戏也能<br>撩!</p>
<img src="https://nos.netease.com/hi-163-qn/upload/201909/04/ff2e1e80cef611e9a213af01a189a04b.png">
</div>
</div>
<img style="width: 150px;height: 150px;margin-left: 30px" src="https://nos.netease.com/hi-163-qn/upload/201909/04/ff2e1e80cef611e9a213af01a189a04b.png">
</div>
<script>

</script>
</body>
</html>

8.实现如下函数

浏览器缓存机制

发表于 2019-07-10 | 分类于 js相关 , 浏览器相关

缓存可以说是性能优化中简单高效的一种优化方式了,一个优秀的缓存策略可以缩短网页请求资源的距离,减少延迟,
并且由于缓存文件可以重复利用,还可以减少带宽,降低网络负荷。
数据请求的步骤:发起网络请求,后端处理,浏览器响应。
浏览器缓存在第一步网络请求和浏览器响应2个环节中做性能优化。
缓存位置:
service worker:运行在浏览器背后的独立线程,一般可以用来实现缓存功能,
。使用 Service Worker的话,传输协议必须为 HTTPS。因为 Service Worker 中涉及到请求拦截,所以必须使用 HTTPS 协议来保障安全。service workder的缓存与浏览器其余内建缓存不同,它可以让我们
控制缓存哪些文件,如何匹配缓存,如何读取缓存,并且缓存是持续性的
2.memory cache
memory cache也是内存中的缓存,主要包含的是当前页面中已经抓取到的资源,例如页面上已经下载好的样式,脚本等,
读取内存中的数据肯定比磁盘来得快,内存读取高效,可是缓存持续性很低,会随着进程的释放而释放,
一旦关闭tab页面,内存中的缓存也就被释放了.
内存缓存在缓存资源时并不关心返回的资源的http缓存头cache-control是什么,同时资源的匹配也并非仅仅是对URL做匹配,还可能会对Content-Type,CORS等其他特征做校验。
3.disk cache 顾名思义也就是硬盘中的缓存,读取速度较低,但是什么都可以存储到磁盘中,,比之 Memory Cache 胜在容量和存储时效性上。
对于大文件来说,大概率是不会存储在内存中的,反之优先, 当前系统内存使用率高的话,文件优先存储进硬盘中.
4.push cache是http/2中的内容,当以上3种缓存都没有命中的时候,才会被使用,只在会话session中使用,一旦会话session结束,也就被释放,并且缓存时间很短。
出于对性能的考虑,有的浏览器会对相同域名但不同的tab标签使用同一个http连接。
大部分的接口都应该选择好缓存策略,通常浏览器缓存策略分为2种,
强缓存和协商缓存,
并且缓存策略都是通过设置
http header来实现的。
浏览器与服务器通信为应答模式,浏览器发出http请求,服务器响应后拿到数据,
浏览器如何确定一个资源该不该被缓存,如何去缓存呢。
浏览器第一次向服务器发起请求后拿到请求结果后,
将请求结果和缓存标识存入浏览器缓存中, 浏览器每次发出请求,都会现在浏览器缓存中查找请求的结果以及缓存标识,浏览器每次拿到返回的请求结果都会将该结果和缓存标识存入浏览 器缓存中
确保了每个请求的缓存存入与读取,
是否需要向服务器重新发起http请求将缓存分为2个部分,分别是
强缓存和协商缓存
强缓存:不会向服务器发送请求,直接从缓存中读取资源,强缓存通过设置2种http header来实现,
expires 和 cache-control.
expires:
用来指定资源到期的时间,是服务器端的具体的时间点,
expires = max-age + 请求时间,。需要和last-modified结合使用,
是web服务器响应消息头字段,在响应http请求时告诉浏览器在过期时间前浏览器都可以直接从浏览器缓存中读取数据,而无需再次请求。
cache-control主要用来控制网页缓存,cache-control:max-age=300,则代表在这个请求正确返回时间,5分钟内再次加载该网页,就会命中强缓存,cache-control可以在请求头或者响应头中设置。
expires是http1.0的产物,cache-control是http1.1的产物,同时存在,
cache-control优先级高于expires.
expires是一个过期的产物,现阶段它的存在只是一种兼容性的写法。
强缓存判断是否缓存的依据是是否超出某个时间或者某个时间段,
而不用去关心服务器端的数据是否跟新了.
可能导致加载文件不是服务器端最新的文件,那我们如何得知
服务器端内容是否已经发生了更新呢这时候就要用到协商缓存。
5.协商缓存。
协商缓存是强缓存失效后,浏览器携带着
缓存标识向服务器发起请求,由服务器根据缓存标识决定是否使用缓存的过程,,
主要有以下情况,
协商缓存生效,返回304和not modified 协商缓存失效,返回200和请求结果
协商缓存可以通过设置http header来实现,last-modified和if-modified-since.
浏览器在第一次访问资源时,服务器返回资源的同时,在response header中添加last-modifed的header,值是这个资源在服务器上的最后修改时间,浏览器接收后缓存文件和header;
last-modifed是文件在服务器上的最后修改时间。
浏览器下一次请求资源时,浏览器首先检测有last-modified这个header,于是添加if-modified-since这个header,值就是last-modified中的值,服务器收到资源后,会根据if-modified-since中的值和服务器中的最后修改时间作比较,如果没有变化,就返回304和空的响应体,直接读取缓存,如果If-Modified-Since的时间小于浏览器的最后修改时间,说明文件有更新,于是返回新的资源文件和200.
如果本地打开了缓存文件,即时没有修改文件,也会造成last-modified被修改,服务器不能命中缓存导致发送相同的资源。
既然根据文件修改时间来决定是否缓存尚有不足,能否根据文件内容是否修改来决定缓存策略?所以在 HTTP / 1.1 出现了ETag和If-None-Match.
ETag是服务器响应请求时,返回当前资源文件的一个唯一标示,(由服务器生成),只要资源有变化,ETag就会重新生成,浏览器在下一次加载资源并向服务器端发送请求时,,会将上一次返回的Etag值放到request header里的If-None-Match里,服务器只需要比较客户端传过来的if-none-match和自己服务器上的etag标签是否一致即可。如果服务器发现ETag匹配不上,那么直接以常规GET 200回包形式将新的资源(当然也包括了新的ETag)发给客户端;如果ETag是一致的,则直接返回304知会客户端直接使用本地缓存即可。
etag优于last-modified
强缓存优于协商缓存进行。,若强制缓存(Expires和Cache-Control)生效则直接使用缓存,若不生效则进行协商缓存(Last-Modified / If-Modified-Since和Etag / If-None-Match),
协商缓存有服务器决定是否使用缓存**,若协商缓存失效,那么代表该请求的缓存失效,返回200,重新返回资源和缓存标识,再存入浏览器缓存中;生效则返回304,继续使用缓存。
用户行为对浏览器缓存的影响:指的是用户在浏览器操作时,会触发怎样的缓存策略。
打开网页:直接输入地址,查找disk cache中是否有匹配。。如有则使用;如没有则发送网络请求。
普通刷新(f5),因为tab并没有关闭,因此memory cache是可用的,会被优先使用,其次才是disk cache.
强制刷新(ctrl + f5),浏览器不使用缓存,存,因此发送的请求头是:cache-control:no-cache(为了兼容,还带了 Pragma: no-cache),服务器直接返回 200 和最新内容。

深入浅出浏览器渲染定理与模块化概念,类型转换等

发表于 2019-07-05 | 分类于 浏览器相关

浏览器的内核是指支持浏览器运行的最核心的程序,分为2个部分,一是渲染引擎,另一个是js引擎,
渲染引擎在不同的浏览器中也是不同的,目前市面上常见的浏览器内核有Trident(IE),Gecko(火狐,
Blink(Chrome),Webkit(Safari),
webkit是当下浏览器世界真正的霸主
页面加载过程:
浏览器根据dns服务器得到域名的ip地址
向这个ip的机器发送http请求
服务器收到,处理并返回http请求
浏览器得到返回内容

一堆HTML格式的字符串,因为只有HTML格式浏览器才能正确解析,
HTML树 -> DOM树形结构
CSS -> CSS规则树
js脚本,等到js脚本文件加载后,通过dom api和cssom api来操作dom树和css规则树
解析完成后,浏览器引擎会通过DOM Tree 和 CSS Rule Tree 来构造render tree,渲染树。
渲染树会包括需要显示的节点和这些节点的样式信息。
css的规则树主要为了完成匹配吧css规则添加到渲染树上的每个节点
最后,计算每个frame的位置,这又叫layout和reflow过程。
字节数据 => 字符串 => token => node => dom
在网络中传输的内容其实都是 0 和 1 这些字节数据。当浏览器接收到这些字节数据以后,它会将这些字节数据转换为字符串,也就是我们写的代码。
将字符串转化为token,例如,等。Token中会标识出当前Token是“开始标签”或是“结束标签”亦或是“文本”等信息。
渲染树只会包括需要显示的节点和这些节点的样式信息
渲染过程中,如果遇到script就停止渲染,执行js代码,因为浏览器有GUI渲染线程和JS引擎线程。为了防止渲染出现不同的结果,这两个线程是互斥的关系,JavaScript的加载、解析与执行会阻塞DOM的构建,也就是说,在构建DOM时,HTML解析器若遇到了JavaScript,那么它会暂停构建DOM,将控制权移交给JavaScript引擎,等JavaScript引擎运行完毕,浏览器再从中断的地方恢复DOM构建。
首屏渲染的越快的话,就越不应该在首屏就加载js文件,这也是将js放在body底部的原因。
js不仅阻塞dom的构建,也会导致cssom和dom的构建。
因为js不仅可以修改DOM,也可以修改样式。
因为js需要修改cssom.所以浏览器将延迟脚本执行和dom构建,直至完成cssom的下载和构建,
在这种情况下,浏览器会先下载和构建CSSOM,然后再执行JavaScript,最后在继续构建DOM
根据渲染树进行布局,也可以叫做回流,
输出一个精准的盒模型,每个元素在视口内的准确位置。
重绘:当我们对dom的修改导致了样式的变化,却并未影响到几何属性,浏览器不需重新计算元素的几何属性、直接为该元素绘制新的样式
回流:当我们对dom的修改引发了dom几何尺寸的变化,浏览器会重新计算,这个过程就是回流。
回流一定会引发重绘,但重绘不一定引发回流.
减少重绘或者回流:
使用visibility替换display:none.因为前者会引发重绘。
不要使用table布局。
动画速度越快,回流次数越多
defer 使脚本在文档解析完成后执行。不会影响html的解析。
async:用于异步下载文件,下载完后立即解释执行。不会阻塞html的执行

模块化概念

将一个复杂的程序依据一定的规则封装成几个块(文件),并进行组合在一起
块的内部数据与实现是私有的,只是向外部暴露一些接口(方法),与外部其他模块通信。
模块化的好处
避免命名冲突(减少命名空间污染)
更好的分离,按需加载
更高复用性
高可维护性
引入多个script后出现的问题
请求过多,会发送多个请求。依赖模糊,难以维护
可能出现牵一发而动全身的情况。
模块化规范:commonjs,AMD,ES6,CMD规范
commonjs node应用由模块组成,采用commonjs模块规范,
每个文件就是一个模块,有自己的作用域。在一个文件里面定义的变量、函数、类,都是私有的,对其他文件不可见。在服务器端,模块的加载是运行时同步加载的;在浏览器端,模块需要提前编译打包处理。
暴露模块 module代表当前模块

1
2
module.exports = value;
exports.xxx = value;

引入模块

1
require(xxx);

commonjs规范加载模块是同步的,也就是说,只有加载完成,才能执行后面的操作
amd规范则是非同步的,允许指定回调函数,由于node js主要用于服务端编程,,模块文件一般都已经存在于本地硬盘,所以加载起来比较快,不用考虑非同步加载的方式,所以CommonJS规范比较适用。但是,
浏览器环境,要从服务器端加载模块,这时必须采用非同步模式,这时AMD就比较实适用。

1
2
3
define['modlue1','module2'],function(m1,m2){
return 模块;
};

引入使用模块

1
2
3
require('module1','module2',function(m1,m1){

});

requurejs是一个工具库,,主要用于客户端的模块管理。它的模块管理遵守AMD规范,
基本思想:通过define,将代码定义为模块,通过require,实现代码的模块加载。
CMD规范专门用于浏览器端,模块的加载是异步的,模块使用时才会加载执行。
CMD整合了commonjs和amd规范的特点,在sea.js中,
通过define配置文件,通过requre导入文件。
AMD和CMD都适用于浏览器端,AMD同步,CMD异步。
ES6的模块化语法
export{basicNum,add};
import{add} from ‘./main’;
commonjs提出的是一个值的拷贝,而es6是值的引用。
commonjs是模块运行时加载,es6模块是**编译时输出的接口。

类型转换

js是一门动态类型语言,所谓的动态类型可以确定是在语言中一切内容是不确定的
如果运算符发现,运算子的类型与预期不符合,就会自动进行转换。
自动转换时基于强制转换的,
强制转换主要指使用Number,String,Boolean.3个函数
其他数据类型转换为string
toString()方法
null和undefined这2个值没有toString方法,如果调用,会报错
采用number类型的toString()方法的基模式,可以用不同的基输出数字,
例如二进制基为2,八进制为8

1
2
var num = 10;
alert(num.toString(2)); //输出1010

方式二 采用string函数
string函数作强制转换,

1
2
3
var a = null;
String(a);//为字符串"null"
String({a:1});//转化为[object Object]

转为数字
如果字符串中有非数字的内容,则转为NaN,

1
2
3
4
Number("324");//324
Number("324anc");//NaN
Number(undefined);//转为NaN
Number({a:1}) //转化为NaN

parseInt()把一个字符串转为整数,有效体转为整数

1
parseInt(10.43a") //为10

parseFloat()把一个字符串转为浮点数。
空字符串,null,undefined,+0,-0,和NaN转为布尔型为false.

作用域

作用域是一个独立的地盘,让变量不会外泄,暴露出去,作用域最大的好处是隔离变量,不同作用域下的同名变量不会冲突。
es6之间只有全局作用域和函数作用域。
es6提供了块级作用域。
let和const的声明并不会提升到当前代码块的顶部,因此需要手动提升。
let不能重复声明

1
2
3
4
5
6
var count = 30;
function outFun2() {
let count = 20;
console.log(count);

}

以上这种情况 在嵌套的作用域内使用let声明一个同名的新变量,
并不会抛出错误。

1
2
var cnt = 30;
let cnt = 40;

作用域链,更确切的说是在创建这个函数的时候的作用域,而不是调用时候的
以上这种情况便会报错。
js的执行分为解释阶段和执行阶段
解释阶段:词法分析,语法分析,作用域规则确定
执行阶段:创建执行上下文,执行函数代码,垃圾回收
执行上下文最明显的就是this的指向是在执行时候确定的。

js事件循环机制

js是单线程任务,所有任务都需要排队,前一个任务结束,后一个任务才会接上,js中有2种任务,一种是同步任务,一种是异步任务,
异步任务指的是,不进入主线程,而进入消息队列的任务,只有任务队列通知主线程,某个异步任务可以执行了,该任务才会进入主线程,异步任务又包括宏任务和微任务,
在所有同步任务执行完之前,异步任务是不会执行的.
event loop,只要主线程空了,就会去读取”任务队列”内的东西。
放入异步任务的代码:setTimeout,DOM事件,promise,ajax请求。
setTimeout和setInterval是过几秒后被放入异步队列
异步任务分为宏任务和微任务,宏任务队列可以有多个,而微任务队列只有一个
宏任务包括:script全局任务,setTimeout,setInterval, setImmediate, I/O, UI rendering。
微任务包括:new Promise().then,
由于执行代码入口都是全局任务scrpit,而全局任务是属于宏任务,所以当栈为空的时候,首先执行微任务队列里的任务,再去执行宏任务队列中最前面的任务。执行宏任务过程中,遇到微任务,再依次加入微任务队列。
栈空后,再次读取微任务队列里的任务,以此类推。
当某个宏任务中代码全部执行完毕后,会查看是否有微任务队列,如果有,先执行微任务队列中的任务,如果没有,就查看是否有其他宏任务队列。

浅拷贝和深拷贝

浅拷贝只复制指向某个对象的指针,而不复制对象本身,新旧对象还是共享同一块内存,
但是深拷贝会另外创建一个一模一样的对象,新对象和原对象不共享内存,修改新对象不影响原对象。
赋值赋的是栈中的地址,而不是堆中的地址。
浅拷贝的实现方式object.assign()
var initObj = Object.assign({},obj);
initObj.a.a = “wade”;
console.log(obj.a.a);//打印出来wade
深拷贝实现方式
json.parse(json.stringfy())
函数库loadash
该函数库有提供_.cloneDeep来做深拷贝

函数柯里化

函数柯里化
只传递函数一部分参数来调用他,让他返回一个函数去处理剩余的参数

1
2
3
4
5
6
7
8
9
10
11
12
普通add函数
function add(x,y){
return x + y;
};
//柯里化后
function curryAdd(x){
return function(y){
return x + y;
}
}
add(1,2);
curryAdd(1)(2);

柯里化作用 可以起到参数服用 复用的结果
可以将一个reg返回后,返回一个带有一个正则表达式校验的函数,
在剩余函数中调用。

视口

代表当前可见的计算机图形区域,在web浏览器中,通常与浏览器窗口相同,但不包括浏览器的UI,菜单栏等。
布局视口:布局视口是网页布局的基准窗口,在 PC浏览器上,布局视口就等于当前浏览器窗口大小(不包括 borders 、 margins、滚动条)。,移动端默认为980px
document.documentElement.clientWidth/clientHeight来获取
视觉视口:用户通过屏幕真实看到的区域:
相当于浏览器的窗口大小,当用户对浏览器进行缩放时,不会改变布局视口的大小,所以页面布局是不变的,但是缩放会改变视觉视口的大小
window.innerWidth和innerHeight来获取
理想视口:网站页面在移动端显示的理想大小。
当页面缩放比例为 100%时, CSS像素=设备独立像素, 理想视口=视觉视口。
screen.width /height

window.innerHeight 获取浏览器视觉视口高度
window.screen 屏幕理想视口宽度,设备的分辨率,设备像素比
document.clientHeight 布局视口高度
offsetHeight 获取包括内边距,滚动条,边框和外边距
scrollHeight在不使用滚动条的情况下适合视口中的所有内容所需的最小宽度。测量方式与 clientHeight相同:它包含元素的内边距,但不包括边框,外边距或垂直滚动条。
移动端适配 @media移动端查询 flexible方案,统一使用rem来布局,
vh,vw方案将视觉视口window.innerWidth和height等分为100份
(连接)[https://mp.weixin.qq.com/s/oF6oAjdzguv9OwE9cdLrPQ]

闭包

闭包是js的一个难点,
作用:可以访问函数内部的变量,使变量的值长期保存在内存中
形成条件:函数嵌套,内部函数引用外部函数的局部变量
能够读取其他函数内部变量的函数
只有函数内部的子函数才能读取内部变量,因此可以把闭包理解为”定义在一个函数内部的函数”,
闭包的特点记住诞生的环境,比如f2记住了它诞生的环境f1,所以从f2可以得到f1的内部变量. 闭包将内部函数和外部函数连接起来的一座桥梁**
内存泄漏指的是任何对象在您不需要拥有或者使用的时候它仍然存在,闭包不能滥用,否则导致内存泄漏,影响网页的性能。闭包使用完了后,要立即释放资源,将引用变量指向null.
闭包作用:读取函数内部的变量,可以使变量的值长期保存在内存中,生命周期比较长。
用来实现js模块,js模块:具有特定功能的js文件,将所有数据和功能都封装在一个函数内部,只向外暴露一个具有n个方法的对象或者函数,只需要通过暴露模块的对象调用来实现对应的功能即可。
forEach,map,filter,find,every,some,reduce它们都有共同的特点,不会改变原来数组。
线程与进程的区别

node中的事件循环

一个进程只有一个主线程
进程是cpu资源分配的最小单位,线程是cpu调度的最小单位,
一个进程可以由一个线程或多个线程组成,线程是一个进程中代码的不同执行路径
进程的内存空间是共享的,每个线程都可以共享这些内存
浏览器内核是多线程的,在内核控制下各个线程互相配合以保持同步,
GUI渲染线程,js引擎线程,定时触发线程,事件触发线程,异步http请求线程。
node中的event loop
node中的event loop和浏览器中的完全是不相同的东西,node js采用v8作为js的解析引擎,而I/O处理方面采用了自己设计的libuv.
libuv是一个基于事件驱动的跨平台抽象层,封装了不同操作系统的底层特性,对外提供统一的api,事件循环机制也是这里面实现的。
node js运行机制如下:
v8引擎解析js脚本。
解析后的代码,调用node api.
libuv库负责node api的执行,将不同的任务分给不同的线程执行,形成一个event loop,以异步的方式将任务的执行结果返回v8引擎.
v8引擎将结果返回给用户

libuv执行node api分为以下几个阶段
事件循环分为6个阶段,会按照顺序反复执行,每当进入一个阶段时,都会从对应的回调队列中取出函数去执行,当队列为空或者执行的回调函数达到系统设定时,将会进入下一个阶段。
外部输入数据 -> 轮询阶段(poll) -> 检查阶段(check) -> 关闭事件回调阶段(close callback) -> 定时器检测阶段(timer) -> I/O事件回调阶段(I/O callbacks) -> 闲置阶段(idle,prepare)
timers阶段(这个阶段执行timer(setTimeout,setInterval))的回调
i/o callback阶段,处理一些上一轮循环中少数的未执行的i/o回调
idle 仅node内部使用
poll阶段 获取新的i/o事件。
check阶段 执行setimmediate的回调
close callback 执行socket的close事件回调

poll阶段
1.回到timer阶段执行回调
2.执行i/o回调
并且在进入该阶段如果没有设定timer的话,会发生如下事件
如果poll队列不为空,会遍历回调队列并且同步执行,直到队列为空或者达到系统上线
如果poll队列为空,如果有setimmediate回调需要执行,poll阶段停止并且进入到 check 阶段执行回调
如果没有setimmediate,会等待回调被加入到队列中并立即执行。
check阶段 setimmediate的回调会被加入到check中
node中事件也有宏任务(macro)和微任务(micro)
macro:setTimeout,setInterval,setImmediate,script代码
micro:process.nextTick,new Promise().then(回调)
process.nextTick,独立于event loop外,有自己的一个队列,
当每个阶段完成后,如果存在nextTick队列,会清空队列中的所有回调函数,并且优于其余的微任务执行。
浏览器环境中,microtask的任务队列是每个macrotask执行完后再执行
而在node js中,microtask会在事件循环的各个阶段之间执行,也就是一个阶段执行完毕,就会去执行microtask中的任务。

js中的垃圾回收和内存泄漏

内存泄漏指的是:不再用到的内存,没有来级的释放。js具有自动回收垃圾机制
js的垃圾回收机制:找出不再使用的变量,然后释放掉其内存即可。垃圾回收期会按照固定的时间间隔周期性的回收
垃圾回收有2种方法:标记清除和引用计数
标记清除:当变量进入执行环境时,就标记这个变量进行环境,逻辑上讲,永远不要释放进入环境的变量所占用的内存,因为只要执行刘进入相应的环境,就可能会用到他们,当变量离开环境的时候,就将其标记为离开环境。
引用计数:是指语言引擎有一张‘引用表’,保存了内存里面的所有资源(通常是各种值)的引用计数。
如果一个值的引用计数为0,就表示该值不会再用到,因此可以将该值释放。
如果一个值不再需要了,引用计数却不为0,垃圾回收机制将无法识别这块内存。从而导致内存泄漏。
哪些情况会造成内存泄漏:
会让变量一直处于进入环境的状态,而无法被回收。

1
2
3
function foo(arg){
bar = "this";
}

创造了一个全局变量,在页面关闭之前是不会释放的。
被遗忘的计时器或者回调函数 闭包可以维持内部函数的局部变量,使其得不到释放。

web前端入门和进阶js笔记-node js笔记

发表于 2019-06-29 | 分类于 js相关 , node相关

异步编程
node 采用google v8引擎来处理js脚本,js最大特点就是单线程运行,一次只能运行一个任务
node 大量采用异步操作,即任务不是马上执行,而是插在任务队列的尾部,等到前面的任务执行完再去执行.
提高代码的响应能力。
异步IO也叫非阻塞IO,例如读文件,传统的语言,基本都是读取完毕才能进行下一步操作。非阻塞就是Node的callback,不会影响下一步操作,等到文件读取完毕,回调函数自动被执行,而不是在等待。
所以只有把错误交给回调函数来处理。

1
2
3
4
5
foo("找小黑",function(error,data){
if(error)
throw error;
console.log(data);
})

异步线程不容易维护,阅读,调试,可以通过es5的promise机制和es6最新提出的async/await机制来实现
进程:每一个正在运行的应用程序被称为进程。进程是操作系统为应用程序分配资源的一个单位
线程:用来执行应用程序中的代码,一个进程内部,可以分为多线程
在一个线程内部,同时只可以干一件事
传统的开发方式大部分都是 I/O 阻塞的,所以需要多线程来更好的利用硬件资源。
多线程弊端:
创建线程耗费,线程数量有限,cpu需要在不同线程之间切换。

事件驱动和非阻塞机制:
node中将所有的阻塞操作都交给了内部线程池来实现。
node主线程本身。主要是不断的往返调用。
node js基本上所有的事件机制都是利用设计模式中的观察者模式来实现。
node js单线程类似于进入一个while(true)循环,直到没有事件观察者退出,每个异步事件生成一个事件观察者,如果有事件发生就调用回调函数。
node js使用事件驱动模型,当web-server接收到后,就把他关闭然后进行处理,然后去服务下一个web请求。
当这个请求完成,它被放回处理队列,当到达队列开头,这个结果被返回给用户。
这个模型非常高效可扩展性非常强,因为webserver一直接受请求而不等待任何读写操作。(这也被称之为非阻塞式IO或者事件驱动IO)
在事件驱动模型中,会生成一个主循环来监听事件,当检测到事件时触发回调函数。
node采用事件驱动的运行模型,通过事件驱动的方式处理请求时无需为每一个请求额外创建线程。在事件驱动的模型当中,每一个IO工作被添加到事件队列中,线程循环的来处理队列上的工作任务,当执行过程中遇到阻塞,线程不会阻塞下来,而是会返回一个回调函数,转而继续执行队列中的下一个任务。这个传递到队列中的回调函数在阻塞任务结束后才会被执行。
nginx是多进程单线程
每个Tick周期中会从事件队列查看是否有事件需要处理,如果有就取出事件并执行相关的回调函数。事件队列事件全部执行完毕,node应用就会终止。Node对于堵塞IO的处理在幕后使用线程池来确保工作的执行。Node从池中取得一个线程来执行复杂任务,而不占用主循环线程。这样就防止堵塞IO占用空闲资源。当堵塞任务执行完毕通过添加到事件队列中的回调函数来处理接下来的工作。
node内部采用google v8引擎,作为js引擎解释器
通过自行开发的libuv库,调用操作系统资源
总结
node js是一个js的运行环境(平台),不是一门语言,也不是一个框架。
node js环境即REPL环境
REPL:ead,eval,print,loop类似于浏览器的控制台
接收用户输入,执行用户输入,打印执行结果到控制台,循环下一次

程序模块化:

js文件越来越多,会遇到一些问题:文件污染,全局污染,命名冲突
程序模块化:
日期模块,数学计算模块,日志模块
模块化:将一个复杂的程序依据一定的规则(规范)封装成几个文件,并且组合在一起。
模块的内部数据:实现是私有的,只是向外部暴露一些接口。
模块化的好处
避免命名冲突,减少命名空间污染
降低耦合性;更好地分离、按需加载
高复用性:代码方便重用,别人开发的模块直接拿过来就可以使用,不需要重复开发类似的功能。
高可维护性:软件的声明周期中最长的阶段其实并不是开发阶段,而是维护阶段,需求变更比较频繁。使用模块化的开发,方式更容易维护。
部署方便
模块化规范:
模块化起源于node js,node js中把很多js打包成package,需要的时候直接(require) common.js要求 导入进来,这就是模块化的方式。
服务端模块化:commonjs是node js使用的模块化规范,约定标准,不是技术。用于约定我们的代码应该是怎样的一种结构。
浏览器端规范:amd规范:是requrejs在推广过程中对模块化定义的规范化产出。异步加载模块
同步加载模块:cmd是seajs在推广过程中对模块化定义的规范化产出。淘宝团队开发。
暴露模块

1
2
3
module.exports = value;
exports.xxx = value;
引入requre(xxx);

自定义:

1
2
3
4
5
6
module.exports = {
name:"我是module1",
foo(){
console.log(this.name);
}
}

引入

1
2
let module1 = require("./modules/module1");
module1.foo();

AMD:异步模块定义:AMD专门用于浏览器端,模块的加载是异步的。

1
2
3
define(function() {
return 模块
})

1
2
3
4
require(['module1','module2'],function(m1,m2){
//使用
m1 / m2;
})

CMD同步模块加载,CMD专门用于浏览器端,模块的加载是同步的,

1
2
3
4
5
6
7
8
module.exports = value;
//引入依赖的模块(同步的方式)
var module2 = require('./module2')

//引入依赖的模块(异步的方式)
require.async('./module3', function (m3) {

})

es6模块化的说明
依赖模块需要编译打包处理
1.有些浏览器不支持es6的语法,写完es6的代码后,需要babel将es6转化为es5
export
引入模块 import xxx from ‘路径’
默认暴露的方式

1
2
3
export default() => {
console.log("我暴露了");
}

es6语法概览:
块级作用域,字符串,对象扩展,解构,类,模块化。
let定义变量,代替var

http状态

http协议是无状态的,服务器只会响应来自客户端的请求,但是他与客户端之间不具备持续连接。
服务端发送事件后,无法推送到客户端。只有在客户端查询服务器当前状态时,所发生事件的信息才会从服务器传递到客户端。
知道服务器的状态:
轮询:客户端每隔很短的时间,都会向服务器发出请求,,查看是否有新的消息,只要轮询速度足够快,例如1秒,就能给人造成交互是实时进行的印象。这种做法是无奈之举,实际上对服务器、客户端双方都造成了大量的性能浪费。
长连接:客户端只请求一次,但是服务器会保存这次连接,不会返回结果。当服务器有了新数据时,实时地发给客户端,而一直保持挂起状态。这种做法的也造成了大量的性能浪费。
websocket协议:允许客户端与服务器端以全双工的形式进行通信。
WebSocket 的原理非常简单:利用HTTP产生请求握手,HTTP头部含有 WebSocket 协议的请求,*握手之后,二者之间使用TCP进行交流(QQ的协议)。
HTTP1.1通过使用Connection:keep-alive进行长连接,HTTP 1.1默认进行持久连接。在一次 TCP 连接中可以完成多个 HTTP 请求,但是对每个请求仍然要单独发 header,Keep-Alive不会永久保持连接,它有一个保持时间,可以在不同的服务器软件(如Apache)中设定这个时间。

websocket是一个真正的全双工。长连接第一次tcp链路建立之后,后续数据可以双方都进行发送,不需要发送请求头。

keep-alive双方并没有建立正真的连接会话,服务端可以在任何一次请求完成后关闭。WebSocket 它本身就规定了是正真的、双工的长连接,两边都必须要维持住连接的状态。
es6中新语法
如果不想让 arr1 和 arr2 指向同一个内存地址,我们可以借助扩展运算符来做:
arr1是一个数组,arr2不需要指向arr1

1
let arr2 = [...arr1];

angularJS提供更多的是一套解决方案,更像是一个生态
vue和react目前都使用了virtual dom
vue和react的相同点
利用虚拟DOM实现快速渲染
轻量级
响应式组件
支持服务端渲染
易于集成路由工具,打包工具以及状态管理工具
虚拟dom:可以在js内存里构建类似于DOM的对象,去拼装数据,拼装完整后,把数据完整解析,一次性插入到DOM里面去,这就形成了虚拟DOM。

promise机制

promise:简单来说就是一个容器,里面保存着某个未来才会结束的事件的结果,从语法上说,promise是一个对象,从他可以获取异步操作的结果,promise提供一个统一的api,各种异步操作都可以用同样的方法处理,让开发者不用再关心时序和底层的结果,promise的状态具有不受外界影响和不可逆的特点。传统回调存在bug:调用回调次数过少或过多。对于Promise来说,即使是立即完成的Promise也无法被同步观察到,也就是说一个Promise调用then()的时候,即使这个Promise已经决议了,提供给then的回调也总会被异步调用。
对于一个proise对象来说,对象的注册和每一个观察回调都是相对独立的,互不干预的,而promise对象调用reslove和reject,每个注册的观察回调也都会被自动调度。所以这些观察回调的任意一个都无法影响或延误对其他回调的调用。
css中的BFC概念。

BFC概念

文档流,常说的文档流其实分为定位流,浮动流,普通流,3种,而普通流就是指BFC中的FC(fomatting context),直译过来就是格式化上下文,它是页面中的一块渲染区域,有一套渲染规则,决定了其子元素如何布局,以及和其他元素之间的关系和作用,常见的FC有BFC,IFC,还有GFC和FFC。
BFC,块级格式化上下文,是用于布局块级盒子的一块渲染区域。MDN上的解释就是:BFC是web页面css视觉渲染的一部分,用于决定块盒子的布局及浮动相互影响的一个区域。
一个BFC的范围包含创建该上下文元素的所有子元素,但不包括创建了新BFC的子元素的内部元素。这从另一方角度说明,一个元素不能同时存在2个BFC中,因为如果一个元素能够同时处于两个BFC中,那么就意味着这个元素能与两个BFC中的元素发生作用,就违反了BFC的隔离作用。
常规流:盒一个接着一个排列。
浮动:floats,左浮动元素尽量靠左,靠上,右浮动。
绝对定位:盒从常规流中被移除,不影响常规流的布局。
根元素,即HTML标签
浮动元素:float值为 left、 right
overflow值不为 visible,为 auto、 scroll、 hidden
display值为 inline-block、 table-cell、 table-caption、 table、 inline-table、 flex、 inline-flex、 grid、 inline-grid
定位元素:position值为 absolute、 fixed

  1. 作用
    BFC是页面上的一个隔离的独立容器,容器里面的子元素不会影响到外面元素,反之亦然。我们可以利用BFC的这个特性来做很多事。
    5.1阻止元素被浮动覆盖。5.2可以包含浮动元素,通过改变包含浮动子元素的父盒子的属性值,触发BFC,以此来包含子元素的浮动盒子。
    5.3阻止因为浏览器因为四舍五入造成的多列布局换行的情况
    5.4阻止相邻元素的margin合并

node js是一个基于google v8引擎的js运行环境,所以v8就是node js中使用的虚拟机环境,在之后讲解的 Node.js 中的 GC 其实就是在讲 V8 的 GC。
node js与v8的关系好比java与JVM之间的关系,另外 Node.js 之父 Ryan Dahl 在选择 V8 做为 Node.js 的虚拟机时 V8 的性能在当时已经领先了其它所有的 JavaScript 虚拟机,至今仍然是性能最好的,因此我们在做 Node.js 优化时,只要版本升级性能也会伴随着被提升
提供了process.memortUsage方法来查看当前进程的使用情况。
垃圾回收是指回收那些在应用程序中不再引用的对象,当一个对象无法从根节点访问这个对象就会作为垃圾回收的候选对象,这里的根对象为全局对象,局部变量,无法从根节点访问指的是不会再被任何其他活动对象所引用。

v8中分为新生代和老生代空间,新生代空间中存储频繁的数目,随后将长期驻存的移到老生代空间中。
IE盒子模型包含border和padding
box-sizing:content-box;标准盒模型
box-sizing:border-box;IE盒模型
获取样式高度 宽度
window.getComputedStyle(element).width/height;
BFC:块级格式化上下文
BFC渲染原理:BFC内部的子元素,在垂直方向,边距会发生重叠。
BFC在页面中是独立的容器,外面的元素不会影响里面的元素,反之亦然
BFC区域不会与旁边的float box区域重叠。
计算BFC的高度时,浮动的元素也参与计算
DOM事件的级别:
准确来说,是DOM标准定义的级别:
dom0级别的写法:

1
2
3
element.onclick = function() {

}

dom2级别的写法

1
2
3
element.addEventListener("click",function() {

},false);

true表示捕获阶段触发,false
dom3级别的写法

1
2
3
element.addEventListener("keyup",function() {

})

DOM3中,增加了很多事件类型,比如鼠标事件,键盘事件等。
为何事件没有DOM1的写法呢?因为,DOM1标准制定的时候,没有涉及与事件相关的内容。
window -> document -> html -> body -> 目标元素

1
2
3
4
5
var myEvent = new Event("clickTest");
element.addEventListener("clickTest",function() {
console.log('smyhvae');
})
element.dispatchEvent(myEvent);

http协议:
客户端和服务器端是两种身份,第一次请求结束后,就断开了,第二次请求时,服务器没有记住之前的状态,
HTTP报文的组成:
请求报文:请求行,请求头,空行,请求体
响应报文:状态行,响应头,空行,响应体
请求行:post方法,请求的url,http协议以及版本
请求头:一大堆键值对
请求体:数据部分
响应报文:
状态行:http协议以及版本,状态码以及描述
响应头:http/1.1 200 OK
响应体:返回的数据
http状态码:1xx 指示信息-表示请求已经接受 基础处理
2xx 成功 表示请求已被成功接受
3xx 重定向 要完成请求必须进一步操作
4xx 客户端错误
5xx 服务器错误
instanceof的作用:用于判断实例属于哪个构造函数
原理:判断实例对象的proto属性,和构造函数的prototype属性,是否是同一个引用(即是否是同一个地址)
foo instanceof Object的结果也是true,
new 运算符发生了什么
1.创建了一个新的空对象实例
2.将此空对象的隐式原型指向其构造函数的显示原型
3.执行构造函数,同时 this 指向这个新实例。
4.如果返回值是一个新对象,就返回该对象,如果无返回值或者返回一个非对象值,那么就将步骤(1)创建的对象返回。

1
2
3
function Animal(){
this.name = "sym";
}

用class声明

1
2
3
4
5
class Animal{
constructor(name){
this.name = name;
}
}

ajax:不支持跨域
websocket:不受同源策略的限制,支持跨域
cors:不受同源策略的限制,支持跨域。同时支持同源和跨域的Ajax。
jsonp实现原理:通过script标签的异步加载来实现,比如说,实际开发中,head标签里,可以通过script标签的src,里面来放url,加载很多在线的插件,这里就是通道了jsonp

反射型xss

在没有网站登出的情况下去访问非法网站,非法网站就要求A去访问新的网站,并且携带者A的cookie -> CSRF
跨域脚本攻击:不需要你做任何的登录认证,它会通过合法的操作(比如在url中输入、在评论框中输入),向你的页面注入脚本,可能是js,html代码块,最后导致结果:盗用cookie,破坏页面解构,插入广告等。d-doss攻击。 -> xss
随表单一起提交给服务器,服务器随后解析,xss代码随响应体一起传回,最后浏览器解析执行XSS代码。这个过程像一次反射,所以叫反射型XSS。
存储型:提交的代码会存储在服务器端,下次请求目标页面时就不用再提交XSS代码了。

文档类型

DTD(文档类型定义):
是一系列的语法规则,用来定义XML或者(x)HTML文件类型,浏览器使用DTD判断文档类型.决定使用哪种协议来解析,以及切换浏览器模式。告诉浏览器,我是什么文档类型,你要用什么协议来解析我。
<!DOCTYPE html>
DOM tree和CSS Rule Tree合并成Render Tree,(虽然有了Render Tree,但并不知道节点的位置,需要依靠接下来的layout)
有了render Tree,浏览器已经知道网页中有哪些节点,各个节点的css定义以及他们的从属关系,从而去计算每个节点在屏幕上的位置(宽高,颜色等).
painting:按照计算出来的规则,通过显卡,把内容绘制到屏幕上。
display:打击看到最终的效果。
reflow:重排,dom节点中的各个元素都有自己的盒子,这些都需要浏览器根据各种样式来进行计算,并根据计算结果将元素放在他该出现的位置,这个过程称为reflow.
触发reflow:增加,删除,修改dom节点。 导致reflow和repaint
移动dom位置。修改css样式,宽高,display为none时。
repaint:重绘制,当各种盒子的位置,大小以及其余属性,例如颜色,字体大小都确定后,浏览器便会把这些元素按照各自的特性绘制一遍,于是页面的内容也就出来了。
页面呈现的内容,绘制在屏幕上,叫做重绘
页面元素的位置,叫做重排
js是单线程(同一时间只能做意见事情),而且只有一个任务队列,全部的同步任务执行完毕后,才会去执行异步任务,
遇到异步任务,setTimeout等,先挂起。全部的同步任务执行完毕后,再来执行异步任务。
什么时候需要等待,就什么时候需要用异步。
定时任务:setTimeout,网络请求,ajax,动态img增加。
事件绑定。比如所,按钮绑定点击事件,用户爱点不点,我们不可能一直卡在那里,,什么都不做。所以,应该用异步)
同步任务指的是,在主线程上排队执行的任务,只有前一个任务执行完毕,才能执行后一个任务。异步任务指的是,不进入主线程、而进入”任务队列”(task queue)的任务,只有任务队列通知主线程,某个异步任务可以执行了,该任务才会进入主线程执行。
总结:只要主线程空了,就去读取“任务队列”。
提升页面性能方法
1.资源压缩合并,减少http请求。
2.非核心代码异步加载,
document.createElement() defer加载,async加载
defer:在html解析完之后才会执行,如果是多个,则按照加载顺序依次执行。
async:在加载完之后立即执行,如果是多个,执行顺序和加载顺序无关。
3.利用浏览器缓存,和存储不是一件事
缓存 资源文件
强缓存:不用请求服务器,直接使用本地缓存
强缓存是利用HTTP响应头中的express或cache-control实现
Cache-Control的优先级高于Expires。
4.使用CDN
5.DNS预解析
前端错误监控:
1.前端错误的分类 2.每种错误的捕获方式 3.上报错误的基本原理
try…catch window.onerror函数 这个函数是全局的
手机端的web开发,怎么和原生做交互?
调用原理需清楚,怎么调用原生的插件的

let var function

let的创建过程被提升了,但是初始化没有被提升
var的创建和初始化都被提升了
function的创建和初始化和赋值都被提升了
声明时的重名问题:
假设a被声明为变量,紧接着又被声明为函数,原则是::声明会被覆盖(先来后到,就近原则)。
如果a已经有值,再用var声明是无效的
如果a已经有值,紧接着又被赋值,则赋值会被覆盖

1
2
3
4
5
var fn;
function fn() {

}
console.log(fn); //打印函数fn

1
2
3
4
5
function fn() {

}
var fn;//再用var 无效
console.log(fn);//打印结果 函数fn
1
2
3
4
5
6
function fn() {}  //fn被声明为function,且此时fn已经有值,这个值就是function的对象

function fn() { //此时fn被重复赋值,会覆盖上一行的值
console.log('smyhvae');
}
console.log(fn)

下面的fn声明会覆盖上面的
使用var关键字声明的变量,是在函数作用域中有效,而且会在函数中所有的代码之前被声明.
函数声明也会在函数中所有的代码执行之前执行。
在函数中,没有var声明的变量会成为全局变量,而且不会提前声明。

web前端入门和进阶js笔记

发表于 2019-06-16 | 分类于 js相关

js和esmscript的关系

js和ecmscrpit的关系
ecmscript是一种有ecma国际制定和发布的脚本语言规范
ecmscript不是一门语言,而是一种标准
js包括ecmpscript(语言核心功能基于ES规范)
DOM js需要支持对DOM的维护,通过document element
BOM js需要支持对BOM的维护,通过window对象实现,这些都是在es6中没有的
提一下nodejs.nodejs是基于chrome V8引擎。上文提到V8引擎是用来解析执行JS,并且V8是基于ECMAscirpt标准实现的.换个角度说,nodejs里头没有DOM和BOM的操作,只保留的javascript的语法核心(ES),并且增加了事件驱动的非阻塞I/O模型,使其轻量级和高效。nodejs作为服务运行在linux,mac,window,把javascipt的角色从前台开发,转移到了后台开发。
js与ecmscript的关系
js是弱变量类型的语言,变量声明用var来实现。而java中必须带类型
var a;

浏览器工作原理


1、User Interface 用户界面,我们所看到的浏览器

2、Browser engine 浏览器引擎,用来查询和操作渲染引擎

3、Rendering engine 用来显示请求的内容,负责解析HTML、CSS

4、Networking 网络,负责发送网络请求

5、JavaScript Interpreter(解析者) JavaScript解析器,负责执行JavaScript的代码

6、UI Backend UI后端,用来绘制类似组合框和弹出窗口

7、Data Persistence(持久化) 数据持久化,数据存储 cookie、HTML5中的sessionStorage

js分为3部分组成
ECMAScript:JavaScript的语法标准。包括变量、表达式、运算符、函数、if语句、for语句等。
DOM:文档对象模型,操作网页上的元素的API。比如让盒子移动、变色、轮播图等。
BOM:浏览器对象模型,操作浏览器部分功能的API。比如让浏览器自动滚动。
PS:JS机械重复性的劳动几乎为0,基本都是创造性的劳动。而不像HTML、CSS中margin、padding都是机械重复劳动。
js是解释型语言,事先不需要被编译成机器码再执行,逐行执行,无需进行严格的变量声明。
解释型语言:边解析边执行,不需要事先编译。例如:JavaScript、php。

编译型语言:事先把所有的代码翻译成计算机能够执行的指令,然后整体执行。例如:c、c++。
分号不是必须加的,如果不写分号,浏览器会自动添加,但是会消耗一些系统资源。
用户输入
prompt()就是专门用来弹出能够让用户输入的对话框,用得少,测试的时候会用

1
2
var a = prompt("请随便输入点东西"); //不管是什么语句 输入都是字符串
console.log(a);

基本对象和引用对象

基本数据类型(值类型):String 字符串、Number 数值、Boolean 布尔值、Null 空值、Undefined 未定义。
引用数据类型(引用类型):Object 对象。
注意:内置对象function、Array、Date、RegExp、Error等都是属于Object类型。也就是说,除了那五种基本数据类型之外,其他的,都称之为 Object类型。
面试问:引用数据类型有几种?
面试题:只有一种,即object类型。
基本数据类型:参数赋值的时候,传数值
引用数据类型:参数赋值的时候,传地址
(2)引号不能嵌套:双引号里不能再放双引号,单引号里不能再放单引号。但是单引号里可以嵌套双引号。
\” \’ \n换行
无穷大 Infinity 无穷小 -Infinity
注意:typeof Infinity的返回结果是number。
NaN:是一个特殊的数字,表示Not a Number
typeof NaN返回的是number
null和undefined有最大的相似性。看看null == undefined的结果(true)也就更加能说明这点。
其他数据类型 -> Number
字符串 -> 数字
1.字符串是纯数字 则将其转化为数字
2.字符串有非数字的内容,则转化为NaN,
3.如果字符串是一个空串或者是一个全是空格的字符串,则转换为0。
null -> 数字 0 undefined -> 数字 NaN
parseInt的作用,将字符串中有效的整数内容转化为数字
console.log(parseInt(“2017.01在公众号上写了6篇文章”)); //打印结果仍是:2017 (说明只会取整数)
只能取开头的,中间的不能截取
对非String使用parseInt()或者parseFloat() 先转换成string再操作

1
2
var a = true;
console.log(parseInt(a));

转化为字符串”true”,然后再操作,打印出来NaN
转化为Boolean
数字 -> 布尔 除了0和NaN 其余都转化为true
字符串 -> 布尔 除了空串 其余都是true
null和undefined 转化为false
对象转化为true
布尔值进行与或运算时,会先将其转换为布尔值,然后再运算,但返回结果是原值

1
2
var result = 5 && 6;
console.log('result' + result);

与运算的返回结果:(以两个非布尔值的运算为例)

如果第一个值为true,则必然返回第二个值(所以说,如果所有的值都为true,则返回的是最后一个值)

如果第一个值为false,则直接返回第一个值

或运算的返回结果:(以两个非布尔值的运算为例)

如果第一个值为true,则直接返回第一个值

如果第一个值为false,则返回第二个值
== 这个符号并不严谨,会将不同类型的东西,转为相同类型进行比较(大部分情况下,都是转

1
2
3
4
5
6
7
 console.log("6" == 6);		// 打印结果:true。这里的字符串"6"会先转换为数字6,然后再进行比较
console.log(true == "1"); // 打印结果:true
console.log(0 == -0); // 打印结果:true

console.log(null == 0); // 打印结果:true
console.log(undefined == null) //打印true
console.log(NaN == NaN) //false

如果要保证完全等于,我们就要用三个等号===。全等不会做类型转换。例如:

1
2
console.log("6" === 6);		//false
console.log(6 === 6);

js中的代码块

js中的代码块,只具有分组的作用,没有其他用途
代码块中的内容,在外部是完全可见的

1
2
3
4
{
var a = 2;
}
console.log(a);

switch语句,条件分支语句。

1
2
3
4
5
6
7
8
switch(表达式){
case 1:
break;
case 2:
break;
default:
breeak;
}

break语句一般建议不要省略,否则会出现case穿透现象
continue用来跳过当次循环
基本数据类型是直接保存在栈内存中,值与值之间是独立存在的,修改一个变量不会影响其他变量。
对象:只要不是那5种基本数据类型,就全都是对象。
如果使用基本数据类型的数据,我们所创建的变量都是独立,不能成为一个整体。
对象属于一种复合的数据类型,在对象中可以保存多个不同数据类型的属性。
对象是保存到堆内存中的,每创建一个新的对象,就会在堆内存中开辟一个新的空间,变量保存的是对象的内存地址(对象的引用)
换言之,对象的值是保存在堆内存里的,但是对象的引用是保存在栈内存中的
对象的分类:内置对象,由ES标准定义的对象,在任何的ES的实现中都可以使用
比如Math,String,Number,Boolean,Function,Object
宿主对象:由js运行环境提供的对象,就是主要由浏览器提供的对象
比如DOM,BOM,console document等
自定义对象 由开发人员自己创建的
in运算符,通过该运算符可以检查一个对象中是否含有指定的属性,如果有则返回true,没有返回false
“属性名” in 对象
console.log(“name” in obj);
js中 所有的变量都是保存在栈中的。
基本数据类型:基本数据类型的值,直接保存在栈内存中。值与值之间是独立存在,修改一个变量不会影响其他的变量。
引用数据类型:对象是保存在堆内存中的,每创建一个新的对象,就会在堆内存中开辟一块新的空间,而变量保存了对象的地址,对象的引用,如果两个变量保存了同一个对象的引用,当一个通过变量去修改属性时,另一个也会修改。
函数的介绍:将一些功能语句进行封装 函数也是一个对象 使用typeof检查一个函数对象时,返回function
函数表达式:将匿名函数赋值给一个变量
fn()与fn的区别
fn()调用函数,相当于获取了函数的返回值
fn:函数对象,相当于直接获取了函数对象
在js中,只有2种作用域:全局作用域和函数作用域
直接编写在script标签中的JS代码,都在全局作用域。

全局作用域在页面打开时创建,在页面关闭时销毁。

在全局作用域中有一个全局对象window,它代表的是一个浏览器的窗口,它由浏览器创建我们可以直接使用。

在全局作用域中:

创建的变量都会作为window对象的属性保存。

创建的函数都会作为window对象的方法保存。

全局作用域中的变量都是全局变量,在页面的任意的部分都可以访问的到
变量的声明提前(变量提升)
使用var关键字声明的变量var = 1 会在所有代码执行之前声明(但不赋值)
但是如果声明时不用var 比如a = 1 则变量不会被声明提前
函数声明:下面就为函数声明的过程

1
2
3
function fn1() {
console.log("我是函数fn1");
}

所以函数的声明会提前,也就是说,整个函数会在所有的代码执行之前就被创建完成,所以我们可以在函数声明之前,调用函数。
fn1()后再声明函数
函数表达式不会提前
在函数作用域中可以访问到全局作用域的变量,在全局作用域中无法访问到函数作用域的变量。
当函数执行时,会创建一个执行期上下文的内部对象。每调用一次函数,就会创建一个新的上下文对象,他们之间是相互独立的。当函数执行完毕,它所产生的执行期上下文会被销毁。参考链接:
this:解析器在调用函数每次都会向函数内部传递一个隐含的参数,这个隐含的参数便是this,this指向的是一个对象,这个对象我们称之为函数的执行上下文对象,
以函数形式调用,this指向window,比如func()
以方法形式调用,this是调用方法的那个对象
以构造函数形式调用,this是新创建的那个对象
使用call和apply调用,this指定的是那个对象

箭头函数中this的指向

es6的箭头函数中并不会使用上面4条标准的绑定规则,而是会继承外层函数调用的this绑定(无论this绑定到什么)
在调用函数式,浏览器每次都会传递2个隐含参数,this和arguments

1
2
3
4
5
function foo() {
console.log(arguments);
console.log(typeof arguments);
}
foo();

arguments是一个类数组对象,它可以通过索引来操作数据,也可以获取长度。
arguments代表的是实参,我们所传递的实参都会在arguments中保存。有个讲究的地方是:arguments只在函数中使用。

1
2
3
4
function fn(a,b){
console.log(fn.length);//获取形参个数
console.log(arguments.length);//获取实参个数
}

3、arguments可以修改元素
之所以说arguments是伪数组,是因为:arguments可以修改元素,但不能改变数组的长短。举例:
new 一个构造函数的执行流程
(1)开辟内存空间,存储新创建的对象
(2)将新建的对象设置为构造函数中的this,在构造函数中可以使用this来引用新对象。
(3)执行函数中的代码,(包括设置对象属性和方法等)。
(4)将新建的对象作为返回值返回
所有的对象都是Object的后代,因此,任何对象instanceof Object返回的结果都是true.
JSON:json的属性必须用双引号来括起来,

1
2
3
4
5
6
7
8
{
"name" : "zs",
"age" : 18,
"sex" : true,
"sayHi" : function() {
console.log(this.name);
}
};

json的遍历与对象的遍历一样,用for…in…来进行遍历

1
2
3
4
5
6
7
8
9
10
11
12
var myJson = {
"name": "smyhvae",
"aaa": 111,
"bbb": 222
};

//json遍历的方法:for...in...
for (var key in myJson) {
console.log(key); //获取 键
console.log(myJson[key]); //获取 值(第二种属性绑定和获取值的方法)
console.log("------");
}

原型prototype

原型prototype的概念:
认识1:我们所创建的每一个函数,解析器都会向函数中添加一个属性prototype,这个属性对应着一个对象,这个对象就是我们所谓的原型对象,
如果函数作为普通函数调用prototype没有任何作用,当函数以构造函数的形式调用时,它所创建的实例对象中都会有一个隐含的属性,指向该构造函数的原型,我们可以通过proto来访问该属性。

1
2
3
4
5
function Person() {}
var per1 = new Person();
var per2 = new Person();
console.log(Person.prototype); //打印结果[object object]
console.log(per1.__proto__ == Person.prototype); //相等

原型对象相当于一个公共的区域,所有同一个类的实例都可以访问到这个原型对象,我们可以将对象中共有的内容,统一设置到原型对象中。
使用in来检查,如果对象中没有但是原型中有,也会返回true.
可以使用对象的hasOwnProperty()来检查对象自身中是否含有该属性。

JS的垃圾回收机制

当一个对象没有任何的变量或者属性对他进行引用时,此时我们将永远无法操作该对象,此时这种对象就是一个垃圾,这种对象过多会占用大量的内存空间,导致程序运行变慢,所以这种垃圾必须进行清理。
在堆内存中:如果堆内存中的对象,没有任何变量指向它时,这个堆内存里的对象就会成为垃圾。
js中有自动的垃圾回收机制,会自动回收这些垃圾。如果你不再使用这些对象,将其置为null即可。
数组Array是属于内置对象。
数组和普通对象的功能类似,也是用来存储一些值的。不同的是:
普通对象是使用字符串来作为属性名的,而数组是使用数字来作为索引来操作元素。
数组的存储性能比普通对象要好。在实际开发中我们经常使用数组来存储一些数据,使用频率非常高。

1
var arr = new Array("参数");

数组常用方法

如果修改的length大于原长度,则多出来部分会空出来,置为null.
如果修改的length小于原长度,则多出来部分会被删除,数组将从后面删除元素。
数组的基本方法
unshift(),在数组最前面插入一个或多个元素,返回结果为数组新的长度。
shift(),删除数组的第一个元素,返回结果为被删除的元素
forEach()没有返回值,也就是说,返回值是undefined.
filter()返回结果是true的项,将组成新的数组,可以起到过滤的作用。
map()对原数组中的每一项进行加工
every()如果有一项返回false,则停止遍历
some()只要有一项返回true,则停止遍历
注意:这几个方法不会修改原数组。都会组成新的数组等。
forEach循环

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
var arr = ["网一","网二"];
arr.forEach(function(item,index,obj){
console.log(item);
console.log(index);
console.log(obj);
})
//表示当前正在遍历的元素,正在遍历元素的索引,和正在遍历的数组
//filter函数
var arr1 = [1,2,3,4,5,6];
var arr2 = arr1.filter(function(item,index){
if(item > 2)
return true;
return false;
})
//map方法 解释:对数组中每一项运行回调函数,返回该函数的结果,组成的新数组(返回的是加工之后的新数组)。

var arr1 = [1, 3, 6, 2, 5, 6];

var arr2 = arr1.map(function (item, index) {
return item + 10; //让arr1中的每个元素加10

})
console.log(arr2);
//every方法 只有全部返回true,才返回true
var arr1 = ["千古", "宿敌", "南山忆", "素颜"];
var bool1 = arr1.every(function (element, index, array) {
if (element.length > 2) {
return false;
}
return true;
});
console.log(bool1); //输出结果:false。只要有一个元素的长度是超过两个字符的,就返回false

some()方法
解释:对数组中每一项运行回调函数,只要有一项返回true,则停止遍历,此方法返回true。
如果都返回false,则返回值是false。如果有一项返回true,则停止遍历,返回true.

数组的常用方法
slice 从数组中提取指定的一个或多个元素,返回新的数组,不会改变原数组
splice从数组中删除指定的一个或多个元素,返回新的数组,会改变原数组
concat连接两个或多个数组,返回新的数组,不会改变原数组
jon将数组转化为字符串,返回转换后的字符串,不会改变原数组
reverse反转数组,返回翻转后的数组,会改变原数组
sort,对数组元素,按unicode编码,从小到大排序,会改变原数组。
slice

1
2
3
var result1 = arr.slice(2);//从第二个位置开始提取
var result2 = arr.slice(-2);//提取最后2个元素
var result3 = arr.slice(2,4);//提取从第二个到第四个 不包含4

将伪数组转化为真数组

1
array = Array.from(arrayLike);

splice 删除一个或多个元素,返回新的数组,会改变原数组
新数组 = 原数组.splice(起始索引index,需要删除的个数,第三个参数,第四个参数)

1
2
3
4
var arr1 = ["a","b","c","d","e","f"];
var result1 = arr1.splice(1);
console.log(arr1); //第1个删除后返回arr1
console.log(result1); //原数组的第一个删除了 给result

从第index为1的位置开始删除元素,一共删除三个元素。并且在 index=1 的前面追加两个元素

1
2
3
4
var arr4 = ["a", "b", "c", "d", "e", "f"];

//从第index为1的位置开始删除元素,一共删除三个元素。并且在 index=1 的前面追加两个元素
var result4 = arr4.splice(1, 3, "千古壹号", "vae");

concat连接 arr1.concat(arr2);将arr2中的元素追加到arr1的尾部
join方法指定一个字符串作为参数,这个字符串将会成为数组元素连接的连接符,如果不指定连接符,则默认使用’,’作为连接符,此时和 toString()的效果是一致的。
reverse反转字符串
sort函数中的自定义方法,
如果返回一个大于0的值,则元素会交换位置,
如果返回一个小于0的值,则元素位置不变
如果返回0,则认为2个元素相等,则不交换位置。
var result = arr3.sort(function(a,b){
if(a > b){
return a - b; //升序排列
return b - a;//降序排列
return 1;//如果a > b则交换a和b的位置,就是进行升序排列
}else if(a < b){
return -1; //元素位置保持不变
}else
return 0;
})
indexOf,lastIndexOf获取数据的索引
从后往前索引,获取 value 在数组中的最后一个下标 从后往前,找到最后一次出现的,也就是排在最后的出现的那位。
find(function (item, index){

})
Array.from将伪数组转化为真数组
伪数组的原型链中没有Array.prototype,而真数组的原型链中有Array.prototype
Array.of(1,’abc’,true);//将一系列值转化成数组
isArray 判断是否是数组
valueOf,返回数组本身 数组本身 = 数组.valueOf();
内置对象简介:内置对象就是指这个语言自带的一些对象,供开发者使用,这些对象提供了一些常用的或是最基本而必要的功能。
内置对象 对象说明
Arguments 函数参数组合
Array 数组
Boolean 布尔对象
Date 日期时间
Error 异常对象
Function 函数构造器
Math 数学对象
Number 数值对象
Object 基础对象
RegExp 正则表达式对象
String 字符串对象
Date对象

1
2
var date = new Date();
console.log(date);

传递一个表示时间的字符串

1
2
var date2 = new Date("2017/09/06 09:00:00");
console.log(date2);

Date和Math方法

获取日期和时间
getDate() //获取日子 1-31
getDay() //获取星期0-6 0代表周末 1代表周一
getMonth() //获取月份0-11 0代表1月
getTime() //获取时间戳
时间戳指的是从格林威治标准时间的1970.1.1号0时0分0秒到现在日期所花费的毫秒数(1s = 1000 ms)
内置对象Math的常见方法
Math.abs()返回绝对值
Math.floor()向下取整(向小取)
Math.ceil()向上取整(向大取)
Math.round()四舍五入(正数四舍五入,负数五舍六入)
Math.random()生成0-1之间的随机数
Math.max(x,y,z)返回多个数中的最大值
Math.min(x,y,z)返回多个数中的最小值
生成0-x之间的随机数

1
Math.round(Math.random() * x);

生成x-y之间的随机数

1
Math.round(Math.random() * (y - x) + x);

url编码和解码

URI 通用资源标识符,进行编码,以便发送给浏览器,有效的URI编码不能包含某些字符,例如空格,而这URI编码方法就可以对URL进行编码,它们用特殊的UTF-8编码替换所有无效的字符,从而让浏览器能够接受和理解。

1
encodeURIComponent();   //把字符串作为 URI 组件进行编码

包装类的介绍:
js中的数据类型包括以下几种,
基本数据类型:string,number,boolean,null,undefined
引用数据类型:object
js为我们提供了3个包装类
String(),将基本数据类型字符串,转化为String对象
Number(),将基本数据类型数字,转化为Number对象。
Boolean():将基本数据类型的布尔值,转换为Boolean对象。

1
2
var num = new Number(3);
var str = new String("hello");

需要注意的是:我们在实际应用中不会使用基本数据类型的对象,如果使用基本数据类型的对象,在做一些比较时可能会带来一些不可预期的结果。
方法和属性只能添加给对象,不能添加给基本数据类型。
slice方法 从字符串中截取指定的内容,不会修改原字符串 而是将截取到的内容返回
(2,5)截取时,包左不包右
字符串 = str.slice(开始索引,结束索引);
(2)表示从指定的索引位置开始,截取到最后
(-3)表示从倒数第几个开始,截取到最后
(1,-1)表示从第一个截取到倒数第一个
(5,2)表示前面的大,后面的小,返回值为空
substring,不能接受负值作为参数,如果传递了一个负值,默认使用0
substring还会自动调整参数的位置,如果第二个参数小于第一个,则自动交换。
substr从字符串中截取指定的内容,不会修改原来的字符串,而是将及截取到的内容返回。
字符串 = str.substr(开始索引, 截取的长度);
开始所以,截取的长度
用逗号来隔开字符串,split
trim去除字符串前后的空白。replace替换所有的
toLowerCase()转换成小写
定义:正则表达式用于定义一些字符串的规则。

作用:计算机可以根据正则表达式,来检查一个字符串是否符合指定的规则;或者将字符串中符合规则的内容提取出来。
语法:

1
2
var 变量 = new RegExp("正则表达式","匹配模式");
console.log(reg.test(str1));

来进行测试,检查是否符合。

let var function,eval的区别

let变量不存在变量提升问题,在我们声明(初始化)他们之前,他们是不可访问的。这被称为暂时死区
let 的「创建」过程被提升了,但是初始化没有提升。
var 的「创建」和「初始化」都被提升了。
function 的「创建」「初始化」和「赋值」都被提升了。
eval会为字符串传递的代码求值,如果它是一个表达式,就像如下所示:

1
const sum = eval("10 * 10 + 5");

sum为105 先计算出来 再赋值
所有对象键:(不包括Symbol)都会被存储为字符串形式,即使你没有给定字符串类型的键。
默认情况下:事件处理程序在冒泡阶段执行

1
2
3
4
5
function a(){
console.log(a);
}
console.log(typeof a);//返回function
console.log*typeof null)//返回object

1
2
3
4
5
6
[[0, 1], [2, 3]].reduce(
(acc, cur) => {
return acc.concat(cur);
},
[1, 2]
);

[1,2]是初始值,随后第一轮连接上[1,2,0,1],第二轮连接上[1,2,0,1,2,3]

1
2
3
4
function aaa(...args) {
console.log(args);
}
aaa(2,34);

这种情况下,将会把传入的数据全都组装成一个数组。
所以,打印出的args为[2,34];
事件的三要素:事件源,事件,事件驱动程序
事件源:应发后续事件的html标签
事件:js已经定义好的
事件驱动程序:对样式和html的操作,也就是DOM
获取事件源:document.getElementById(“box”);
绑定事件:box.onclick = function(){}
书写事件驱动程序:关于DOM的操作
js的加载和html是同步加载的,因此,如果使用元素在定义元素之前,容易报错。这个时候,onload事件就能派上用场了,我们可以把使用元素的代码放在onload里,就能保证这段代码是最后执行。
建议是:整个页面上所有元素加载完毕之后执行js内容。
所以,window.onload可以预防使用标签在预定义之前。
DOM:文档对象模型,DOM为文档提供了结构化表示,并定义了如何通过脚本来访问文档结构,目的其实是为了能让js操纵DOM形成一种规范。
渲染引擎将把内存中把HTML文档,生成一个DOM树。

1
2
3
4
5
6
var arr1 = document.getElementsByTagName("div");     //方式二:通过 标签名 获得 标签数组,所以有s

var arr2 = document.getElementsByClassName("hehe"); //方式三:通过 类名 获得 标签数组,所以有s
//返回数组
var div1 = document.getElementById("box1"); //方式一:通过id获取单个标签
//返回object

下一个兄弟节点 = 节点.nextElementSibling || 节点.nextSibling
获取父节点:节点.parentNode获取到父节点
前一个兄弟节点 = 节点.previousElementSibling || 节点.previousSibling
childNodes:标准属性,返回的是指定元素的子节点的集合(包括元素节点、所有属性、文本节点)
子节点数组 = 父节点.childNodes;
创建一个li标签

1
var a1 = document.createElement("li");

插入节点
appendChild(新的子节点);
逐一获取属性

1
myNode.getAttribute("src");

设置属性

1
setAttribute("src","imgs");

删除节点属性

1
removeAttributes(属性名);

1
2
3
<div id = "box" value = "111">
声明
</div>

上面这个标签就包含了3种标签,元素节点(标签) 属性节点 文本节点

1
2
3
4
5
var element = document.getElementById("box1");  //获取元素节点(标签)
var attribute = element.getAttributeNode("id"); //获取box1的属性节点
var txt = element.firstChild; //获取box1的文本节点

var value = element.getAttribute("id"); //获取id的属性值

nodeType = 1表示的是元素节点
nodeType = 2 表示属性节点
nodeType = 3表示文本节点
nodeName表示名称,nodeValue表示值
添加事件

1
2
3
element.addEventListener('click',function() {

},false);

参数1:事件名(注意,没有on)
参数2:事件名(执行函数)
参数3:true表示捕获阶段触发,false表示冒泡阶段触发,如果不写,默认为false
//addEventListener: 事件监听器。 原事件被执行的时候,后面绑定的事件照样被执行
//第二种事件绑定的方法不会出现层叠。(更适合团队开发)
第二件添加的事件不会覆盖第一件的
DOM事件流:
事件传播的3个阶段:事件捕获,事件目标,事件冒泡
事件捕获:事件从上一级标签开始往下寻找,直到捕获到事件目标 target,从祖元素到子元素,DOM树结构,在这个过程中,事件相应的监听函数不会被触发。
事件目标:当到达目标元素之后,执行目标元素事件对应的处理函数,如果没有绑定监听函数,那就不执行。
事件冒泡:事件从事件目标target开始,网上逐渐冒泡到页面最上层一级。
在js中,如果想获取html节点,方法是document.documentElement
如果想获取body节点,方法是docuemt.body 二者不要混淆
事件冒泡:鼠标点击一个按钮,同样这个事件会在所有父元素上被触发。
通俗来讲,冒泡指的是:子元素的事件被触发时,父盒子的同样的事件也会被触发。取消冒泡就是取消这种机制。
冒泡顺序:
一般的浏览器: (除IE6.0之外的浏览器)
div -> body -> html -> document -> window
IE6.0:
div -> body -> html -> document
不是所有的事件都能冒泡:
以下事件不冒泡:blur,focus,load,unload,onmouseenter,onmouseleave,意思是事件不会向父元素那里传递。
检查一个元素是否会冒泡,可以通过事件的如下参数:event.bubbles.
阻止冒泡的方法(火狐,谷歌,IE11)event.stopPropagation();
IE10以下则是event.cancelBubble = true;
事件委托:事件委托:通俗来说,就是把一个元素响应事件函数委托到另一个元素上
window对象是BOM的顶层(核心)对象,所有对象都是通过它延伸出来的 也可称为window子对象
window对象是js中的顶级对象,全局变量,自定义函数也是window对象的属性和方法
alert(1);confirm(1) prompt()不推荐使用 弹出框
打开窗口window.open(url,target,param)
url:打开地址 target:新窗口位置_blank _self _parent
param:新窗口的一些设置
返回值:新窗口的句柄
window.location简写成location,locaton相当于浏览器地址栏,可以将url解析成独立的字段
href:跳转 hash:返回url中#后面的内容 host:主机名 hostname:主机名 protocol 协议 一般是http、https
使用href的作用就是调用assign
window.location.assign(“https://www.baidu.com");
设置location.href 就会调用assign()。一般使用location.href 进行页面之间的跳转。assign会记录到历史记录中去
location.replace():替换浏览器地址栏的地址,不会记录到历史中
navigator对象会获取客户端的一些信息
console.log(navigator.userAgent);
history.back() 表示后退 history.go(-1) 0是刷新
与普通函数相比,构造函数有以下明显特点:
用new关键字调用,不需要return显示返回值的,默认为返回this。建议函数名首字母大写,与普通函数区分开。
原型规则
规则1 所有的引用类型(数组,对象,函数)都具有对象特性,都可以自由扩展属性。null除外。
所有的引用类型(数组,对象,函数)都有proto属性,属性值是一个普通的对象。proto的含义是隐式原型。

1
2
var obj = {};
console.log(obj.__proto__);

所有的构造函数都有prototype类型 指向原型对象
通过for…in循环遍历对象,针对上面的那个fn对象,它自身有两个属性:name、printName,另外从原型中找到了第三个属性alertName。现在,如果我们对fn进行遍历,能遍历到两个属性还是三个属性呢?
答案:2个,因为高级浏览器已经屏蔽了来自原型的属性,。但是,为了保证代码的健壮性,我们最好自己加上判断,手动将第三个属性屏蔽掉:

call和apply

这2个方法都是函数对象的方法,需要通过函数对象来调用
当函数调用call和apply时,函数会立即执行
都可以用来改变函数的this对象的指向
第一个参数都是this要指向的对象(函数执行时,this将指向这个对象)
thisObj不传或者为null、undefined时,函数中的this会指向window对象(非严格模式)。
传递一个别的函数名时,函数中的this将指向这个函数的引用。
传递值为数字,布尔值,字符串时,this会指向这些基本类型的包装对象Number,Boolean,String
传递一个对象时,函数中的this则指向传递的这个对象。
call和apply的区别,call后面的实参和say方法中是一一对应的,而apply在传递实参时,要封装成一个数组,数组中的元素是和say方法中一一对应的,这就是两者最大的区别。
call()和apply()的作用
改变this的指向
实现继承。Father.call(this)
bind()
都能改变this的指向
call()/apply()是立即调用函数
bind()是将函数返回,因此后面还需要加()才能调用。
bind传参 xw.say.bind(xh,”实验”,”六年级”)();
或者xw.say.bind(xh)(“实验”,”小学”);
apply方法xw.say.apply(xh,[“实验小学”,”六年级”]);
call方法xw.say.call(xh,”实验小学”,”六年级”);
函数赋值给变量时,this指向window
var foo1 = args.getInfo;
foo1()
var foo2 = function() {};
foo2();
//this都是指向window
执行上下文主要有2种情况:
全局代码,一段script标签内,有一个全局的执行上下文。所做的事情是:变量定义,函数声明
函数代码:每个函数里面有一个上下文,所做的事情是:变量定义、函数声明、this,arguments
var定义的为全局变量 => undefined
function声明的全局变量 ===> 赋值fun 添加为window的方法
this => 赋值(window)(
函数执行上下文:调用函数时,准备执行函数体之前,创建对应的函数执行上下文对象,(虚拟的,存在于栈中)
对局部数据进行预处理
形参变量 ===> 赋值(实参) 添加为执行上下文的属性
arguments ===> 赋值(实参列表) 添加为执行上下文的属性
var 定义的局部变量 ===> undefined 添加为执行上下文的属性
function声明的函数 ==>赋值(fun), 添加为执行上下文的方法
this ===> 赋值(调用函数的对象)
执行上下文栈:
在全局代码执行前,JS引擎会创建一个栈来存储管理所有的执行上下文对象
在全局执行上下文window确定后,将其添加到栈中
在函数执行上下文创建之后,将其添加到栈中
在当前函数执行完后,将栈顶的对象移除
当所有的代码执行完后,栈中只剩下window
this指的是,调用函数的那个对象。this永远指向函数运行时所在的对象。
解析器在调用函数的时候每次都会向函数内部传递一个隐藏的参数,这个隐藏的参数就是this
以函数形式调用,this会指向window
以构造函数创建,this是新创建的那个对象
使用call和apply调用时,this指向那个对象
作用域指一个变量的作用范围,是静态的(相对于上下文对象)
全局作用域 函数作用域
调用函数时会创建函数作用域,函数执行完毕以后,函数作用域会销毁。
每调用一次函数就会创建一个新的函数作用域,他们之间是互相独立的。
在函数作用域中可以访问到全局作用域中的变量,在全局作用域中无法访问到函数作用域中的变量。
使用var关键字声明的变量,是在函数作用域内有效,而且会在函数中所有的代码执行之前被声明
在函数作用域中有效,而且会在函数中所有代码执行前会被声明。
全局执行上下文是在全局作用域确定之后,js代码马上执行之前就创建了。
函数执行上下文实在调用函数时,函数体代码执行之前创建
作用域是静态的,只要函数定义好就一直存在,且不再变化
执行上下文是动态的,调用函数时创建,函数调用结束时就会自动释放
执行上下文(对象)是从属于所在的作用域
全局上下文环境 ===> 全局作用域
函数上下文环境 ===> 对应的函数使用域
闭包:能够读取其他函数内部数据(变量/函数)的函数
因此可以把闭包简单理解成”定义在一个函数内部的函数”。
object.prototype.toString.call(‘’) 检测类型[object:string]
this的值是在执行的时候才能确认,但是不能在定义的时候确认
箭头函数this指向:箭头函数没有自己的this,看其外层的是否有函数,如果有,外层函数的this就是内部箭头函数的this,
如果没有,this就是window
执行栈认为是一个存储函数调用的结构,遵循先进后出原则。

手写实现ajax

1
2
3
4
5
6
7
8
9
10
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function () {
if(xhr.readyState == 4){
if(xhr.status == 200){
alert(xhr.responseText);
}
}
}
xhr.open("GET","/api",false);
xhr.send(null);

动态创建DOM元素的3种方式

document.write()不常用 因为容易覆盖掉原来的页面
innerHTML = () 用的比较多,绑定属性和内容比较方便
document.createElement() 用的也比较多,,指定数量的时候一般用它。
vue双向绑定原理:通过数据劫持结合发布者-订阅者模式的方式来实现
利用object.defineProperty()这个方法重新定义了对象获取属性值(get)和设置属性值(set)。
jquery是事件驱动 而其余是数据驱动
jquery业务和UI更改混杂在一起,UI里面还涉及交互逻辑,让本来混乱的逻辑更加混乱
node js借助事件驱动,非阻塞I/O模型变得更加轻量和高效,非常适合于运行在分布式设备的数据密集型实时应用。
offsetWidth和offsetHight
offsetWitdh用于检测盒子自身的宽高+padding+border
offsetWidth = width + padding + border;
offsetLeft 可以返回没有定位盒子的距离左侧的位置。如果父系盒子中都没有定位,以body为准。
style.left 只能获取行内式,如果没有,则返回””(意思是,返回空);
scrollWidth = width + padding;
scrollHeight = height + padding;
client家族的形成
clientWidth:获取盒子区域宽度(padding + width)
clientHeight:获取盒子区域高度(padding + height)
body/html调用时,
clientWidth获取网页可视区域宽度
clientHeight获取网页可视区域高度

clientX:event调用:鼠标距离可视区域左侧距离
clientY:event调用:鼠标距离可视区域上侧距离

clientTop:盒子的上border。
clientLeft:盒子的左border。

宽高:
offsetWidth = width + padding + border;
offsetHeight = height + padding + border;

window.onresize事件指的是:在窗口或框架被调整大小时发生:
window.onscroll()屏幕滑动
window.onresize()浏览器大小变化
window.onload()页面加载完毕
div.onmousemove()鼠标在盒子上移动

1
2
3
window.onresize = function() {
document.title = window.screen.width + window.screen.height;
}

获取显示屏的分辨率1920 * 1080
jQuery的两大特点 链式编程比如.show和.html可以连写成.show().html()
通常情况下:只有设置操作才能把链式编程延续下去,因为获取操作的时候,会返回获取到的相应值,无法返回this.
隐式迭代的意思是:在方法的内部会为匹配到的所有元素进行循环遍历,执行相应的方法;而不用我们再进行循环,简化我们的操作,方便我们调用。
jquery加载完

1
2
3
4
//dom树生成即可
$(document).ready(function(){

})

//文档加载完毕,图片不用加载完 写下面这个

1
2
3
$(function() {
alert(1);
})

onload是网页全部加载完毕,包括图片,ready只需要dom加载完毕,生成dom树即可
通过jquery获取的元素是一个数组 数组中包含着原生JS中的DOM对象
通过原生js获取这些元素节点的方式是

1
2
3
var myBox = document.getElementById("box");           //通过 id 获取单个元素
var boxArr = document.getElementsByClassName("box"); //通过 class获取的是数组
var divArr = document.getElementsByTagName("div"); //通过标签获取的是数组

总结:jquery就是把dom对象重新包装了一下,让其具有了jquery方法
子代选择器 > 表示儿子 后代选择器 表示全部的都会被选中
属性选择器:$(“a[href]”) $(“a[href = ‘itcast’]”)
添加类样式
$(selector).addClass(“listItem”);
删除类样式
$(selector).removeClass(“listItem”);
判断是否有样式
$(selector).hasClass(“listItem”);
切换类样式
$(selector).toggleClass(“listItem”);
有则移除 没有则添加
jquery设置和获取属性
设置属性attr(“title”,”生命一号”);
获取属性attr(“title”);
val() 设置或返回form表单元素中的value值
$(selector).val();
获取文本内容
$(selector).text();
jquery设置宽度和高度
$(selector).height();//不带参数表示获取高度
$(selector).height(200);//带参数表示设置高度

$(selector).width(); //不带参数表示获取宽度
$(selector).width(200); //带参数表示设置高宽度

$(“div”).css() //返回的是string类型,例如30px
$(“div”).height() 返回的是number类型,30常用于数学计算
click是单击事件 blur失去焦点 mouseenter鼠标进入 mouseleave 鼠标离开等
解除匹配元素的所有事件
$(selector).off()
阻止事件冒泡
event.stopProgation()
阻止默认行为
event.preventDefault()
$(selector).each(function(index,element){

})
参数一表示当前元素所在匹配元素中的索引号,
参数而表示当前元素
多库共存指的是:jquery占用了$和jquery两个变量,当在同一个页面引用了jquery和其他库时,恰好其他库也使用了jquery或者$
,那么要保证多库共用,
获取jquery库的版本号console.log($.fn.jquery);
办法一:让jquery放弃对$的使用权
$.noConflict();
办法二:同时放弃2个符号的使用权,并定义一个新的使用权
$.noConflict(true);
zepto库介绍
zepto是轻量级js库,专门为移动端定制
与jquery有类似的API,俗称:会jquery就会zepto
css3现状
浏览器支持程度不够好,有些需要添加私有前缀
移动端支持优于PC端
不断改进中
应用相对广泛
过渡:transition 2D转换:transform 3D转换:transform 动画:animation
实现不同状态间的平滑过渡
transition-property: all; 如果希望所有的属性都发生过渡,就使用all。
transition-duration:1s;过渡的持续时间
transition-timing-function: linear; 运动曲线
transition:all 3s linear 0s;
缩放:scale
transform:scale(x,y);x轴的缩放和y轴的缩放
x:表示水平方向的缩放倍数。y:表示垂直方向的缩放倍数。如果只写一个值就是等比例缩放。
translate 参数为百分比,表示相对于自身移动
正值:向右和向下 负值:向左和向上

1
2
3
4
5
6
7
8
9
{
width:600px;
height:60px;
background-color:red;
position:absolute; 绝对定位
left:50%; 让左边线居中
top:0;
transform:translate(-50%); 然后利用translate,往左走自己一半的宽度
}

transform:rotate(角度);rotate(45deg); 正值:顺时针 负值:逆时针
3D旋转 rotateX,rotateY,rotateZ
动画可通过设置多个节点,来精确控制一个或一组动画,常用来实现复杂的动画效果。
@keyframes 动画名{
from{初始状态}
to{结束状态}
}

@keyframes move1 {
from {
transform: translateX(0px) rotate(0deg);
}
to {
transform: translateX(500px) rotate(555deg);
}
}

flex布局

主轴:Flex容器的主轴主要用来配置Flex项目,默认是水平方向,从左向右。
侧轴:与主轴垂直的轴称作侧轴,默认是垂直方向,从上往下。
flex-direction:row;reverse-row; column; reverse-column
justify-content:设置子元素在主轴上的对齐方式
justify-content:flex-start flex-end center space-around space-between
align-items:设置子元素在侧轴上的对齐方式。

align-items:flex-start; 设置子元素在侧轴上的对齐方式。属性值可以是:
flex-start 从侧轴开始的方向对齐
flex-end 从侧轴结束的方向对齐
baseline 基线 默认同flex-start
center 中间对齐
stretch 拉伸
通过window.online来检测用户当前的网络状况,返回一个布尔值。另外:
window.online用户网络连接时被调用 window.offline用户网络断开时被调用
boostrap标签

1
<meta = http-equiv = "X-UA-Compatible" content = "IE=edge">

解释:设置浏览器的兼容模式版本,表示如果在IE浏览器下则使用最新的标准,渲染当前文档

1
<meta name = "viewport" content = "width=device-width,inital-scale=1.0,user-scalable=no" >

解释:声明当前网页在移动端浏览器中展示的相关位置,我们在做移动 web 开发时,就用上面这行代码设置 viewport。
视口的作用:在移动浏览器中,当页面超出设备时,浏览器内部虚拟的一个页面容器,将页面容器缩放到设备这么大,然后展示。
目前大多数手机浏览器视口:宽度都是980
此属性为移动端页面视口设置,上方代码设置的值,表示在移动端页面的宽度为设备的宽度,并且不缩放(缩放级别为1)
width:设置viewport的宽度 initial-scale:初始化缩放比例 minimum-scale:最小缩放比例 maximum-scale:最大缩放比例
user-scalable:是否允许用户手动缩放(值可以写成yes/no,也可以写成1/0)
C/S架构和B/S架构
是Client/Server这两个单词的首字母,指的是客户端和服务器
优点:
性能较高:可以将一部分的计算工作放在客户端上,这样服务器只需要处理数据即可。
界面酷炫:客户端可以使用更多系统提供的效果,做出更为炫目的效果。
缺点:
更新软件:如果有新的功能,就要推出新的版本。
不同设备访问:如果使用其他的电脑,没有安装客户端的话就无法登陆软件。
B/S架构:浏览器/服务器类型
优点:
更新简洁:如果需要更新内容了,对开发人员而言需要更改服务器的内容,对用户而言只需要刷新浏览器即可。
多设备同步:所有数据都在网上,只要能够使用浏览器即可登录使用。
缺点:
性能较低:相比于客户端应用性能较低,但是随着硬件性能的提升,这个差距在缩小。
浏览器兼容:处理低版本的浏览器显示问题一直是前端开发人员头痛的问题之一。移动设备兼容性较好,ie6已经越来越少人用了。
php代码执行方式:在服务器端执行,然后返回给用户结果,如果直接使用浏览器打开,则会是一串文本
意思:需要浏览器通过http请求,才能够执行php页面。
ajax:可以在不刷新页面的情况下,通过ajax方式去获取一些新的内容
ajax的核心是js对象:XMLHttpRequest
发送请求
open(method,url,async);
method 请求的类型 get或post
url:文件在服务器上的位置
async:true(异步) 或 false(同步)
send(string)仅用于post请求

1
2
3
4
5
xmlhttp.open("POST","ajax_test.php", true);

xmlhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");

xmlhttp.send("name=smyhvae&age=27");

注册onreadystatechange事件,每当readyState属性改变时,就会调用该事件
readyState:0请求未初始化 1服务器建立连接 2请求已接收
3请求处理中 4请求已完成
200 “OK” 404 “未找到页面”
jquery已经封装好

1
2
3
4
5
6
7
8
9
$.ajax({
url:"01.php",
data:"name=fox&age=18',
type:"GET",
success:function(){
},
beforeSend:function(){
}
})

同源策略:是浏览器的一种安全策略,指的是域名,协议,端口完全相同
jsonp 带补丁的json,本质是利用了

1
<script src = ""></script>

标签具有可跨域性,由服务端返回一个预先定义好的js函数的调用,并且将服务器数据以该函数参数的形式传递过来。

1
2
<!-- jsonp 就是 利用 src,实现的跨域 用的是 script标签 -->
<script type="text/javascript" src='http://192.168.141.137/2018-02-28/myData.php'></script>

BFC笔记

发表于 2019-06-15 | 分类于 css相关

formatting context是w3c css2.1规范中的一个概念,是页面中的一块渲染区域,并且有一套渲染规则,他决定了其子元素如何定位,以及和其他元素的关系和相互作用。最常见的便是BFC(块级格式化上下文)
是一个独立的渲染区域,只有block-level box参与,规定了内部的block-level box如何布局,并且与这个区域外部毫不相干,通俗的讲,bfc是一个容器,用于管理块级元素。
如何创建
float为left|right overflow为hidden|auto|display display为table-cell position为absolute 根元素
BFC布局规则:内部box在垂直方向,一个一个排列。
BFC的区域不会与float box重叠(利用这点可以实现自适应两栏布局)。
内部垂直方向距离有margin决定。属于同一个bfc的2个相邻box会发生margin重叠。
margin重叠3个条件:同属于一个bfc,相邻,块级元素
计算bfc高度时,浮动元素也参与运算。
bfc是页面上的一个独立容器,容器内部的子元素不会影响到外部。

公众号文章-面试经验-面试官需要什么样的人才

发表于 2019-06-14 | 分类于 面试相关

我在阿里做技术面试官的一些经验
言川 前端技术优选 3天前
戳蓝字「前端技术优选」关注我们哦!

我可能是在同龄人中做面试官经验比较丰富的,在某乎实习的时候就参与了前端的技术面试。后来在阿里以及另一家公司也面试过不少候选人,校招、社招、外包都有面试过。这里以一个面试官的角度来给大家谈谈在面试的时候怎么能给面试官留下更好的印象,更容易拿到大厂的Offer。为了不造成任何面试题泄露,这里我不会涉及到任何具体的面试题。

社招和校招的面试重点
社招其实和校招的面试重点有一些区别,以前端为例,社招更看重对前端技术体系的深入理解,以及解决问题的能力。比如对React的实现原理的理解,性能、安全等方面问题。为了避免泄题嫌疑这里就不举具体例子,具体大家可以自行搜索一下。

社招的通常简历中会有很多项目经历,面试官也会挑一两个项目问的比较深入,所以写在简历上的项目一定要自己有比较深的理解,不然面试的时候深入问一下答不上来就会非常不好。

相对的,校招更看重的其实是基本功和学习能力(或者说是潜力)。前端知识更多会考一些基础的JS和CSS,框架的原理方面不会问的很深,数据结构和算法、网络协议等会问的比较多,如果有靠谱的项目/比赛经历也会是考察重点。

还有比较敏感的学历问题,坦白说,如果一个HR/面试官要从成百上千的简历中初步筛选,是没有精力一个个认真看的,学历作为一个重要指标这个时候非常值得参考。而实际情况也是高学历的候选人大部分时候会明显强于低学历的候选人,即使一些人的简历看起来非常华丽。

大厂的面试流程
一般阿里腾讯这样的大公司,校招面试的流程是一轮统一笔试+三轮技术面试+一轮HR面试,如果对候选人的水平有争议,技术面试有可能会增加一轮,以2019年春招(实习生招聘)为例:

统一的笔试。

技术初面,一般这一轮都是由你将来同一个团队的比较资深的同事来面试

技术二面,一般是由你的未来主管面试

技术交叉面,一般是其他事业部的主管面试

HR终面,非技术问题

对应届生来说,大厂统一校招前,如果你想进哪一个,一定要关注一下他们的内推信息。内推一般都不用笔试,可以直接参加面试。而且一般内推和统一招聘是分开的,也就是内推挂了依然可以参加统一招聘,多一次机会。当然内推具体会不会影响统招,还是要让内推人确认下。

这里说一下实习生的春招和秋招,春招和秋招都是招第二年毕业的学生,区别是春招签的是实习Offer,秋招会签正式Offer,所以区别大家应该懂得(春招不一定能转正)。

社招一般也是三/四轮技术面+一轮HR面,不过社招很多时候会有一轮是级别比较高的人(总监级)人来面试。

面试前准备
首先在面试前一定要花一些时间进行准备,特别是常见的比较典型的面试题要准备一下,避免由于长时间没有接触某一类知识而在面试的时候发挥失常,比如计算机网络、常见的算法等。大部分面试问题都能在网上找到相同类型的,但是想全部找到原题一边不太现实,很多面试官都会有自己准备的题目。比如我在每一次大规模招聘开始的时候,都会花一些时间自己准备几个题目。

然后就是简历一定要认真写,重点突出,最好一页就能写完。三四页的长篇大论一般我都不会认真看。简历中写上去的东西,一定要诚实,不懂得别乱写。技术面试至少有一轮面试官会对着你的简历来问的,如果写的精通实际却解释不清楚,会给面试官非常差的印象,降低整个人的信用。所以简历中写道的项目,如果是很久以前的最好自己再回忆整理一下。

既然简历不能写的太长,那么哪些东西写上去会让面试官特别感兴趣呢?

大型比赛获奖

靠谱的项目/实习经历

开源项目经历

相对的,有一类简历写法会让人比较反感,就是把各种技术名词罗列出来写成一长列,全是熟悉/精通xxxx。不是不能这么写,而是不能写的特别多。没有哪个人是能全部都精通的,如果你这么写了,面试官随便挑两个问一问结果答得不好,那么会觉得你精通的都这个水平,其他肯定更不怎么样。

面试的时候的一些建议
面试官和候选人从来不是对立关系,作为面试官非常希望候选人特别优秀,最好面一个人就能直接通过,没有人想在低质量的候选人身上不断浪费时间。所以面试的时候一定要心态放好,不是去被刁难,而是平等的交流。这里说几个我认为比较重要的点:

诚实,确实完全不懂的就直接说不知道,不要装也不要编,面试官的水平一般远高于你,很多时候你以为忽悠过去了,其实面试官只是懒得跟你解释太多而已。

主动发问,如果解决一个问题的时候有一些疑问或者不懂的地方,可以主动问面试官,一般都会给你一些提示。甚至有的题目专门会留一个模棱两可的条件就是希望你能问出来的。发现并提出问题的能力也很重要

不怕错误,不要放弃,即使上一个题目完全错的离谱下一题也要认真对待

不要刻意套近乎,我就很反感上来一口一个“哥”,甚至打听面试官私人问题的

作为面试官,绝大多数人一般都是非常友好的。很多时候一些比较难的问题,都会先抛出一个相对简单的,候选人解决完之后会提出下一个要求,比如限制条件再解决这个问题,或者指出你的实现方式存在的问题然后问你怎么解决。好的面试题通常不是一上来就特别难,而是看起来不算太难,但是随着面试官逐步引导追问会变得越来越难。

很多时候一个复杂的问题在面试的时候本来就很难用一两句话描述清楚,这个时候面试官很可能会故意只进行粗略的描述,希望候选人在读题的时候能自己发现问题并提出来。如果你感觉一个面试题有模棱两可的地方,一定要主动提出来,能给面试官留下很好的印象。

面试的时候不要因为某个题目犯了严重错误就自暴自弃,后面不专心答题了。一个题目结束后调整好心态进行下一题。没有哪一个面试官会因为某一个题目而一票否决候选人,都是面试结束后根据候选人的综合表现来评价的。所以心态放好,即使个别题目错误的离谱,整体评价依然可以做到比较好。

面试结束的时候应该问点什么
一般面试快结束的时候,面试官都会问你有没有什么问题想问他的?很多人在这个时候手足无措不知道问些什么好。其实很多问题都可以问,比如:

团队的一些技术栈和所承担的业务

如果通过了未来的工作主要是做什么?

有师兄师姐带我么?公司有没有一些系统的培训?

甚至可以问一些学习的方法

但是切记有一个问题不要问,就是“我能通过这次面试么”,这个问题非常不适合在这里问,不通过的一般也不好当面说,能通过这一轮面试的一般也会其他候选人综合对比,或者有下一轮。

面试结果?
面试结束后,如果通过了,正常都会在一周内有回复的,如果等了一周也没有见到回复,那么最好问一下面试你的人,虽然八成是没戏了。如果没有通过面试也不要太灰心,可以加一下面试官的微信,或者让他帮你拉群。很多团队自己为了以后方面抢人,都会有一些招聘群,加进去方便下一次有机会的时候能获得第一手信息。

面试官面试的时候在干嘛
这个比较有意思,其实技术面试官都是比较资深的员工,大家平时都很忙的,很多时候面试其实是额外的任务。所以面试的时候,除了和候选人沟通之外,面试官有可能还在同时做自己的事。比如在线编程环节,沟通完题目要求之后,如果候选人埋头写题目不说话,我有时候就会去干别的事,15分钟后才回来看。所以即使写代码的时候最好和面试官保持沟通,说说自己的思路,不懂的地方提出来。不然面试官无聊了可能就去干别的去了。

还有很多面试官在开头会让候选人自我介绍,其实这个时候你只要保持镇定简单说下就好,他八成没听你说的话,正在抓紧时间看你的简历呢。所以我从来不会让人自我介绍,我会在面试开始前先花两分钟看完简历,标记重点要问的问题。甚至个别自己记不清的还要google一下。

最后说一句,无论多少人在说工作难找,优秀的人才总是每个公司都要抢的。

html,css restful相关

发表于 2019-06-13 | 分类于 html相关 , css相关

h1标签有什么作用:
正确答案:给文本增加主标题的语义
错误答案:给文字加粗,加黑,放大
标记:

称为开始标记 ,

称为结束标记,也叫标签。每个标签都规定好了特殊的含义。
元素:

内容

称为元素.
属性:给每一个标签所做的辅助信息。
xhtml: 符合XML语法标准的HTML。
dhtml:dynamic,动态的。javascript + css + html合起来的页面就是一个dhtml。
http:超文本传输协议。用来规定客户端浏览器和服务端交互时数据的一个格式。SMTP:邮件传输协议,ftp:文件传输协议。
避免乱码:我们用meta标签声明的当前这个html文档的字库,一定要和保存的文件编码类型相同,否则乱码(重点)
html结构
1.声明部分:主要作用是用来告诉浏览器这个页面使用的是哪个标准。<!doctype html>是HTML5标准。
2.head部分:将页面的一些额外信息告诉服务器。不会显示在页面上。
3.body部分:我们所写的代码必须放在此标签內。
1.文档声明头
<!DOCTYPE> 文档声明头 DocType Declaration 简称DTD,此标签可告知浏览器文档使用哪种 HTML 或 XHTML 规范。
2.头标签
title base meta body link

:指定整个网页的标题,在浏览器最上方显示。

:为页面上的所有链接规标题栏显示的内容定默认地址或默认目标。

:提供有关页面的基本信息

:用于定义HTML文档所要显示的内容,也称为主体标签。我们所写的代码必须放在此标签內。

:定义文档与外部资源的关系。
meta中设置description 即百度搜索结果,就能显示这些语句,表示引擎优化SEO
文本级标签p span a b i u em 里面只能放文字,图片,表单元素
容器级标签 div h系列,里面能放任何东西
div 把标签中的内容当做一个块来对待,必须独占一行
span 是不换行的
center 代表是一个标签,而不是一个属性值,只要是这个标签的内容,都会居中于浏览器
pre 预格式化标签 含义:将保留其中的所有的空白字符(空格、换行符),原封不动的输出结果(告诉浏览器不要忽略空格和空行) 说明:真正排网页过程中,

标签几乎用不着。但在PHP中用于打印一个数组时使用。
锚链接:指定超链接起一个名字 作用是在本地或者其他页面的不同位置进行跳转。
列表标签
    unordered list 表示无序列表 没有1 2 3 只有点
    有序列表
      有1.2.3标签
      定义列表dl dl的子元素只能是dt或者dd dt表示标题,dd表示内容
      表格table 表格由行组成,行由列组成
      表单标签
      用于与服务器的交互,表单就是收集用户信息的,就是让用户填写的、选择的。
      属性:
      name:表单的名称,用于JS来操作或控制表单时使用;
      id:表单的名称,用于JS来操作或控制表单时使用;
      action:指定表单数据的处理程序,一般是PHP,如:action=“login.php”
      method:表单数据的提交方式,一般取值:get(默认)和post
      get提交和post提交的区别:

GET方式: 将表单数据,以”name=value”形式追加到action指定的处理程序的后面,两者间用”?”隔开,每一个表单的”name=value”间用”&”号隔开。 特点:只适合提交少量信息,并且不太安全(不要提交敏感数据)、提交的数据类型只限于ASCII字符。

POST方式: 将表单数据直接发送(隐藏)到action指定的处理程序。POST发送的数据不可见。Action指定的处理程序可以获取到表单数据。 特点:可以提交海量信息,相对来说安全一些,提交的数据格式是多样的(Word、Excel、rar、img)。

Enctype: 表单数据的编码方式(加密方式),取值可以是:application/x-www-form-urlencoded、multipart/form-data。Enctype只能在POST方式下使用。

Application/x-www-form-urlencoded:默认加密方式,除了上传文件之外的数据都可以
Multipart/form-data:上传附件时,必须使用这种编码方式。

css部分

html的单位只有一种,那就是像素px,所以单位是可以省略的,但是css不一样,css的单位是必须写的,因为它没有默认单位
绝对单位
1 in = 2.54 cm = 25.4 mm = 72pt = 6 pc
in 英寸 pt 点points 或者叫英镑 pc 皮卡
相对单位: px:像素
em:印刷单位相当于12个点
%:百分比,相对周围的文字的大小
单行文本垂直居中
行高 = 盒子搞 默认文字是居中显示的 在行元素内
比如行高24px 字体大小14px 所以padding会计算出来是5px
font-family的设置
font-family: “Times New Roman”,”微软雅黑”,”宋体”;
英语字体放在最前面,所有的中文,就不能匹配英文字体,匹配后面的中文字体
行高可以用百分比,表示自豪的百分之多少 一般是大于100%的 因为行高一定大于字号
滤镜:让图片变成灰度图的效果

常见背景属性有如下几种
background-color:#ff99ff;background-image:url(image/2.gif)
background-repeat:no-repeat 设置背景图片是否重复以及如何重复 默认平铺满
no-repeat 不要平铺 repeat-x 横向平铺 repeat-y 纵向平铺
background-color属性的设置 red rgb(255,0,0) #ff0000
css和html结合的3种方式:行内样式表 内嵌样式表 外部样式表
外部引入 必须卸载

1234…6
KevinSwift

KevinSwift

58 日志
28 分类
64 标签
© 2020 KevinSwift
由 Hexo 强力驱动
|
主题 — NexT.Pisces v5.1.4