1.使用 setInterval1
2this.timerID = setInterval(fn, time);
clearInterval(this.timerID);
2.angular 中使用 $interval
1
2this.timerID = $interval(fn, time);
$interval.cancel(this.timerID)
learn and share
1.使用 setInterval1
2this.timerID = setInterval(fn, time);
clearInterval(this.timerID);
2.angular 中使用 $interval
1
2this.timerID = $interval(fn, time);
$interval.cancel(this.timerID)
在react中,触发render的有4条路径。
以下假设shouldComponentUpdate都是按照默认返回true的方式。
首次渲染Initial Render
调用this.setState (并不是一次setState会触发一次render,React可能会合并操作,再一次性进行render)
父组件发生更新(一般就是props发生改变,但是就算props没有改变或者父子组件之间没有数据交换也会触发render)
调用this.forceUpdate
指令的职责是,当表达式的值改变时,将其产生的连带影响,响应式地作用于 DOM
v-if 条件指令,绑定值为真时构建DOM,假时bu构建或者删除已存在DOM1
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 属性保持一致”
使用命令行构建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
其值为vue模板挂载ID,用于标识vue的APP template挂载在index.html的什么位置
通过{ {}}}插值的时候,可以在大括号里面添加一个简单的计算表达式,从而将计算结果插入,但是对于复杂的计算,需要执行多个计算表达式时不能放在大括号里面的,为方便绑定,在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 | //computed方式 |
计算属性还可以设置getter和setter1
2
3
4
5
6
7
8
9
10
11
12
13
14
15computed: {
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 也会相应地被更新
定义某个变量发生变化时需要执行的函数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++
}
}
}
在display:flex基础上使用flex-direction,可用于多子模块布局
flex-direction可以为四个值
row:水平并行排列在左侧
row-reverse:水平并行排列在右侧,顺序与书写顺序相反,最前的在最右边
column:垂直排列在上方,相当于display:block状态下模块默认布局
column-reverse:垂直排列在下方,顺序与书写顺序相反,最前的在最下边
1 | <!doctype html> |
1 | let arr = [1,2,3,4,5]; |
在map中可以传递一个函数,数组的每一项作为参数调用这个函数,然后返回根据该数组项得到的结果,每一个数组项返会一个结果,从而组成新的数组
函数的参数有三个,第一项为数组按序传进的一个值,该值的index和数组本身
整个结果产生新数组,原来数组不变
1 | 例1. |
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
27var 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 | var reducers = { |
2.计算对象数组属性值1
2
3
4
5
6
7
8
9
10
11
12
13
14
15var 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}
async :立即异步下载,因此不保证能够按指定的先后顺序执行,但会在load事件前,DOMContentLoad前后执行
defer :延迟执行,也不保证按顺序执行,在DOMContentLoad前后执行
src :外部文件链接
charset :src指定代码的字符集,防止出现乱码
language :已废弃,表示脚本语言,
type :值为脚本语言内容类型(MIME),language替代属性,服务器传递过来类型为application/x-javascript需要注意,一个是可能导致脚本被忽略,另一个是可能触发浏览器XHTML标准模式;另外外链文件不是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.0 new 操作符调用构造函数 执行过程
1.创建或者构造一个全新的对象
2.将构造函数的作用域赋给这个新的对象,
3.执行构造函数 (为这个新对象添加属性) ,第二,三步相当于func.call(newobj)
4.如果构造函数没有返回值或返回值非对象,则返回新对象,否则返回构造函数return的对象
3.1 继承的6种方式及优缺点
第一种原型链方式,子类的原型对象指向父类的实例
缺点
给原型添加方法必须要在替换原型的语句之后;
不能实现多继承(原型指向多个父对象);
所有属性共享
无法传递参数到父类进行初始化
第二种借助构造函数,在子类构造函数中使用call或者apply执行父类构造函数
优点
可以实现多继承
可以传递参数
方法属性不共享
缺点
只能继承构造函数中属性,不能继承原型上方法,不能复用方法
实例仅为子类实例,不是父类实例
第三种组合继承,以上两组结合在一起,两种方式都执行
缺点
要调用两次父类构造函数,影响性能
实例属性和原型属性各占一份,同名覆盖机制,重复占内存,没必要
第四种原型式继承,借助object()或者object.create()函数,缺点同原型链方式
1 | function object(o){ |
第五种寄生式继承,利用原型式继承和增强对象过程的封装函数创建子类,缺点同原型链方式
第六种寄生组合式继承,保留借助构造函数部分,原型部分功能借助中间函数处理,
中间函数借助object拿到父类prototype,给到子类的prototype,从而完美解决组合继承的缺点
1 | function inheritPrototype(subType,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实例
普通函数执行,指向全局作用域
对象属性方法调用,指向调用对象
call,apply中强制绑定对象,this执行绑定的对象
构造函数中this指向构造的新对象
(箭头函数中this,指向词法作用域的父域)
放html底部原因:
下载解析执行过程是阻断式的,会停止页面渲染,造成白屏,影响用户体验;
另外JS中如果有对dom的操作,页面中还没有dom,获取不到,是不符合逻辑的,会报错
哪些js功能文件可以放顶部:
与css相关的js,比如rem单位的换算,需要根据根结点进行设置
使用的框架需要在根结点将浏览器支持的样式罗列出来
内部文件相比外部文件最大好处就是性能提升,因为访问外部文件时,不管文件大小都会造成一次网络请求链接,请求服务器,下载文件,
解析文件,除了文件本身代码外,还要处理文件头文件尾的请求,增加了链接数,从而造成性能影响
对于功能短小精悍,不会被到处复用的js代码不适合采用外部文件,应该采用内部文件写法,尤其对手机端页面有性能提升
在浏览器开启禁用缓存的模式
手动清缓存 ctrl+shfit+del
引用的文件名添加随机数,浏览器根据文件名不同,就会重新获取资源更新缓存
在代码压缩时,’use strict’ 这一行可能不在位于第一行,
或者后续代码不需要在严格模式下执行,被压缩在了严格模式范围内,导致了全部以严格模式执行
解决办法就是,将需要严格模式执行的代码放在匿名函数中,形成代码块,在函数中使用严格模式
避免变量污染:有些变量仅在小功能内使用,将小功能封装起来,就可以避免这些变量暴露到全局,
另外函数本身没有函数名,不会增加全局变量
提升性能:功能所需变量全都在函数内时,查找变量快
有利于压缩:一部分代码执行需要用到的变量变量名太长,将这段代码封装成立即执行函数,将长变量名以参数形式传进去
避免全局命名冲突:一段代码需要用到两个代表不同功能但名称相同的变量,可以将该段代码封装成立即执行函数,
将其中一个变量以参数形式传递进来,达到换名的目的
保存闭包状态:循环执行异步代码时,将异步代码用立即执行函数包裹,函数内可保存本次循环的状态
改变代码运行顺序:umd,通用模块规范,function(fn){fn()}()
根据当前变量的值的类型确定
如果想要进行标记,方法有三种
初始化时指定相应类型值
使用匈牙利标记法,用单字母表示类型,添加到变量命中,例sName 代表string类型
使用注释,变量声明时,在旁边添加注释
转数字时,null –>0;undefined–>NaN
undefined可以当做windows对象上的一个属性,null不行
基本类型包括,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
12null + 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()四舍五入
两个情境需要重复计算时,保证前后书写顺序
一共 33个
set/get(UTC)FullYear,Month,Date,Hours,Minutes,Seconds,Millseconds
set/get Time
get(UTC) Day
getTimezoneOffset
Math.ceil:比值大的最小整数
Math.round:四舍五入
Math.floor:比值小的最大整数
累积效应
代码执行时间大于间隔时间,后续调用会进行累积,累积会在短时间内连续触发
当用于动画时,因与显示器刷新频率不统一会造成视觉卡顿,解决办法如下:
一种是使用CSS3创建动画,根据显示器刷新执行动画
另一种是使用 requestAnimationframe(function(){})函数,也是在显示器刷新时执行
可以解决CSS3无法实现的,例如滚动控制等效果
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树的一个快照
然后拿选择器和快照进行对比,符合选择器就放到合集中,知道整个快照对比完,再把合集的快照返回
绑定方式
直接通过HTML属性绑定
缺点
有可能响应函数还未被解析就被触发
事件名和回调1对1,修改繁琐
响应执行时,作用域为全局,不同浏览器解析规则不同,造成某些对象无法访问
使用dom属性绑定
冒泡阶段执行
缺点
只能绑定一个响应,后续赋值会被覆盖
IE attachEvent/detachEvent绑定/解绑
冒泡阶段执行
绑定多个时按按绑定顺序的逆序执行
addEventListener()/removeEventListener()绑定/解绑
第三个参数为对象时,passive属性为true时,会针对touchstart,touchend等特定事件通过开启两个线程,
一个执行浏览器默认行为,一个执行JS进行优化
事件优先级
浏览器在绑定事件而不是JS在绑定事件
1.html标签绑定事件会被dom属性事件覆盖
2.html标签优先执行,即使被属性事件覆盖,则执行被覆盖的属性事件
3.仅有监听事件和属性事件时,按绑定顺序执行,即事件对象的冒泡事件可能会在捕获事件之前执行
event对象属性
curentTarget:响应函数绑定的对象
target:发生事件的对象
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中收集的处理函数
async :立即异步下载,因此不保证能够按指定的先后顺序执行,但会在load事件前,DOMContentLoad前后执行
defer :延迟执行,也不保证按顺序执行,在DOMContentLoad前后执行
src :外部文件链接
charset :src指定代码的字符集,防止出现乱码
language :已废弃,表示脚本语言,
type :值为脚本语言内容类型(MIME),language替代属性,服务器传递过来类型为application/x-javascript需要注意,一个是可能导致脚本被忽略,另一个是可能触发浏览器XHTML标准模式;另外外链文件不是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 | //补充1 |
3.0 new 操作符调用构造函数 执行过程
1.创建或者构造一个全新的对象
2.将构造函数的作用域赋给这个新的对象,
3.执行构造函数 (为这个新对象添加属性) ,第二,三步相当于func.call(newobj)
4.如果构造函数没有返回值或返回值非对象,则返回新对象,否则返回构造函数return的对象
3.1 继承的6种方式及优缺点
第一种原型链方式,子类的原型对象指向父类的实例
缺点
给原型添加方法必须要在替换原型的语句之后;
不能实现多继承(原型指向多个父对象);
所有属性共享
无法传递参数到父类进行初始化
第二种借助构造函数,在子类构造函数中使用call或者apply执行父类构造函数
优点
可以实现多继承
可以传递参数
属性不共享
缺点
只能继承构造函数中属性,不能继承原型上方法,不能复用方法
实例仅为子类实例,不是父类实例
第三种组合继承,以上两组结合在一起,两种方式都执行
缺点
要调用两次父类构造函数,影响性能
实例属性和原型属性各占一份,同名覆盖机制,重复占内存,没必要
第四种原型式继承,借助object()或者object.create()函数,缺点同原型链方式
1 | function object(o){ |
第五种寄生式继承,利用原型式继承和增强对象过程的封装函数创建子类,缺点同原型链方式
第六种寄生组合式继承,保留借助构造函数部分,原型部分功能借助中间函数处理,
中间函数借助object拿到父类prototype,给到子类的prototype,从而完美解决组合继承的缺点
1 | function inheritPrototype(subType,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实例
普通函数执行,指向全局作用域
对象属性方法调用,指向调用对象
call,apply中强制绑定对象,this执行绑定的对象
构造函数中this指向构造的新对象
(箭头函数中this,指向词法作用域的父域)
放html底部原因:
下载解析执行过程是阻断式的,会停止页面渲染,造成白屏,影响用户体验;
另外JS中如果有对dom的操作,页面中还没有dom,获取不到,是不符合逻辑的,会报错
哪些js功能文件可以放顶部:
与css相关的js,比如rem单位的换算,需要根据根结点进行设置
使用的框架需要在根结点将浏览器支持的样式罗列出来
内部文件相比外部文件最大好处就是性能提升,因为访问外部文件时,不管文件大小都会造成一次网络请求链接,请求服务器,下载文件,
解析文件,除了文件本身代码外,还要处理文件头文件尾的请求,增加了链接数,从而造成性能影响
对于功能短小精悍,不会被到处复用的js代码不适合采用外部文件,应该采用内部文件写法,尤其对手机端页面有性能提升
在浏览器开启禁用缓存的模式
手动清缓存 ctrl+shfit+del
引用的文件名添加随机数,浏览器根据文件名不同,就会重新获取资源更新缓存
在代码压缩时,’use strict’ 这一行可能不在位于第一行,
或者后续代码不需要在严格模式下执行,被压缩在了严格模式范围内,导致了全部以严格模式执行
解决办法就是,将需要严格模式执行的代码放在匿名函数中,形成代码块,在函数中使用严格模式
避免变量污染:有些变量仅在小功能内使用,将小功能封装起来,就可以避免这些变量暴露到全局,
另外函数本身没有函数名,不会增加全局变量
提升性能:功能所需变量全都在函数内时,查找变量快
有利于压缩:一部分代码执行需要用到的变量变量名太长,将这段代码封装成立即执行函数,将长变量名以参数形式传进去
避免全局命名冲突:一段代码需要用到两个代表不同功能但名称相同的变量,可以将该段代码封装成立即执行函数,
将其中一个变量以参数形式传递进来,达到换名的目的
保存闭包状态:循环执行异步代码时,将异步代码用立即执行函数包裹,函数内可保存本次循环的状态
改变代码运行顺序:umd,通用模块规范,function(fn){fn()}()
根据当前变量的值的类型确定
如果想要进行标记,方法有三种
初始化时指定相应类型值
使用匈牙利标记法,用单字母表示类型,添加到变量命中,例sName 代表string类型
使用注释,变量声明时,在旁边添加注释
转数字时,null –>0;undefined–>NaN
undefined可以当做windows对象上的一个属性,null不行
基本类型包括,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
12null + 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()四舍五入
两个情境需要重复计算时,保证前后书写顺序
1
2let arr = []
let iterator = arr[Symbol.iterator]() //可以获取数组迭代器
遍历对象/数组的方法
for
while(do…while)
forEach
map
reduce
for…of
for…in
iterator
generator
一共 33个
set/get(UTC)FullYear,Month,Date,Hours,Minutes,Seconds,Millseconds
set/get Time
get(UTC) Day
getTimezoneOffset
Math.ceil:比值大的最小整数
Math.round:四舍五入
Math.floor:比值小的最大整数
累积效应
代码执行时间大于间隔时间,后续调用会进行累积,累积会在短时间内连续触发
当用于动画时,因与显示器刷新频率不统一会造成视觉卡顿,解决办法如下:
一种是使用CSS3创建动画,根据显示器刷新执行动画
另一种是使用 requestAnimationframe(function(){})函数,也是在显示器刷新时执行
可以解决CSS3无法实现的,例如滚动控制等效果
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树的一个快照
然后拿选择器和快照进行对比,符合选择器就放到合集中,知道整个快照对比完,再把合集的快照返回
绑定方式
直接通过HTML属性绑定
缺点
有可能响应函数还未被解析就被触发
事件名和回调1对1,修改繁琐
响应执行时,作用域为全局,不同浏览器解析规则不同,造成某些对象无法访问
使用dom属性绑定
冒泡阶段执行
缺点
只能绑定一个响应,后续赋值会被覆盖
IE attachEvent/detachEvent绑定/解绑
冒泡阶段执行
绑定多个时按按绑定顺序的逆序执行
addEventListener()/removeEventListener()绑定/解绑
第三个参数为对象时,passive属性为true时,会针对touchstart,touchend等特定事件通过开启两个线程,
一个执行浏览器默认行为,一个执行JS进行优化
事件优先级
浏览器在绑定事件而不是JS在绑定事件
1.html标签绑定事件会被dom属性事件覆盖
2.html标签优先执行,即使被属性事件覆盖,则执行被覆盖的属性事件
3.仅有监听事件和属性事件时,按绑定顺序执行,即事件对象的冒泡事件可能会在捕获事件之前执行
event对象属性
curentTarget:响应函数绑定的对象
target:发生事件的对象