一、JavaScript高级第一天
1.JavaScript基础知识复习
JavaScript的基本组成
* ECMAScript 语法规范
* DOM 操作dom元素的api
* BOM 操作浏览器对象的api
JavaScript数据类型
简单数据类型
* string
* number
* boolean
* undefined
复杂数据类型
* Object
* Array
* Date
* RegExp
* Function
* String
* Number
* Boolean
* null
* Math
部分关键字的使用
* in
- 判断属性是否存在于对象中
- for in 遍历对象的 键
* typeof 判断对象的类型 返回值是string类型的 引用类型中,除了function其他的对象都是object类型
* delete
- 删除对象的属性
- 删除未使用var声明的变量
- 返回值为boolean 表示是否删除成功
- 注意:删除的属性如果不存在,返回true
- 删除的如果是原型中的属性,返回true 但是删除不成功
* break continue
- break 用来终止循环
- continue 用来跳出当前循环,继续下次循环
* === 和 ==
- === 要判断数据类型和值是否相等
- == 值判断值是否相等
* || 和 &&
- 表达式1 || 表达式2 如果 表达式1 就 返回 表达式1 否则 返回 表达式2
- 表达式1 && 表达式2 如果 表达式1 就 返回 表达式2 否则 返回 表达式1
值类型和引用类型
* 值类型: 存储的是数据本身的值就是值类型的数据
* 引用类型:存储的是数据的地址的值就是引用类型的数据,数据自己在内存中单独存储
* 值类型的赋值:直接将存储的数据复制一份赋值给新的变量 两个变量独立存在互不影响
* 引用类型赋值:将存储的数据的地址复制一份赋值给新的额便令 两个变量指向同一个对象,相互影响
异常处理
* 异常的最大的特征:一旦发生异常,后面的代码都不会再执行
* 异常处理语句 try catch finally
```js
try{
//可能出现异常的代码
}
catch(e){
//e就是出现异常的异常信息
//出现异常后的处理代码
}
finally{
//不管有没有出现异常,都会执行的代码
//一般用来释放资源
}
```
* 如何手动抛出异常: throw 任何东西, catch中会抓到该东西
2.面向对象的基本介绍
面向对象是什么?
面向对象是一种思维方式.
是将解决问题的关注点放到解决问题所需要的一些列对象上。
面向过程是什么?
面向过程是一种思维方式.
是将解决问题的关注点放到解决问题的详细的步骤上。
面向过程和面向对象的关系
面向对象是对面向过程的封装!!!
什么是对象?
万物皆对象
JavaScript中什么是对象
无序键值对儿的集合就是
二、JavaScript高级第二天
1.面向对象的三大特性
* 封装
* 继承
自己没有的,拿别人过来用,就是继承
* 多态
父类引用指向子类的对象(JavaScript中用不到)
2.创建对象的四种方式
a. 使用字面量创建对象
```js
var o = {key:value, key:value...}
```
用一个创建一个,不能复用,造成代码冗余,资源浪费
b. 使用内置构造函数创建对象
```js
var o = new Object();
var o = new Array();
```
创建出来的对象都是空的对象,要手动的去为对象添加属性。造成代码重复
c. 封装简单的工厂函数(不推荐使用)
```js
function createObj(){
var obj = {};
obj.xx=xxx;
return obj;
}
```
d. 自定义构造函数
```
function 构造函数名{
this.xxx=xxx;
//....
}
```
0.构造函数名首字母要大写
1.构造函数一般和new关键字一起使用
2.构造函数返回值默认为新创建好对象 如果手动返回基本数据类型,不影响默认返回值,如果返回的是对象,那么新创建出来的对象将不会返回,取而代之的是return后面的对象
构造函数(constructor)的执行步骤
1.使用new关键字创建对象
2.调用构造函数,将new创建出来的对象赋值给构造函数内的this
3.使用this给新创建出来的对象增加成员
4.默认返回新创建出来的这个对象
3.原型
构造函数存在问题
构造函数中的方法,每新创建一个对象的时候,该对象都会重新的创建一次这个方法,每个独享独占一个方法
但是该方法内容完全相同,所以造成资源浪费
1.解决办法1
将构造函数内的方法,进行提取,放在构造函数外面,在构造函数内部进行引用赋值
那么创建出来的对象,都会指向构造函数外面的这个函数,达到共享的目的
问题:全局变量增多,造成全局变量污染,代码结构混乱,不容易维护
2.解决办法2
使用原型
4.原型
原型是什么?
在构造函数创建出来的时候,系统会默认的创建并关联一个对象,这个对象就是原型,原型对象默认是空对象
默认的原型对象中会有一个属性constructor指向该构造函数
原型的作用
原型对象中的成员,可以被使用和它关联的构造函数创建出来的所有对象共享
原型对象的使用
1. 使用对象的动态特性,为原型对象添加成员
2. 直接替换原型对象
注意事项:
直接替换原型对象,会导致替换之前创建的对象的原型和替换之后创建的对象的原型不一致
原型的使用该注意事项
1.使用对象访问属性的时候,会现在对象中查找,如果找到了就直接使用
如果没有找到,就去原型中查找
2.使用对象设置属性的时候,只会在对象本身中查找,不会去原型中查找,如果在对象本身中没有找到这个属性
则给该对象新增一个属性,如果在对象中有这个属性,修改这个属性
3.如果在原型对象中有引用类型的属性,那么使用对象进行修改该属性内容,则其他所有跟这个原型对象相关的对象都会受到影响
Person.prototype.car = {};
var p = new Person( );
p.car = {}; //这是修改属性
p.car.brand= ""; //这是修改属性的内容
4.一般情况下不会将属性添加到原型对象中
只会将需要共享的方法,添加到原型对象中
proto
1.这个属性不是标准属性,所以存在通用性问题
2.一般不推荐使用这个属性
3.调试的时候,可以使用这个属性
4.这个属性是原型中的属性
替换原型时候的注意事项:
在新替换的原型中,没有constructor属性,会影响三角结构关系的合理性
so,在新替换的原型中,手动添加constructor属性,以保证关系的合理性,赋值为关联的构造函数
三、JavaScript 高级第三天
1.继承
混入式继承
for in
使用for in遍历对象1的属性,将所有的属性添加到另外一个对象2上
这时候就可以称 对象2 继承自 对象1
原型继承
* 利用对象的动态特性,为原型对象添加成员
* 直接替换原型对象
1.替换前的对象,在替换之后,所有的成员都丢失
2.替换原型对象的时候,需要手动去指定原型对象的construtor属性
* 利用混入给原型对象添加成员
经典继承
var 对象1 = Object.create(对象2);
这个时候,创建出来的对象1继承自对象2
Object.create方法存在兼容性问题
如何解决?
1.检测浏览器是否支持Object.create方法,如果不支持,直接手动给Object添加create方法
2.自定义函数,在函数内部判断浏览器是否支持Object.create方法,如果不支持,则手动创建对象返回,否则直接调用
function create(obj){
if(Object.create){
return Object.create(obj);
}else{
function F(){
}
F.prototype = obj;
return new F();
}
}
2.原型链
什么是原型链
每个构造函数都有原型对象,每个对象都有构造函数,每个构造函数的原型对象都是对象,也就有构造函数
然后就形成一个链式的结构,我们称之为原型链
原型继承是什么?
通过修改原型链的结构,实现继承的方式就是原型继承
对象和原型的成员关系
function Person(){};
var p = new Person();
p对象中包含的成员有:Person.prototype中的成员和自身拥有成员
Person.prototype中的成员有:Object.prototype的成员和自身的成员
p对象可以访问Person.prototype和Object.prototype中的所有成员
Object.prototype的成员
- constructor :指向和该原型相关的构造函数
- hasOwnProperty 方法: 判断对象本身是否拥有某个属性
- properIsEnumerable 方法: 1.判断属性是否属于对象本身,2.判断属性是否可以被遍历
- toString toLocaleString: 将对象转换成字符串 toLocalString转换成字符串的时候应用的本地的设置格式
- valueOf 方法:在对象参与运算的时候,首先调用valueOf方法获取对象的值,如果该值无法参与运算,将会调用toString方法
- _ proto_ 属性: 指向当前对象的原型对象
3.Function
Function可以初始化一个构造函数,用来初始化函数对象
3种创建函数的方式
* 直接声明函数
* 函数表达式
* new Function()
可以用Function来创建函数:
语法:
var 函数名 = new Function(); //创建一个空的函数
var 函数名 = new Function("函数体") //创建一个没有参数的函数
var 函数名 = new Function("参数1","参数2", "参数3",..."函数体")
//当给Fucntion传多个参数的时候,最后一个参数为函数体,前面的参数为创建出来的函数的形参
//Function接收的所有的参数都是字符串类型的!!!
4.arguments对象
arguments对象是函数内部的一个对象,在函数调用的时候,系统会默认的将所有传入的实参存入该对象
注意:不管有没有形参,实参都会被存入该对象
arguments.callee调用函数本身
5.eval
可以将字符串转换成js代码并执行
注意:当使用eval解析JSON格式字符串的时候,要注意,会将{}解析为代码段
1.可以在JSON格式字符串前面拼接 "var 变量名 ="
eval("var 变量名 =" + JSON格式的字符串);
2.可以在JSON格式字符串前后拼接()
eval("("+JSON格式的字符串+")")
6.静态成员和实例成员
静态成员
通过构造函数去访问的属性和方法就是静态成员
实例成员
通过对象(实例)去访问的属性和方法就是实例成员
7.Function和eval比较
相同点 都可以将字符串转为js代码
不同点 Function创建出来的是函数,并不会直接调用,只有手动调用函数才会执行。而eval把字符串转为代码后直接执行
四、JavaScript高级第四天
原型相关知识复习
1.原型链
2.函数的原型链
可以把Funciton当做一个构造函数,其他构造函数都是这个Function构造函数的实例
再用对象原型链的方式,去分析这个原型关系
3.instansof
判断一个构造函数的原型是不是存在于该对象的原型链上
javascript中所有的对象 都会有 Object.prototype
所以 所有的对象 instanceof Object 都是true
歌曲列表管理案例
递归
自己调用自己
化归思想
化繁为简,化未知为已知
递归的两个要素
1.自己调用自己
2.有递归结束条件
五、JavaScript高级第五天
使用递归获取后代元素
1.作用域
什么是作用域
变量起作用的范围
1 设置值的时候,也是访问变量
2. 获取值的时候,是访问变量
3.并不是在函数内部写了变量,这个变量就属于这个函数的作用域, 而是必须使用var来声明变量,这个变量才会属于这个作用域
什么是块级作用域
JS中没有块级作用域,使用代码块限定的作用域就是块级作用域
JS中的作用域叫做 词法作用域
词法作用域
在代码写好的时候,就能确定变量的作用域,这种作用域就是词法作用域
动态作用域.(是词法作用域就不可能是动态作用域)
在js当中,只有函数能创造作用域
var num = 123;
function f1(){
console.log(num); //如果是动态作用域打印的就是456 如果是词法作用域 打印123
}
function f2(){
var num = 456;
f1();
}
f2();
变量提升
JS代码的运行分两个阶段
* 预解析阶段
* 变量名和函数提升
将var声明的变量名和function开头的函数进行提升
提升到当前作用域的最上方
* 执行阶段
注意:
1.变量和函数同名的时候
只提升函数,忽略变量名
2.函数同名的时候
都提升,但是后面的函数会覆盖前面的函数
3.函数表达式,只会提升变量名,不会提后面的函数
4.变量提升只会将变量和函数提升到当前作用域的最上方
```js
funciton foo(){
var num =123;
}
```
5.变量提升是分块
```
6.条件式函数声明 能否被提升,取决于浏览器, 不推荐使用!!!
```
foo();//会报错,因为未被提升
if(true){
function foo(){
}
}
```
2.作用域链
只要是函数都有作用域,函数内部的作用域可以访问函数外部的作用域
当多个函数嵌套的时候,就会形成一个链式的结构,这个就是作用域链
绘制作用域链图的步骤
1.先绘制0级作用域链
2.在全局作用域中查找,变量和函数的声明,找到之后,将所有的变量和函数用小方格放在0级作用域链上
3.再从0级作用域链上的函数引出1级作用域链
4.再去每一个1级作用域链中查找变量和函数的声明,找到之后.....
5.以此重复,就画好了整个作用域链
变量的搜索规则
1.首先在访问变量的作用域中查找该变量,如果找到直接使用
2.如果没有找到,去上一级作用域中继续查找,如果如果找到直接使用
3.如果没有找到,继续去上一级作用域中继续查找,直到全局作用域
4.如果找到了就用,如果没有直到就报错
3.闭包
闭包是什么
一个封闭的对外不公开的包裹结构或空间
js中的闭包是函数
闭包要解决的问题
1、在函数外部访问不到函数内部的数据
2、要解决的问题就是需要在外部间接的访问函数内部的数据
闭包的基本结构
function outer(){
var data = "数据";
return function(){
return data;
}
}
function outer(){
var data = "数据";
var data1 = "数据1";
return {
getData:function(){
return data;
},
getData1:function(){
return data1;
}
}
}
function outer(){
var data = "数据";
return {
getData:function(){
return data;
},
setData:function(value){
data = value;
return data;
}
}
}
4.闭包的作用
如果把数据放在全局作用域内,那么所有人都可以随意修改,这个数据就不再可靠。
闭包可以创建一个私有空间,在这个空间内部的数据,外部无法直接访问
外部空间想要访问函数内部的数据,只能通过闭包提供的指定的方法,在这个方法内部
可以设置一些校验规则,让数据变得更加的安全。
六、JavaScript高级第六天
1.闭包练习
setTimeout的执行时机
所有的主任务的代码执行完毕之后,去检查所有的setTimeout回调函数,如果到时间了就执行
用闭包来解决回调函数在调用的时候访问的是全局的变量
在闭包中创建一个变量,来单独存储当前的回调函数需要的数据,
在调用的时候就会去使用这个单独的数据,而不是去访问全局变量
注册点击事件的时候
点击事件在触发的时候访问的是全局的变量
在闭包中创建一个变量,来单独存储当前的事件处理函数需要的数据,
在调用的时候就会去使用这个单独的数据,而不是去访问全局变量
2.闭包缓存
缓存:将常用的数据进行存储,以提升性能
硬件缓存
浏览器缓存
CDN
内存型数据库
如何用闭包实现缓存
1、写一个闭包在闭包中创建一个对象,用来做缓存的存储对象
2、在闭包中创建一个对象,用来做缓存的存储对象
3、在闭包中创建一个数组,用来存储换中的键
4、返回一个函数,这个函数需要两个参数,一个是key 一个是value
5、在返回的函数中,判断传入的value是否为undefined
6、如果为Undefined 则表示是获取值,就直接返回在第一步创建的缓存对象中指定的键对应的值
7、如果不为Undefined 则表示是设置值
8、在缓存对象中设置指定的key的值为value
9、把key加入存储key的数组
10、判断key数组是不是超出了缓存大小限制
11、如果超出限制,删除数组第一个元素(使用shift),获取到删除的key
12、使用删除的key删除缓存对象中存储的值(delete)
3.使用缓存解决斐波那契数列的性能问题
就是将已经计算过的数字缓存进一个数组中,下次再来访问的时候,直接在数组中进行查找,如果找到直接使用,如果没有找到,计算后将数字存入数组,然后返回该数字
4.沙箱模式
沙箱模式就是一个封闭的独立的环境
沙箱模式的基本模型
(function(){
//变量定义
//逻辑代码
//如果需要,向window对象添加成员,以暴露接口
})()
第三方框架
插件
独立的组件
沙箱的优势:1、沙箱模式使用的是IIFE,不会再外界暴露任何的全局变量,也就不会造成全局变量污染
2、沙箱中的所有数据,都是和外界完全隔离的,外界无法对其进行修改,也就保证了代码的安全性
沙箱的原理:函数可以构建作用域!上级作用域不能直接访问下级作用域中的数据
5.函数的四种调用模式
函数模式
this--->window方法模式
this---->调用方法的对象构造函数模式
this----->new出来的对象
工厂模式
寄生模式-
上下文模式
- this----->指定的是谁就是谁
- call 函数.call(对象,arg1,arg2,arg3,...argn)
apply 函数.apply(对象,数组)
都可以用来改变this的指向为参数的第一个值
call是使用单独的每一个参数来传参
apply是使用数组进行传参的,这个数组在调用的时候,会被意义拆解,当做函数的每一个采参数call在函数的形参个数确定的情况下使用
apply在函数的形参个数不确定的情况下使用
this指向不同
七、JS高级总复习
1.Javascript基础复习
2.面向对象
- 把解决问题的重点放在解决问题相关的对象上
- 封装/继承/多态
- 对象:无序的键值对
- 属性:数值类型的
- 方法:函数类型的
- 创建对象的方法
- 字面量:用完之后不可复用
- 内置对象创建:a)创建的是空对象,需要手动添加属性 b)动态特性:创建好对象后,可以给对象添加属性和方法
- 工厂函数:定义一个对象,给他动态添加属性,返回
- 自定义构造函数:a)也是函数的一种,一般用来初始化对象 b)和new一起出现,new创建一个对象,构造函数初始化对象 c)返回new创建的对象 d)如果return的基本类型,不影响,仍返回new对象 / 返回Object类型,返回这个Object
- 自定义构造函数的执行过程:a)先使用new创建对象 b)把new创建出来的对象交给构造函数的this
c) 在构造函数内部通过this给对象封装方法
- 原型
- 在构造函数创建出来的时候默认会创建一个与对象与之关联,这个对象就是原型对象
- 访问 构造函数.prototype / 对象._ proto _
- 原型的使用:直接替换/混入式添加属性和方法/经典继承
- 原型链:每个对象都有原型对象,原型对象又有原型对象
3.Function
- 创建函数
4.递归
- 化归思想
- 案例:求和、阶乘、斐波那契数列、获取所有页面节点
5.作用域
- 词法作用域
- 变量提升
- JS执行阶段
- 预解析阶段
- 执行阶段
6.作用域链
- 外部无法访问内部作用域
- 内部可访问外部
7.闭包
- 封闭的对外不公开的空间
- 外面访问不到
- 外部访问只能通过内部的接口
- 作用:保护数据
- 案例:返回多个值/设置及获取、歌曲播放列表、解决斐波那契数列问题、闭包对缓存实现了一个保护作用
- jQuery实现缓存
- 定义一个对象存储数据
- 定义一个数组存储键:a)记录顺序 b)记录长度,超容量判断
8.沙箱模式
- 一个封闭的对外隔离的环境
- 避免外界窃取内部的数据
- 使用自调用(IIFE)函数实现
- 限制作用域
- 自调用函数没有名字
- 代码结构
- 最上面:定义变量
- 中间:逻辑代码
- 下面:暴露接口(有利于代码压缩)
1.最后及加上window
2.给函数一个形参
3.形参.变量 = 变量
- 作业:封装第三方插件、封装框架
9.函数调用模式
- 函数调用模式
- this指向window
- 方法调用模式
- this指向与之关联的对象
- 构造函数调用模式
- this指向new创建的对象
- 上下文调用模式
- call(对象,[],[],..[])
- apply(对象,[])
- 可以用apply实现借用构造函数
- 在当前函数使用其他函数.apply()
10.注册事件兼容性
- addEventListenter(事件,处理函数)
- attachEvent(on 事件,处理函数)
- 回调函数的this的指向与其他两个不同
- on事件 = 处理函数
- 案例:
- 歌曲管理案例
- 方法写在原型
- 属性写在构造函数内
- Tab栏切换案例
- 歌曲管理案例