My Little World

learn and share


  • 首页

  • 分类

  • 标签

  • 归档

  • 关于
My Little World

指令

发表于 2018-12-22

指令的职责是,当表达式的值改变时,将其产生的连带影响,响应式地作用于 DOM

简单指令

v-if 条件指令,绑定值为真时构建DOM,假时bu构建或者删除已存在DOM

1
2
3
4
5
6
7
8
9
10
<p v-if="seen">现在你看到我了</p>

export default {
name: 'vpc',
data () {
return {
seen: true
}
}
}

v-for 循环指令,根据绑定值,循环输出DOM元素

1
2
3
4
<div v-for="(item, index) in modalFooter">
<button @click="customFunc(item.Func)" type="button" class="btn btn-primary" v-if='item.name'>{{item.name}}</button>
</div>
//根据数据modalFooter数组循环出多个数组

v-on 监听 DOM 事件的指令,触发事件的回调函数放在method中,可以简写成‘@事件名’

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<div id="app-5">
<p>{{ message }}</p>
<button v-on:click="reverseMessage">逆转消息</button>
//或者 <button @click="reverseMessage">逆转消息</button>
</div>

var app5 = new Vue({
el: '#app-5',
data: {
message: 'Hello Vue.js!'
},
methods: {
reverseMessage: function () {
this.message = this.message.split('').reverse().join('')
}
}
})

v-model 双向绑定指令,绑定的值在页面更改后js可以及时更改,js改变该值后,页面能马上渲染响应

1
2
3
4
5
6
7
8
9
10
11
<div id="app-6">
<p>{{ message }}</p>
<input v-model="message">
</div>

var app6 = new Vue({
el: '#app-6',
data: {
message: 'Hello Vue!'
}
})

v-bind 绑定HTML标签属性,响应式地更新 HTML 特性 缩写形式” :属性名=’响应函数名’ “

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<div id="app-2">
<span v-bind:title="message">
//或者<span :title="message">
鼠标悬停几秒钟查看此处动态绑定的提示信息!
</span>
</div>

var app2 = new Vue({
el: '#app-2',
data: {
message: '页面加载于 ' + new Date().toLocaleString()
}
})
//在这里,该指令的意思是:“将这个元素节点的 title 特性和 Vue 实例的 message 属性保持一致”

自定义指令

My Little World

文件结构

发表于 2018-12-22

构建

使用命令行构建

1
2
3
4
5

npm install --global vue-cli //全局安装vue命令
vue init webpack my-project //使用vue命令构建名为my-project的项目
cd my-project //进入项目所在文件夹
npm run dev //运行项目

文件结构

.
├── build/                      # webpack config files
│   └── ...
├── config/
│   ├── index.js                # main project config
│   └── ...
├── src/
│   ├── main.js                 # app entry file
│   ├── App.vue                 # main app component
│   ├── components/             # ui components
│   │   └── ...
│   └── assets/                 # module assets (processed by webpack)
│       └── ...
├── static/                     # pure static assets (directly copied)
├── test/
│   └── unit/                   # unit tests
│   │   ├── specs/              # test spec files
│   │   ├── eslintrc            # config file for eslint with extra settings only for unit tests
│   │   ├── index.js            # test build entry file
│   │   ├── jest.conf.js        # Config file when using Jest for unit tests
│   │   └── karma.conf.js       # test runner config file when using Karma for unit tests
│   │   ├── setup.js            # file that runs before Jest runs your unit tests
│   └── e2e/                    # e2e tests
│   │   ├── specs/              # test spec files
│   │   ├── custom-assertions/  # custom assertions for e2e tests
│   │   ├── runner.js           # test runner script
│   │   └── nightwatch.conf.js  # test runner config file
├── .babelrc                    # babel config
├── .editorconfig               # indentation, spaces/tabs and similar settings for your editor
├── .eslintrc.js                # eslint config
├── .eslintignore               # eslint ignore rules
├── .gitignore                  # sensible defaults for gitignore
├── .postcssrc.js               # postcss config
├── index.html                  # index.html template
├── package.json                # build scripts and dependencies
└── README.md                   # Default README file
My Little World

vue对象属性

发表于 2018-12-22

el

其值为vue模板挂载ID,用于标识vue的APP template挂载在index.html的什么位置

data

method

计算属性computed

通过{ {}}}插值的时候,可以在大括号里面添加一个简单的计算表达式,从而将计算结果插入,但是对于复杂的计算,需要执行多个计算表达式时不能放在大括号里面的,为方便绑定,在computed属性中定义计算属性A,A是一个函数用到变量b,然后将该A属性插入,从而实现相关值b变化,插入值A随之响应的效果

相当于计算属性因为依赖项改变而执行计算,将计算结果插入

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
例
<p>Original data: "{{ value }}"</p>
<p>Computed result: "{{ doubleValue }}"</p>
<button @click='changeValue'><button>

export default {
data() {
value: 10
},
computed: {
doubleValue: function() {
return this.value * 2
}
},
method: {
changeValue: function() {
this.value++
}
}
}
//当value 变化时,doubleValue通过运算将结果插入

与method区别

也可以在大括号里面调用method中定义的方法,达到计算响应

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<p>{{doubleVlue()}}</p>
<button @click='changeValue'><button>
export default {
data() {
value: 10
},
method: {
doubleValue: function() {
return this.value * 2
},
changeValue: function() {
this.value++
}
}
}

当计算属性函数依赖的值不发生变化时,每次调用计算属性都会去取最后一次运算的结果,即读取缓存的结果

比如有一个计算属性A需要遍历一个庞大的数组然后得到一个结果,而这个结果则用于其他计算,这样我们就不需要每次去运算A属性函数得到结果,直接读取缓存结果即可

但如果属性A结果的得来是通过运行method方法,那么每次调用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
38
39
40
41
42
43
44
//computed方式
<p>Original data: "{{ value }}"</p>
<p>Computed result: {{ double }}</p>
<button @click='changeValue'><button>

export default {
data() {
value: 10
},
computed: {
double: function() {
return this.value + this.doubleValue
},
doubleValue: function() {
console.log('double') //只打印一次
return 2
}
},
method: {
changeValue: function() {
this.value++
}
}
}
//method方式

<p>Original data: "{{ value }}"</p>
<p>Computed result: {{ value + doubleValue() }}</p>
<button @click='changeValue'>1234<button>

export default {
data() {
value: 10
},
method: {
doubleValue: function() {
console.log('double') //value 改变一次,打印一次,即函数会被执行一次
return 2
},
changeValue: function() {
this.value++
}
}
}

计算属性还可以设置getter和setter

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
computed: {
fullName: {
// getter
get: function () {
return this.firstName + ' ' + this.lastName
},
// setter
set: function (newValue) {
var names = newValue.split(' ')
this.firstName = names[0]
this.lastName = names[names.length - 1]
}
}
}
//给fullName设置值的时候,比如fullName = 'John Doe' 时,setter 会被调用,firstName 和 lastName 也会相应地被更新

watch

定义某个变量发生变化时需要执行的函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<p>Original data: "{{ value }}"</p>
<p>Computed result: {{ result }}</p>
<button @click='changeValue'>1234<button>

export default {
data() {
value: 10
result: 0
},
watch: {
value: function() {
this.result +=10
}
},
method: {
changeValue: function() {
this.value++
}
}
}
//当value发生变化的时候,就会执行watch绑定的函数,从而可以让result发生响应

对比computed属性,假设一个结果需要依赖多个变量,如果使用watch方法则需要定义多个响应函数,而且响应函数是重复的,而如果使用computed属性则只需要定义一次即可

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
例
//computed方式
<p>Original data: "{{ value }}"</p>
<p>Computed result: {{ result }}</p>
<button @click='changeValue'>1234</button>
export default {
data() {
value: 10,
val:1
},
computed: {
result: function() {
return this.val + this.value
}
},
method: {
changeValue: function() {
this.value++
}
}
}
//watch方式
<p>Original data: "{{ value }}"</p>
<p>Computed result: {{ result }}</p>
<button @click='changeValue'>1234</button>

export default {
data() {
value: 10,
val:1
},
watch: {
value: function() {
this.result = this.val + this.value
},
val: function() {
this.result = this.val + this.value
}
},
method: {
changeValue: function() {
this.value++
}
}
}

生命周期钩子函数

components

My Little World

flex-drection属性使用

发表于 2018-12-22

在display:flex基础上使用flex-direction,可用于多子模块布局

flex-direction可以为四个值

row:水平并行排列在左侧

row-reverse:水平并行排列在右侧,顺序与书写顺序相反,最前的在最右边

column:垂直排列在上方,相当于display:block状态下模块默认布局

column-reverse:垂直排列在下方,顺序与书写顺序相反,最前的在最下边

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
<!doctype html>
<html>
<head>
<style>
#main1
{
width:200px;
height: 300px;
border:1px solid black;
display: flex;
flex-direction:row;
}
#main2
{
width:200px;
height: 300px;
border:1px solid black;
display: flex;
flex-direction:row-reverse;
}
#main3
{
width:200px;
height: 300px;
border:1px solid black;
display: flex;
flex-direction:column;
}
#main4
{
width:200px;
height: 300px;
border:1px solid black;
display: flex;
flex-direction:column-reverse;
}
</style>
</head>
<body>
<h4>This is an example for flex-direction:row(default)</h4>
<div id="main1">
<div style="background-color:red;">RED</div>
<div style="background-color:lightblue;">BLUE</div>
<div style="background-color:lightgreen;">GREEN</div>
</div>
<h4>This is an example for flex-direction:row-reverse</h4>
<div id="main2">
<div style="background-color:red;">RED</div>
<div style="background-color:lightblue;">BLUE</div>
<div style="background-color:lightgreen;">GREEN</div>
</div>
<h4>This is an example for flex-direction:column</h4>
<div id="main3">
<div style="background-color:red;">RED</div>
<div style="background-color:lightblue;">BLUE</div>
<div style="background-color:lightgreen;">GREEN</div>
</div>
<h4>This is an example for flex-direction:column-reverse</h4>
<div id="main4">
<div style="background-color:red;">RED</div>
<div style="background-color:lightblue;">BLUE</div>
<div style="background-color:lightgreen;">GREEN</div>
</div>
</body>
</html>
My Little World

数组的map和reduce

发表于 2018-12-22

数组的map方法

1
2
3
4
5
6
7
let arr = [1,2,3,4,5];
let arr1 = arr.map(function(val,index,arr){
console.log(val,index,arr)
return val+1
})
console.log(arr1)//[2, 3, 4, 5, 6]
console.log(arr) //[1, 2, 3, 4, 5]

在map中可以传递一个函数,数组的每一项作为参数调用这个函数,然后返回根据该数组项得到的结果,每一个数组项返会一个结果,从而组成新的数组

函数的参数有三个,第一项为数组按序传进的一个值,该值的index和数组本身

整个结果产生新数组,原来数组不变

数组的reduce 方法

1
2
3
4
5
6
7
8
9
10
11
12
13
例1.
let arr = [1,2,3];
let result = arr.reduce(function(preresult,item){
return preresult += item;
},0)
console.log(result) //6

例2.
let result4 = arr.reduce(function(preresult,item){
preresult.name += item;
return preresult
},{name:0})
console.log(result4); //{name:6}

reduce 用于对数组每一项进行累计计算,每一项计算结果作为参数参加数组下一项的计算,最终返回计算结果

例1中单纯对数组每一项进行叠加处理,返回叠加结果
例2同样进行叠加只是叠加结果放在对象中返回

reduce(callback(),initval)

需要两个参数,一个是用于累计计算的callback函数,一个是初始值,见上两例

callback()函数有四个参数依次为:

preVal (上一次调用回调返回的值,或者是提供的初始值(initialValue))

currentValue (数组中当前被处理的元素)

index (当前元素在数组中的索引)

array (调用 reduce 的数组)

初始值会在第一次调用时当作回调函数callback的第一个参数使用

希望返回值是什么类型的数据,初始值就要设置为什么样的类型,callback返回值也是该类型;或者说是在这里设置返回值的类型

整个处理过程就是拿初始值initval和数组第一个值在callback里面进行处理,返回结果result,result当作callback的preval参数和数组第二个元素传入callback在处理,直到数组全部元素被处理完,返回一个最终处理结果

高级应用
对对象数组元素进行累计计算

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
var reducers = {  
totalInEuros : function(state, item) {
return state.euros += item.price * 0.897424392;
},
totalInYen : function(state, item) {
return state.yens += item.price * 113.852;
}
};

var manageReducers = function(reducers) {
return function(state, item) {
return Object.keys(reducers).reduce(
function(nextState, key) {
reducers[key](state, item);
return state;
},
{}
);
}
};

var bigTotalPriceReducer = manageReducers(reducers);
var initialState = {euros:0, yens: 0};
var items = [{price: 10}, {price: 120}, {price: 1000}];
var totals = items.reduce(bigTotalPriceReducer, initialState);
console.log(totals);
//{euros: 1014.08956296, yens: 128652.76}

该例的目的是将对象数组items的元素属性price进行不同处理操作然后将结果分别保存到结果对象的属性中

处理的关键是manageReducers返回的作为items callback的函数bigTotalPriceReducer,

处理思路是items每用一个元素调用callback时,callback的处理过程是将这个元素作为参数调用reducers 对象里面设置的每一个处理函数,

调用reducers处理函数的过程同样使用一个reduce方法进行处理

Object.keys(obj)方法返回对象键值组成的数组

当items的元素参加完reducers所有处理函数后,返回的结果参加下一个元素的计算最终返回结果

扩展:

1.在reduces中设置对items不同属性的计算,从而得到不同属性的结算结果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var reducers = {  
totalInEuros : function(state, item) {
return state.euros += item.p1;
},
totalInYen : function(state, item) {
return state.yens += item.price * 113.852;
}
};

var bigTotalPriceReducer = manageReducers(reducers);
var initialState = {euros:0, yens: 0};
var items = [{price: 10,p1:1}, {price: 120,p1:1}, {price: 1000,p1:1}];
var totals = items.reduce(bigTotalPriceReducer, initialState);
console.log(totals);
//{euros: 3, yens: 128652.76}

2.计算对象数组属性值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var manageReducers = function(state, item) {
return Object.keys(item).reduce(
function(nextState, key) {
state[key] +=item[key];
return state;
},
{}
);
};

var initialState = {price:0, p1: 0};
var items = [{price: 10,p1:1}, {price: 120,p1:1}, {price: 1000,p1:1}];
var totals = items.reduce(manageReducers, initialState);
console.log(totals);
//{price: 1130, p1: 3}

参阅资料

My Little World

js 知识点 一

发表于 2018-12-08

1.< script > 标签几个属性

async :立即异步下载,因此不保证能够按指定的先后顺序执行,但会在load事件前,DOMContentLoad前后执行
defer :延迟执行,也不保证按顺序执行,在DOMContentLoad前后执行
src :外部文件链接
charset :src指定代码的字符集,防止出现乱码
language :已废弃,表示脚本语言,
type :值为脚本语言内容类型(MIME),language替代属性,服务器传递过来类型为application/x-javascript需要注意,一个是可能导致脚本被忽略,另一个是可能触发浏览器XHTML标准模式;另外外链文件不是js文件时,一定要设置该值

2.js 代码执行过程

包括两个部分一个是编译,或者叫预处理过程,一个是执行
编译过程 首先会创建一个全局作用域,然后进行词法分析,
词法分析过程会涉及到变量提升和函数声明提前处理,
即词法分析到变量声明会先判断当前域到全局域有没有该变量声明,如果有,就会将该变量挂到该作用域的对象上,
如果到全局域都没有则以全局为背景,新建该变量,并为其分配内存,
对于基本类型,变量中会保存它的值,对于对象,变量中会保存值所在内存的内存地址,
在一定场景下,这里就相当于发生了变量提升,把变量从局部提升到了全局,或者将声明提前到了使用之前,
避免变量提升可以使用es6的let 关键字或者使用立即执行实现变量声明使用,但要注意使用let重复声明会报错,var 会同名覆盖;
当遇到函数声明时,会直接按声明顺序,将声明提前到代码顶端,
重复声明 的函数会被后者覆盖,
如果变量名与函数名相同,则无论原来词法位置如何,先将函数声明提前到顶端,不再进行变量声明,变量名在哪赋值,则原函数在哪被覆盖,
覆盖之前调用使用原函数
提前之后会为函数创建作用域,
这时创建的作用域就是函数的 【【scope】】属性,保存着指向父域到全局域的指针
(指针就是指向活动对象的一个地址,全局域浏览器环境就是windows,nodejs环境就是global)
将来执行时会根据此指针建立作用域链,作用域链就是指针列表,指向不同层级作用域的内存,在里面取值
以上就基本上是编译过程,除了一些特定的编译规则,编译过程还会会使用大量技巧进行优化提升编译速度
但在使用js时,需要注意try-catch,with和eval三个语法关键字的使用,因为在使用它们时,会创建块级作用域,
破坏掉编译器原有的创建管理作用域的规则,在编译时,编译器也就不会对其中的代码进行优化,最终导致性能变差

运行过程,基本就是在运行函数,函数在运行时会首先根据【【scope】】属性拿到父域到全局的指针,创建指针列表即作用域链,
然后创建函数执行的局部作用域,将函数中声明的变量挂到局部作用域活动对象上,然后将局部作用域指针推向作用域链前端,
在用到变量值时,会根据作用域链依次查找取值
函数执行结束后,局部活动对象被销毁,作用域链被销毁,进行垃圾回收
但是对于声明在一个函数内部的函数来说,这个声明的函数在声明时,就会包含其父域的活动对象,
因此在外部使用该函数时,可以访问到其父域的变量,实现了父域访问子域变量,延长了变量的使用范围,也就是常见的闭包现象,
缺点就是闭包的函数执行完毕后,因为本身【【scope】】会指向父域的活动对象,所以父域的活动对象始终不会被回收,除非闭包函数被销毁
从而有可能造成内存泄露,为什么说有可能,因为父活动对象占的内存其实是比较小的,造成内存泄露的真正原因是使用闭包易造成循环引用,
尤其是闭包作用域中保存dom结点时,如果是在IE中,dom和bom都是以C++的COM对象保存的,垃圾回收机制是技术策略,
因此循环引用的话,永远都不会被回收

补充,对于未以分号结尾的语句,会采用能合就合的原则,即,会尝试和下一行语句合并执行,如果能合并执行就合并执行,
不能合并执行就在中间加分号再执行,如果再执行不了就会报错
好处就是对于条件判断语句可进行一行一行判断
坏处就是如果下一行以大括号开头,上一行语句就会变成函数,导致出现意想不到的结果
两个例外,
对于return,break,continue语句不会做尝试合并;
对于++,–自增自减符后没有分号,上一行也没分号情况,自增自减会和下一行合并,上一行自行添加分号

以上即是我所了解的js运行机制

3.关于对象继承

3.0 new 操作符调用构造函数 执行过程
1.创建或者构造一个全新的对象
2.将构造函数的作用域赋给这个新的对象,
3.执行构造函数 (为这个新对象添加属性) ,第二,三步相当于func.call(newobj)
4.如果构造函数没有返回值或返回值非对象,则返回新对象,否则返回构造函数return的对象

3.1 继承的6种方式及优缺点
第一种原型链方式,子类的原型对象指向父类的实例
缺点
给原型添加方法必须要在替换原型的语句之后;
不能实现多继承(原型指向多个父对象);
所有属性共享
无法传递参数到父类进行初始化
第二种借助构造函数,在子类构造函数中使用call或者apply执行父类构造函数
优点
可以实现多继承
可以传递参数
方法属性不共享
缺点
只能继承构造函数中属性,不能继承原型上方法,不能复用方法
实例仅为子类实例,不是父类实例
第三种组合继承,以上两组结合在一起,两种方式都执行
缺点
要调用两次父类构造函数,影响性能
实例属性和原型属性各占一份,同名覆盖机制,重复占内存,没必要
第四种原型式继承,借助object()或者object.create()函数,缺点同原型链方式

1
2
3
4
5
function object(o){
function F(){}
F.prototype = o;
return new F();
}

第五种寄生式继承,利用原型式继承和增强对象过程的封装函数创建子类,缺点同原型链方式
第六种寄生组合式继承,保留借助构造函数部分,原型部分功能借助中间函数处理,
中间函数借助object拿到父类prototype,给到子类的prototype,从而完美解决组合继承的缺点

1
2
3
4
5
6
function inheritPrototype(subType,superType){
var prototype = object(superType.prototype)
prototype.constructor = subType
subType.prototype = prototype
}
subType.prototype.__proto__ = superType

3.2 es6 使用class extend实现继承
使用class声明构造函数时,本来挂在this上的属性,放在constructor()函数里面执行初始化,
挂在prototype上的方法直接放在class里面声明

使用extend继承时,需要在constructor里面先执行super函数才能使用this关键字,
增强方法同样直接在class中和constructor并列声明,相当于挂在prototype上

注意super函数只能在consructor中运行;super用作对象在constructor中使用时,相当于this,
添加属性会添加在当前对象上,运行函数时会调用继承的父类的方法

还有就是class extend继承null和 什么也不继承是,相当于继承Function.prototype
继承Object时,子类就相当于object 的复制,子类实例就是object实例

4.关于this 四种使用场景

普通函数执行,指向全局作用域
对象属性方法调用,指向调用对象
call,apply中强制绑定对象,this执行绑定的对象
构造函数中this指向构造的新对象
(箭头函数中this,指向词法作用域的父域)

5.js文件位置

放html底部原因:
下载解析执行过程是阻断式的,会停止页面渲染,造成白屏,影响用户体验;
另外JS中如果有对dom的操作,页面中还没有dom,获取不到,是不符合逻辑的,会报错

哪些js功能文件可以放顶部:
与css相关的js,比如rem单位的换算,需要根据根结点进行设置
使用的框架需要在根结点将浏览器支持的样式罗列出来

6.什么情况下用内部文件,内部文件比外部文件好处在哪?

内部文件相比外部文件最大好处就是性能提升,因为访问外部文件时,不管文件大小都会造成一次网络请求链接,请求服务器,下载文件,
解析文件,除了文件本身代码外,还要处理文件头文件尾的请求,增加了链接数,从而造成性能影响
对于功能短小精悍,不会被到处复用的js代码不适合采用外部文件,应该采用内部文件写法,尤其对手机端页面有性能提升

7.开发过程避免缓存方法

在浏览器开启禁用缓存的模式
手动清缓存 ctrl+shfit+del
引用的文件名添加随机数,浏览器根据文件名不同,就会重新获取资源更新缓存

8.使用严格模式弊端及解决办法

在代码压缩时,’use strict’ 这一行可能不在位于第一行,
或者后续代码不需要在严格模式下执行,被压缩在了严格模式范围内,导致了全部以严格模式执行

解决办法就是,将需要严格模式执行的代码放在匿名函数中,形成代码块,在函数中使用严格模式

9.立即执行函数好处

避免变量污染:有些变量仅在小功能内使用,将小功能封装起来,就可以避免这些变量暴露到全局,
另外函数本身没有函数名,不会增加全局变量
提升性能:功能所需变量全都在函数内时,查找变量快
有利于压缩:一部分代码执行需要用到的变量变量名太长,将这段代码封装成立即执行函数,将长变量名以参数形式传进去
避免全局命名冲突:一段代码需要用到两个代表不同功能但名称相同的变量,可以将该段代码封装成立即执行函数,
将其中一个变量以参数形式传递进来,达到换名的目的
保存闭包状态:循环执行异步代码时,将异步代码用立即执行函数包裹,函数内可保存本次循环的状态
改变代码运行顺序:umd,通用模块规范,function(fn){fn()}()

10.变量类型

根据当前变量的值的类型确定
如果想要进行标记,方法有三种
初始化时指定相应类型值
使用匈牙利标记法,用单字母表示类型,添加到变量命中,例sName 代表string类型
使用注释,变量声明时,在旁边添加注释

11.null vs undefined

转数字时,null –>0;undefined–>NaN
undefined可以当做windows对象上的一个属性,null不行

12. 类型转换

基本类型包括,undefined,null,boolean,string,number

基本类型 —> boolean Boolean(someval) 相当于 !!someval
undefined,null,NaN,’’,+0,-0 —> false
其他 —> true

基本类型 —> string String(someval)相当于 someval+’’
一般情况直接加引号
[] —> ‘’
{} —> ‘[object object]’

基本类型—>number + someval 相当于 Number(someval)
undefined,{} —> NaN
false, null,’’,[],—> 0
true —> 1
‘123’ —> 123
‘abc’ —> NaN
[]—> toString —> ‘’ —> 0
{} —> valueOf —> {} —> toString —> ‘[object object]’ —> NaN

基本类型 —>对象
undefined,null —> {}
true/123 —> {initval:true/123}
‘abc’ —> {initval:’abc’,length:3,0:’a’,1:’b’,2:’c’}

对象 —>基本类型

关于–对象分类:
内部对象(错误对象;常用对象:Boolean,Number,String,Object,Array,Function,Date,Exec;内置对象:Math,global,Json)
宿主对象:windows,document
自定义对象

关于–属性访问
obj.someprop—>检查obj是不是null/undefined—>是|不是—>报错|是不是Object,不是的话转object—>取值
obj[someval]—>检查obj是不是null/undefined—>是|不是—>报错|是不是Object,不是的话转object—>计算someval拿到string—>取值

Boolean —>true
Number —>基本类型转的|{}/{a:1}|Date—>相应值|NaN|时间戳
Array.toString:数组每一项转字符串
Function.toString:原代码字符串形式
Date.toString:日期和时间组合形式
Exec.toString:正则字符串形式

运算转换

Number()参数不能有非数字
parseInt()参数只能为字符串,非字符串会进行强制转化字符串,可含非数字,但不能以非数字开头
一元操作符对任何数据类型有效,得到数字

+二元运算侧重转字符串,然后进行字符串拼接
其中一个为字符串或者两个都是对象时,转字符串拼接
undefined,null,Boolean,数字混合运算+时,会被转数字再计算
{}为第一个运算值时,会被当做函数结束,不参与计算

1
2
3
4
5
6
7
8
9
10
11
12
null + null --> 0
undefined + null --> NaN
[] + [] --> ''
1 + [1,2] --> '11,2'
1 + {a:1} --> '1[object object]'
{a:1} + 1 --> 1
{} + {} --> NaN
({}) + {} --> '[object object][object object]'
[] + {} --> '[object object]'
{} + [] --> 0
var a = {}
a + a -->'[object object][object object]'

*/- 转数字,进行相减,如果不能转数字,返回NaN

>/< 侧重转数字
string < string 字典比较
非字符串<非字符串/字符串 都转数字然后比较

string == number 字符串转数字
boolean == 其他类型 二者转数字然后比较
null == undefined —>true undefined和null只与对方和自己==比较时为true,其他均为false
null === undefined —>false
非对象 == 对象 与数字比较object转数字,与字符串比较二者转数字再比较

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
'0' == null  //false
'0' == undefined //false
'0' == false //true
'0' == NaN //false
'0' == 0 //true
'0' == '' //true

false == null //false
false == undefined //false
false == NaN //false
false == 0 //true
false == '' //true
false == [] //true
false == {} //false

'' == null //false
'' == undefined //false
'' == NaN //false
'' == 0 //true
'' == [] //true
'' == {} //false

0 == null //false
0 == undefined //false
0 == NaN //false
0 == [] //true
0 == {} //false

[] == ![]

&&和|| 计算结果根据短路原则判断到了哪里,返回最后一个进行判断的值

运算符优先级
属性访问.
一元操作符(+,-,++,–)
二元操作符(+-*/)
比较(>,<)
相等(==,===,!=)
与&&,或||
三目运算符
赋值

运算符结合性
除了一元操作符,三目运算符和赋值是右结合,其他都是左结合

减少小数计算误差
尽量不使用小数进行比较或运算
转整数计算,再转回相应位数小数
使用toFixed()四舍五入
两个情境需要重复计算时,保证前后书写顺序

13. 数组相关方法

arrmethod

14.字符串相关方法

strmethod

15.日期相关方法

一共 33个
set/get(UTC)FullYear,Month,Date,Hours,Minutes,Seconds,Millseconds
set/get Time
get(UTC) Day
getTimezoneOffset

16. Math三个舍入方法

Math.ceil:比值大的最小整数
Math.round:四舍五入
Math.floor:比值小的最大整数

17. setInterval 注意问题

累积效应
代码执行时间大于间隔时间,后续调用会进行累积,累积会在短时间内连续触发

当用于动画时,因与显示器刷新频率不统一会造成视觉卡顿,解决办法如下:
一种是使用CSS3创建动画,根据显示器刷新执行动画
另一种是使用 requestAnimationframe(function(){})函数,也是在显示器刷新时执行
可以解决CSS3无法实现的,例如滚动控制等效果

18. 关于DOM

document 三个属性
url:地址栏中URL
domain:域名,跨域域名 X;父域名到子域名 X;
referer:上一页URL,可在跳转时,判断与当前页是否在同一域,是的话,就可以back,否则 location.href其他页面
dom.getAttribute(‘style’),得到样式字符串
dom.style 得到到样式对象
dom.getAttribute(‘onclick’) ,得到代码字符串
dom.onclick 得到函数对象

动态合集
使用时可能会造成死循环
使用框架如Jquery获取的合集不具有动态性
使用 queryselect(all)()获取到的也是静态合集

动态合集生成原理:
浏览器通过DOM树预先缓存起来,获取时,浏览器会通过缓存直接注册,创建一个变量返回

静态合集生成原理:
获取标识是一个CSS选择器,浏览器会先去解析字符串,判断是一个CSS选择器,
分析选择器并创建一个选择器结构,浏览器根据DOM树创建一个静态文件,即DOM树的一个快照
然后拿选择器和快照进行对比,符合选择器就放到合集中,知道整个快照对比完,再把合集的快照返回

19. 事件

绑定方式

直接通过HTML属性绑定
缺点
有可能响应函数还未被解析就被触发
事件名和回调1对1,修改繁琐
响应执行时,作用域为全局,不同浏览器解析规则不同,造成某些对象无法访问

使用dom属性绑定
冒泡阶段执行
缺点
只能绑定一个响应,后续赋值会被覆盖

IE attachEvent/detachEvent绑定/解绑
冒泡阶段执行
绑定多个时按按绑定顺序的逆序执行

addEventListener()/removeEventListener()绑定/解绑
第三个参数为对象时,passive属性为true时,会针对touchstart,touchend等特定事件通过开启两个线程,
一个执行浏览器默认行为,一个执行JS进行优化

事件优先级
浏览器在绑定事件而不是JS在绑定事件

1.html标签绑定事件会被dom属性事件覆盖
2.html标签优先执行,即使被属性事件覆盖,则执行被覆盖的属性事件
3.仅有监听事件和属性事件时,按绑定顺序执行,即事件对象的冒泡事件可能会在捕获事件之前执行

event对象属性
curentTarget:响应函数绑定的对象
target:发生事件的对象

My Little World

一些jQuery知识

发表于 2018-12-08

1.jquery对象与Element对象转换

1
2
3
4
5
6
7
//Element对象转jquery对象
var domObj = document.getElementById('id')
var $obj = $(domObj)//jQuery对象

//jquery对象转Element对象
var $box = $('.box')
var box = $box[0]

2.常用jQuery选择器接口
//传入对象 , 例$(document),把传入的对象包装成jQuery对象
$(this}

//传入函数 , 这个是在页面DOM文档加载完成后加载执行的,等效于在DOM加载完毕后执行了${document).ready()方 法。
$ (function (){})

//传入字符串 ,査询D0M节点包装成jQuery对象
$(.box)

//传入HTML字符串 创建DOM节点包装成jQuery对象
$(<div>)

//空
$()创建jQuery对象

3.如何把创建的Dom结点包装成jQuery对象
contetx.createElement创建DOM节点存储在数组中,调用merge方法把数组中存储的DOM节点的成员添加到jQuery实例对象上

4.jQuery实例对象length属性作用
存储DOM节点的数组对象平滑地添加到jQuery实例对象上

5.merge方法应用场景有哪些
合并数组
把数组成员合并在有length属性的对象上

6.$(document).ready()与$(function(){})的关系
$(document).ready()是对document.DOMContentLoaded事件的封装
$(function(){})每次调用$()传入的参数会收集在readyList数组中,
当document.DOMContentLoaded事件触发时依次执行readyList中收集的处理函数

My Little World

js 知识点 一

发表于 2018-12-08

1.< script > 标签几个属性

async :立即异步下载,因此不保证能够按指定的先后顺序执行,但会在load事件前,DOMContentLoad前后执行
defer :延迟执行,也不保证按顺序执行,在DOMContentLoad前后执行
src :外部文件链接
charset :src指定代码的字符集,防止出现乱码
language :已废弃,表示脚本语言,
type :值为脚本语言内容类型(MIME),language替代属性,服务器传递过来类型为application/x-javascript需要注意,一个是可能导致脚本被忽略,另一个是可能触发浏览器XHTML标准模式;另外外链文件不是js文件时,一定要设置该值

2.js 代码执行过程

包括两个部分一个是编译,或者叫预处理过程,一个是执行
编译过程 首先会创建一个全局作用域,然后进行词法分析,
词法分析过程会涉及到变量提升和函数声明提前处理,
即词法分析到变量时会先判断当前域到全局域有没有该变量声明,如果有,就会将该声明的变量挂到该作用域的对象上,
如果到全局域都没有则以全局为背景,新建该变量,并为其分配内存,
对于基本类型,变量中会保存它的值,对于对象,变量中会保存值所在内存的内存地址,
在一定场景下,这里就相当于发生了变量提升,把变量从局部提升到了全局,或者将声明提前到了使用之前,
避免变量提升可以使用es6的let 关键字或者使用立即执行实现变量声明使用,但要注意使用let重复声明会报错,var 会同名覆盖;
当遇到函数声明时,会直接按声明顺序,将声明提前到代码顶端,
重复声明 的函数会被后者覆盖,
如果变量名与函数名相同,则无论原来词法位置如何,先将函数声明提前到顶端,不再进行变量声明,变量名在哪赋值,则原函数在哪被覆盖,
覆盖之前调用使用原函数
提前之后会为函数创建作用域,
这时创建的作用域就是函数的 【【scope】】属性,保存着指向父域到全局域的指针
(指针就是指向活动对象的一个地址,全局域浏览器环境就是windows,nodejs环境就是global)
将来执行时会根据此指针建立作用域链,作用域链就是指针列表,指向不同层级作用域的内存,在里面取值
以上就基本上是编译过程,除了一些特定的编译规则,编译过程还会会使用大量技巧进行优化提升编译速度
但在使用js时,需要注意try-catch,with和eval三个语法关键字的使用,因为在使用它们时,会创建块级作用域,
破坏掉编译器原有的创建管理作用域的规则,在编译时,编译器也就不会对其中的代码进行优化,最终导致性能变差

运行过程,基本就是在运行函数,函数在运行时会首先根据【【scope】】属性拿到父域到全局的指针,创建指针列表即作用域链,
然后创建函数执行的局部作用域,将函数中声明的变量挂到局部作用域活动对象上,然后将局部作用域指针推向作用域链前端,
在用到变量值时,会根据作用域链依次查找取值
函数执行结束后,局部活动对象被销毁,作用域链被销毁,进行垃圾回收
但是对于声明在一个函数内部的函数来说,这个声明的函数在声明时,就会包含其父域的活动对象,
因此在外部使用该函数时,可以访问到其父域的变量,实现了父域访问子域变量,延长了变量的使用范围,也就是常见的闭包现象,
缺点就是闭包的函数执行完毕后,因为本身【【scope】】会指向父域的活动对象,所以父域的活动对象始终不会被回收,除非闭包函数被销毁
从而有可能造成内存泄露,为什么说有可能,因为父活动对象占的内存其实是比较小的,造成内存泄露的真正原因是使用闭包易造成循环引用,
尤其是闭包作用域中保存dom结点时,如果是在IE中,dom和bom都是以C++的COM对象保存的,垃圾回收机制是计数策略,
因此循环引用的话,永远都不会被回收

补充,对于未以分号结尾的语句,会采用能合就合的原则,即,会尝试和下一行语句合并执行,如果能合并执行就合并执行,
不能合并执行就在中间加分号再执行,如果再执行不了就会报错
好处就是对于条件判断语句可进行一行一行判断
坏处就是如果下一行以大括号开头,上一行语句就会变成函数,导致出现意想不到的结果
两个例外,
对于return,break,continue语句不会做尝试合并;
对于++,–自增自减符后没有分号,上一行也没分号情况,自增自减会和下一行合并,上一行自行添加分号

以上即是我所了解的js运行机制

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
//补充1
每个值都有内存地址,变量名指向内存地址/保存内存地址
变量名携带内存地址存储在栈中
保存变量值的内存空间在堆中(数据类型:object,function,函数缓存区,函数加载区),相同模样的值,内存地址不同,(即不同变量名,赋值为看似一样的对象时,会不相等;更改变量的值,即更改指向的地址)
常量值保存在池中(数据类型:string,number,boolean),相同值,内存地址相同

变量是个引用,常量是个值
== 比较值
=== 比较地址

//补充2
function func(a,b,c){
/*
* 逻辑代码执行前
* step1 创建AO对象
* AO ={}
* step2 初始化AO对象
* AO = {
* this:undefined,//内置
* arguments:undefined,//默认
* a:undefined,//参数
* b:undefined,//参数
* c:undefined,//参数
* inner:undefined//函数内声明
* }
* step3 赋值
* AO = {
* this:window,//内置
* arguments:[length:2,0:1,1:2],//默认
* a:1,//参数
* b:2,//参数
* c:undefined,//参数
* inner:undefined//仅声明还未执行
* }
* step4 处理函数声明,有相同变量名的函数覆盖赋值已有变量名,新函数名直接挂到AO上
* AO = {
* this:window,//内置
* arguments:[length:2,0:1,1:2],//默认
* a:function a(){},//有同名函数声明进行覆盖
* b:2,//参数
* c:undefined,//参数
* inner:undefined,//仅声明还未执行
* innerFunc:function(){}//添加函数声明
* }
*/
console.log(arguments);
console.log(global)
console.log(inner)
////////////////
var inner = 20;//执行到该步,inner被赋值为20
function inner(){

}
function innerFunc(){

}
console.log(inner)
}

var global=20
func(1,2)

3.关于对象继承

3.0 new 操作符调用构造函数 执行过程
1.创建或者构造一个全新的对象
2.将构造函数的作用域赋给这个新的对象,
3.执行构造函数 (为这个新对象添加属性) ,第二,三步相当于func.call(newobj)
4.如果构造函数没有返回值或返回值非对象,则返回新对象,否则返回构造函数return的对象

3.1 继承的6种方式及优缺点
第一种原型链方式,子类的原型对象指向父类的实例
缺点
给原型添加方法必须要在替换原型的语句之后;
不能实现多继承(原型指向多个父对象);
所有属性共享
无法传递参数到父类进行初始化
第二种借助构造函数,在子类构造函数中使用call或者apply执行父类构造函数
优点
可以实现多继承
可以传递参数
属性不共享
缺点
只能继承构造函数中属性,不能继承原型上方法,不能复用方法
实例仅为子类实例,不是父类实例
第三种组合继承,以上两组结合在一起,两种方式都执行
缺点
要调用两次父类构造函数,影响性能
实例属性和原型属性各占一份,同名覆盖机制,重复占内存,没必要
第四种原型式继承,借助object()或者object.create()函数,缺点同原型链方式

1
2
3
4
5
function object(o){
function F(){}
F.prototype = o;
return new F();
}

第五种寄生式继承,利用原型式继承和增强对象过程的封装函数创建子类,缺点同原型链方式
第六种寄生组合式继承,保留借助构造函数部分,原型部分功能借助中间函数处理,
中间函数借助object拿到父类prototype,给到子类的prototype,从而完美解决组合继承的缺点

1
2
3
4
5
6
function inheritPrototype(subType,superType){
var prototype = object(superType.prototype)
prototype.constructor = subType
subType.prototype = prototype
}
subType.prototype.__proto__ = superType

3.2 es6 使用class extend实现继承
使用class声明构造函数时,本来挂在this上的属性,放在constructor()函数里面执行初始化,
挂在prototype上的方法直接放在class里面声明

使用extend继承时,需要在constructor里面先执行super函数才能使用this关键字,
增强方法同样直接在class中和constructor并列声明,相当于挂在prototype上

注意super函数只能在consructor中运行;super用作对象在constructor中使用时,相当于this,
添加属性会添加在当前对象上,运行函数时会调用继承的父类的方法

还有就是class extend继承null和 什么也不继承是,相当于继承Function.prototype
继承Object时,子类就相当于object 的复制,子类实例就是object实例

4.关于this 四种使用场景

普通函数执行,指向全局作用域
对象属性方法调用,指向调用对象
call,apply中强制绑定对象,this执行绑定的对象
构造函数中this指向构造的新对象
(箭头函数中this,指向词法作用域的父域)

5.js文件位置

放html底部原因:
下载解析执行过程是阻断式的,会停止页面渲染,造成白屏,影响用户体验;
另外JS中如果有对dom的操作,页面中还没有dom,获取不到,是不符合逻辑的,会报错

哪些js功能文件可以放顶部:
与css相关的js,比如rem单位的换算,需要根据根结点进行设置
使用的框架需要在根结点将浏览器支持的样式罗列出来

6.什么情况下用内部文件,内部文件比外部文件好处在哪?

内部文件相比外部文件最大好处就是性能提升,因为访问外部文件时,不管文件大小都会造成一次网络请求链接,请求服务器,下载文件,
解析文件,除了文件本身代码外,还要处理文件头文件尾的请求,增加了链接数,从而造成性能影响
对于功能短小精悍,不会被到处复用的js代码不适合采用外部文件,应该采用内部文件写法,尤其对手机端页面有性能提升

7.开发过程避免缓存方法

在浏览器开启禁用缓存的模式
手动清缓存 ctrl+shfit+del
引用的文件名添加随机数,浏览器根据文件名不同,就会重新获取资源更新缓存

8.使用严格模式弊端及解决办法

在代码压缩时,’use strict’ 这一行可能不在位于第一行,
或者后续代码不需要在严格模式下执行,被压缩在了严格模式范围内,导致了全部以严格模式执行

解决办法就是,将需要严格模式执行的代码放在匿名函数中,形成代码块,在函数中使用严格模式

9.立即执行函数好处

避免变量污染:有些变量仅在小功能内使用,将小功能封装起来,就可以避免这些变量暴露到全局,
另外函数本身没有函数名,不会增加全局变量
提升性能:功能所需变量全都在函数内时,查找变量快
有利于压缩:一部分代码执行需要用到的变量变量名太长,将这段代码封装成立即执行函数,将长变量名以参数形式传进去
避免全局命名冲突:一段代码需要用到两个代表不同功能但名称相同的变量,可以将该段代码封装成立即执行函数,
将其中一个变量以参数形式传递进来,达到换名的目的
保存闭包状态:循环执行异步代码时,将异步代码用立即执行函数包裹,函数内可保存本次循环的状态
改变代码运行顺序:umd,通用模块规范,function(fn){fn()}()

10.变量类型

根据当前变量的值的类型确定
如果想要进行标记,方法有三种
初始化时指定相应类型值
使用匈牙利标记法,用单字母表示类型,添加到变量命中,例sName 代表string类型
使用注释,变量声明时,在旁边添加注释

11.null vs undefined

转数字时,null –>0;undefined–>NaN
undefined可以当做windows对象上的一个属性,null不行

12. 类型转换

基本类型包括,undefined,null,boolean,string,number

基本类型 —> boolean Boolean(someval) 相当于 !!someval
undefined,null,NaN,’’,+0,-0 —> false
其他 —> true

基本类型 —> string String(someval)相当于 someval+’’
一般情况直接加引号
[] —> ‘’
{} —> ‘[object object]’

基本类型—>number + someval 相当于 Number(someval)
undefined,{} —> NaN
false, null,’’,[],—> 0
true —> 1
‘123’ —> 123
‘abc’ —> NaN
[]—> toString —> ‘’ —> 0
{} —> valueOf —> {} —> toString —> ‘[object object]’ —> NaN

基本类型 —>对象
undefined,null —> {}
true/123 —> {initval:true/123}
‘abc’ —> {initval:’abc’,length:3,0:’a’,1:’b’,2:’c’}

对象 —>基本类型

关于–对象分类:
内部对象(错误对象;常用对象:Boolean,Number,String,Object,Array,Function,Date,Exec;内置对象:Math,global,Json)
宿主对象:windows,document
自定义对象

关于–属性访问
obj.someprop—>检查obj是不是null/undefined—>是|不是—>报错|是不是Object,不是的话转object—>取值
obj[someval]—>检查obj是不是null/undefined—>是|不是—>报错|是不是Object,不是的话转object—>计算someval拿到string—>取值

Boolean —>true
Number —>基本类型转的|{}/{a:1}|Date—>相应值|NaN|时间戳
Array.toString:数组每一项转字符串
Function.toString:原代码字符串形式
Date.toString:日期和时间组合形式
Exec.toString:正则字符串形式

运算转换

Number()参数不能有非数字
parseInt()参数只能为字符串,非字符串会进行强制转化字符串,可含非数字,但不能以非数字开头
一元操作符对任何数据类型有效,得到数字

+二元运算侧重转字符串,然后进行字符串拼接
其中一个为字符串或者两个都是对象时,转字符串拼接
undefined,null,Boolean,数字混合运算+时,会被转数字再计算
{}为第一个运算值时,会被当做函数结束,不参与计算

1
2
3
4
5
6
7
8
9
10
11
12
null + null --> 0
undefined + null --> NaN
[] + [] --> ''
1 + [1,2] --> '11,2'
1 + {a:1} --> '1[object object]'
{a:1} + 1 --> 1
{} + {} --> NaN
({}) + {} --> '[object object][object object]'
[] + {} --> '[object object]'
{} + [] --> 0
var a = {}
a + a -->'[object object][object object]'

*/- 转数字,进行相减,如果不能转数字,返回NaN

>/< 侧重转数字
string < string 字典比较
非字符串<非字符串/字符串 都转数字然后比较

string == number 字符串转数字
boolean == 其他类型 二者转数字然后比较
null == undefined —>true undefined和null只与对方和自己==比较时为true,其他均为false
null === undefined —>false
非对象 == 对象 与数字比较object转数字,与字符串比较二者转数字再比较

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
'0' == null  //false
'0' == undefined //false
'0' == false //true
'0' == NaN //false
'0' == 0 //true
'0' == '' //false

false == null //false
false == undefined //false
false == NaN //false
false == 0 //true
false == '' //true
false == [] //true
false == {} //false

'' == null //false
'' == undefined //false
'' == NaN //false
'' == 0 //true
'' == [] //true
'' == {} //false

0 == null //false
0 == undefined //false
0 == NaN //false
0 == [] //true
0 == {} //false

[] == ![] //true

&&和|| 计算结果根据短路原则判断到了哪里,返回最后一个进行判断的值

运算符优先级
属性访问.
一元操作符(+,-,++,–)
二元操作符(+-*/)
比较(>,<)
相等(==,===,!=)
与&&,或||
三目运算符
赋值

运算符结合性
除了一元操作符,三目运算符和赋值是右结合,其他都是左结合

减少小数计算误差
尽量不使用小数进行比较或运算
转整数计算,再转回相应位数小数
使用toFixed()四舍五入
两个情境需要重复计算时,保证前后书写顺序

13. 数组相关方法

arrmethod

1
2
let arr = []
let iterator = arr[Symbol.iterator]() //可以获取数组迭代器

遍历对象/数组的方法
for
while(do…while)
forEach
map
reduce
for…of
for…in
iterator
generator

14.字符串相关方法

strmethod

15.日期相关方法

一共 33个
set/get(UTC)FullYear,Month,Date,Hours,Minutes,Seconds,Millseconds
set/get Time
get(UTC) Day
getTimezoneOffset

16. Math三个舍入方法

Math.ceil:比值大的最小整数
Math.round:四舍五入
Math.floor:比值小的最大整数

17. setInterval 注意问题

累积效应
代码执行时间大于间隔时间,后续调用会进行累积,累积会在短时间内连续触发

当用于动画时,因与显示器刷新频率不统一会造成视觉卡顿,解决办法如下:
一种是使用CSS3创建动画,根据显示器刷新执行动画
另一种是使用 requestAnimationframe(function(){})函数,也是在显示器刷新时执行
可以解决CSS3无法实现的,例如滚动控制等效果

18. 关于DOM

document 三个属性
url:地址栏中URL
domain:域名,跨域域名 X;父域名到子域名 X;
referer:上一页URL,可在跳转时,判断与当前页是否在同一域,是的话,就可以back,否则 location.href其他页面
dom.getAttribute(‘style’),得到样式字符串
dom.style 得到到样式对象
dom.getAttribute(‘onclick’) ,得到代码字符串
dom.onclick 得到函数对象

动态合集
使用时可能会造成死循环
使用框架如Jquery获取的合集不具有动态性
使用 queryselect(all)()获取到的也是静态合集

动态合集生成原理:
浏览器通过DOM树预先缓存起来,获取时,浏览器会通过缓存直接注册,创建一个变量返回

静态合集生成原理:
获取标识是一个CSS选择器,浏览器会先去解析字符串,判断是一个CSS选择器,
分析选择器并创建一个选择器结构,浏览器根据DOM树创建一个静态文件,即DOM树的一个快照
然后拿选择器和快照进行对比,符合选择器就放到合集中,知道整个快照对比完,再把合集的快照返回

19. 事件

绑定方式

直接通过HTML属性绑定
缺点
有可能响应函数还未被解析就被触发
事件名和回调1对1,修改繁琐
响应执行时,作用域为全局,不同浏览器解析规则不同,造成某些对象无法访问

使用dom属性绑定
冒泡阶段执行
缺点
只能绑定一个响应,后续赋值会被覆盖

IE attachEvent/detachEvent绑定/解绑
冒泡阶段执行
绑定多个时按按绑定顺序的逆序执行

addEventListener()/removeEventListener()绑定/解绑
第三个参数为对象时,passive属性为true时,会针对touchstart,touchend等特定事件通过开启两个线程,
一个执行浏览器默认行为,一个执行JS进行优化

事件优先级
浏览器在绑定事件而不是JS在绑定事件

1.html标签绑定事件会被dom属性事件覆盖
2.html标签优先执行,即使被属性事件覆盖,则执行被覆盖的属性事件
3.仅有监听事件和属性事件时,按绑定顺序执行,即事件对象的冒泡事件可能会在捕获事件之前执行

event对象属性
curentTarget:响应函数绑定的对象
target:发生事件的对象

My Little World

拖拽

发表于 2018-12-04

使用 React 实现拖放的技术要点

1.如何使用 React 的鼠标事件系统
2.如何判断拖放开始和拖放结束
3.如何实现拖放元素的位置移动 (可分为两种,一种是直接拖着具体要被移动的dom移动;另外一种是具体dom留在原位,拖着具体dom的影子移动,确定位置后,再将具体的dom放过去)
4.拖放状态在组件中如何维护

鼠标移动可能会超出要移动的组件和他的父组件,除了在document上监听,还可以在一个全局透明遮罩层上监听MouseMove和MouseUp好处:拖放过程不会选中其他任何元素,防止点击到其他组件

其他情景思考:
每个条目高度不一致,如何确定移动位置?
条目所在的列表有折叠,存在滚动条,如何根据滚动条确定位置?

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
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100

import React, { Component } from "react";

require("./DndSample.css");

const list = [];
for (let i = 0; i < 10; i++) {
list.push(`Item ${i + 1}`);
}

const move = (arr, startIndex, toIndex) => {
arr = arr.slice();
arr.splice(toIndex, 0, arr.splice(startIndex, 1)[0]);
return arr;
};

const lineHeight = 42;
class DndSample extends Component {
constructor(props) {
super(props);
this.state.list = list;
}
state = {
dragging: false,
draggingIndex: -1,
startPageY: 0,
offsetPageY: 0,
};

handleMounseDown = (evt, index) => {
this.setState({
dragging: true,
startPageY: evt.pageY,
currentPageY: evt.pageY,
draggingIndex: index,
});
};
handleMouseUp = () => {
this.setState({ dragging: false, startPageY: 0, draggingIndex: -1 });
};
//如果往下滑,就一次把下一条数据交换位置,如果往上移动,就一次把上一条数据交换位置,
handleMouseMove = evt => {
let offset = evt.pageY - this.state.startPageY;
const draggingIndex = this.state.draggingIndex;
if (offset > lineHeight && draggingIndex < this.state.list.length - 1) {
// move down
offset -= lineHeight;
this.setState({
list: move(this.state.list, draggingIndex, draggingIndex + 1),
draggingIndex: draggingIndex + 1,
startPageY: this.state.startPageY + lineHeight,
});
} else if (offset < -lineHeight && draggingIndex > 0) {
// move up
offset += lineHeight;
this.setState({
list: move(this.state.list, draggingIndex, draggingIndex - 1),
draggingIndex: draggingIndex - 1,
startPageY: this.state.startPageY - lineHeight,
});
}
this.setState({ offsetPageY: offset });
};

getDraggingStyle(index) {
if (index !== this.state.draggingIndex) return {};
return {
backgroundColor: "#eee",
transform: `translate(10px, ${this.state.offsetPageY}px)`,
opacity: 0.5,
};
}

render() {
return (
<div className="dnd-sample">
<ul>
{this.state.list.map((text, i) => (
<li
key={text}
onMouseDown={evt => this.handleMounseDown(evt, i)}
style={this.getDraggingStyle(i)}
>
{text}
</li>
))}
</ul>
{this.state.dragging && ( //在一个遮罩层上监听MouseMove和MouseUp
<div
className="dnd-sample-mask"
onMouseMove={this.handleMouseMove}
onMouseUp={this.handleMouseUp}
/>
)}
</div>
);
}
}

export default DndSample;

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
.dnd-sample ul {
display: inline-block;
margin: 0;
padding: 0;
background-color: #eee;
}

.dnd-sample li {
cursor: default;
list-style: none;
border-bottom: 1px solid #ddd;
padding: 10px;
margin: 0;
width: 300px;
background-color: #fff;
}

.dnd-sample-mask {
position: fixed;
left: 0;
right: 0;
top: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.1);
}
My Little World

对话框

发表于 2018-12-04

使用React Portals

React 16.3 新引入的 API
可以将虚拟 DOM 映射到任何真实 DOM 节点
解决了漂浮层的问题,比如Dialog,Tooltip 等

主要思路使用ReactDOM.createPortal将自定义dialog利用id挂到根标签上,dialog样式(包括悬浮)自己需要通过css定义,弹窗的显示和隐藏通过state操作

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
mport React from "react";
import ReactDOM from "react-dom";
import { Button } from "antd";
import "./PortalSample.css";

export default class PortalSample extends React.PureComponent {
state = { visible: false };
renderButton() {
return (
<Button type="primary" onClick={() => this.setState({ visible: true })}>
打开对话框
</Button>
);
}
renderDialog() {
return (
<div className="portal-sample">
<div>这是一个对话框!</div>
<br />
<Button
type="primary"
onClick={() => this.setState({ visible: false })}
>
关闭对话框
</Button>
</div>
);
}
render() {
if (!this.state.visible) return this.renderButton();
return ReactDOM.createPortal(
this.renderDialog(),
document.getElementById("dialog-container"),//在APP组件中定义
);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
.portal-sample {
position: absolute;
padding: 20px;
width: 500px;
height: 300px;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
background-color: #fff;
border-radius: 10px;
border: 1px solid #ddd;
box-shadow: 0px 0px 20px 2px #ddd;
}

使用UI组件库

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
import React from "react";
import ReactDOM from "react-dom";
import { Button, Modal } from "antd";
import "./PortalSample.css";

export default class PortalSample extends React.PureComponent {
state = { visible: false };
renderButton() {
return (
<Button type="primary" onClick={() => this.setState({ visible: true })}>
打开对话框
</Button>
);
}
renderDialog() {
return (
<Modal
visible={this.state.visible}
onCancel={() => this.setState({ visible: false })}
>
<div>这是一个对话框!</div>
</Modal>
);
}
render() {
return (
<div>
{this.renderButton()}
{this.renderDialog()}
</div>
);
}
}
1…111213…26
YooHannah

YooHannah

260 日志
1 分类
23 标签
RSS
© 2025 YooHannah
由 Hexo 强力驱动
主题 - NexT.Pisces