目录
对象原型 等价于 构造函数原型对象 实例对象._proto_ === 构造函数.prototype
class son extend Father { constructor(){} }
利用父亲的实例的_proto_属性访问, 别忘了利用construcor指回原来的构造函数
9.1.1 arr.forEach( function (value, index, array){})
9.3.1Object.defineProperty方法 vue会用到
fn.apply(调用者,[参数]) 参数必须包含在数组(伪数组)里
fn.bind(把this指向谁,参数1,参数2,...) 只改变this指向,不调用!
10.6 闭包closure-------内部函数访问外部函数的局部变量
13.2.2 实例方法:startWith() 和 endWith()
1.面向对象
面向对象相当于盖浇饭, 需要什么口味的,就浇什么口味的汁(适合多人维护)
面向过程就是做一份蛋炒饭
2.ES6中的类和对象(抽象 和 具体)
泛指某一大类 和 特指某一个
2.1 创建类
2.2 类constructor 构造函数
类添加方法
- 类里面所有函数不需要加function
- 类里面多个函数或方法之间不需要添加逗号分隔
3.类的继承
子承父业,儿子可以继承父亲的一些属性和方法
但子类和父类都拥有各自的constructor 父类里方法的参数用的是父类condtructor的,子类想给父类的方法传参调用,必须要用super关键字,即调用父类的构造函数
原因是this指向不同
子类的构造函数中的 this指向 子类 构造函数创建的那个实例
父类的构造函数中的 this指向 父类 构造函数创建的那个实例
所以要调用父类里的函数(有参数的)必须先在子类构造函数里先调用父类的构造函数super,
且super必须放在子类this之前
3.1super 关键字
子类不仅可以调用父类的构造函数,也可以调用父类的普通函数
super相当于ES5 的call(), apply()改变this指向
继承属性和方法的查找原则(就近原则)
- 继承中,如果实例化子类输出一个方法,先看子类有没有这个方法,如果有就先执行子类的
- 如果子类没有,就去查找父类有没有这个方法,有就执行(就近原则)
4.使用类的2个注意点
- ES6里面没有变量提升,所以必须先定义类,才能通过类实例化对象
- 类里面的共有属性和方法必须通过加this使用
- 在类中所有的方法都自动定义在prototype的属性上
5.类里面this的指向问题
this开辟了一个新空间,表示在哪里添加变量。
谁调用就指向谁, 方法this指向不是实例的时候又想要调用实例的属性,就用全局that调用
<button>我是谁的按钮</button>
<script>
let that = null
class Star {
constructor(uname, age) {
//以下这些数据都添加在实例里面了 方法不能直接使用 必须要用this指明使用
that = this //将实例地址赋值给that
this.uname = uname;
this.age = age;
this.btn = document.querySelector('button') //给实例对象添加获取一个按钮元素
this.btn.addEventListener('click', this.sing)
}
sing() {
// console.log(this.uname);undefined //this指向调用者 ,这里是btn调用 而btn没有uname
console.log(that.uname); //如果想用实例对象里的 就要用全局that保存this
}
dance() {
console.log(this.age);
}
}
let ldh = new Star("刘德华", 18); //刘德华拥有 大家都可以使用里面的方法和属性
ldh.dance() //实例对象调用
</script>
6.面向对象案例 tab栏 动态添加标签页
- 先创建一个tab 类 (最大的父盒子)
- 类里面 获取所有要用的子元素,初始化(给所有子元素绑定点击事件)
- 写上所有功能需求的函数
- 补充完善里面的每一个功能函数
new Tab('#tab') //传对象
2.
6.构造函数和原型
在ES6之前是没有类的概念的 是通过构造函数创造一个对象
6.1 实例成员和静态成员
- 实例成员是通过this添加的,
- 静态成员是直接给构造函数本身添加的Star.sex = '男'
- 实例成员只能通过实例化的对象访问
- 静态成员只能通过构造函数来访问
6.2 构造函数存在浪费内存问题
ldh.sing=== zxy.sing //false 比较的是两个sing函数的地址 地址不同
所以一些不变的方法(没有参数)可以放到原型对象上供大家使用,减少内存浪费
6.2.1 构造函数的原型 prototype
- 原型是什么? 一个对象,我们称为prototype为原型对象
- 原型的作用? 共享方法,避免开辟不必要的内存空间。
- 一般情况下,我们的公共属性定义到构造函数里面,公共的方法我们放到原型对象身上。
实例对象.sing() 可以调用
方法的查找规则:
首先看实例对象上是否有sing方法,如果有就执行这个对象上的sing方法,
如果没有,因为有_proto_的存在,就去构造函数的原型对象prototype身上查找sing这个方法
6.2.2 对象原型 _proto_
只要是对象,它就会有_proto_原型
这个属性开发中并不能直接使用, 只是在内部给对象的查找提供了一个方向
对象原型 等价于 构造函数原型对象 实例对象._proto_ === 构造函数.prototype
6.2.3构造函数 constructor
对象原型即构造函数原型对象里面都有一个属性: constructor属性 指回构造函数本身
6.2.4 构造函数,实例,原型对象三者之间的关系
6.2.5 原型链
- 只要是对象就一定有_proto_属性,即原型,而原型是一个对象
- 每个函数都有一个prototype属性,函数通过prototype属性去原型链查找
- 对象通过原型链这条线路查找 (内部查找)
- ldh实例对象的原型是一个对象,而这个对象是Object的实例对象
- 是函数必定有prototype属性, 有prototype属性,必定有原型链即有爸爸—爸爸的爸爸—null。
- 是对象必定有_proto_属性。[[prototype]]是_proto_的书面写法,不同的浏览器输出写法不同。
- 构造函数和普通函数既是函数,又是对象,所以他们两个属性都有,只是普通函数的这两个属性都指向同一个对象,
- 而构造函数是普通函数的实例,他的原型指向普通函数的原型对象。
6.2.6 JavaScript的成员查找机制(规则)
实例对象——爸爸——————————爸爸的爸爸——————null
内部查找是根据原型自动依次往上查找,即原型链
我无论在那一层添加了属性,它都能根据原型链找到这个属性
实例对象访问的东西要么来自本身,要么来自构造函数,要么来自原型链
外面想访问函数里的this,就需要用一个全局变量that将this存储起来
6.2.7 原型对象中this的指向
不管是构造函数里的this还是原型对象里的this,指向的都是调用者,也就是实例对象
6.2.8 原型对象的一个应用————扩展内置对象
通过原型对象,对原来的内置对象进行扩展自定义的方法。比如给数组添加自定义求偶数和功能
7.继承方法
7.1 利用ES6 类继承
class son extend Father { constructor(){} }
类中所有的方法都定义在prototype的属性上,所以类的继承 也就同时继承了 构造函数+原型对象
7.2 组合继承
ES6之前没有extends继承 我们可以通过构造函数+ 原型对象 模拟实现继承, 被成为 组合继承,
,需要两步,较为繁琐。
7.2.1 借用父构造函数实现继承
call(调用者,参数1,参数2,...)
Father.call() 改变Father的this指向
7.2.2 借用原型对象继承
利用父亲的实例的_proto_属性访问, 别忘了利用construcor指回原来的构造函数
8.类的本质
class Star{}
类的本质是一个函数, 是构造函数的另一种写法,构造函数有的它都有。
ES6 之前通过 构造函数+原型 实现 面向对象 编程
ES6 通过 类 实现 面向对象 编程 是构造函数的语法糖
9.ES5 新增方法
9.1 ES5新增 数组的方法
9.1.1 arr.forEach( function (value, index, array){})
回调函数的三个参数:每一个数组元素 下标 数组名
相当于增强版的for循环 也就是 v-for (item,index)in array
9.1.2 filter
筛选出符合条件的value放入新数组中
value >= 20 得到的是布尔值,返回结果为true的成员组成新数组
9.1.3 some()
是否有返回条件的数,有返回true
//false
查询符合条件的商品思想:fliter
- 封装一个遍历数组生成表格的函数fn,只需要传一个数组进去遍历就可以了。
- 先调用fn遍历一个数组的全部数据显示出来,
- 利用filter筛选选出符合条件的数存进新数组,清除所有数组后再调用fn遍历新数组
查询商品名 思想:some (找到第一个立马跳出循环) 适合用于查找数组中唯一的一个元素
- if 符合条件 就将这个 value push到新数组 返回true跳出some循环
- 然后利用fn遍历新数组
- forEach和 filter中的return不会跳出循环 ,会把所有元素遍历完,效率低
9.2 ES5新增 字符串的方法
trim方法去除字符串两端的空格
会删除两边的 不会删除中间的空格
应用场景:表单输入为空格时 可以视为用户未输入内容
9.3 ES5新增 对象方法
9.3.1Object.defineProperty方法 vue会用到
默认不可枚举,不可删除不可重新设置参数的值true或false,不可重写
delete obj.address ×
9.3.2 Object.keys()
获取对象的所有属性名
10.函数的进阶
10.1 函数定义方式 三种
10.2 函数的调用方式
10.3 函数内部的this指向
另外 call apply bind 可以改变this指向
fn.call(调用者,参数1,参数2...)
主要应用:
继承父亲构造函数 但没继承原型 还是ES6的类好用
fn.apply(调用者,[参数]) 参数必须包含在数组(伪数组)里
主要应用:利用数学内置对象求最大最小值 不过似乎用 Math.max(...arr)更好
Math.max.apply (Math,arr)
fn.bind(把this指向谁,参数1,参数2,...) 只改变this指向,不调用!
返回的是原函数改变this之后的新函数
主要应用: 如果函数不需要立即调用,但又想改变这个函数内部的this指向此时用bind
另一个应用场景:
把构造器中的this作为参数传给方法使用
方法里的this还是可以指向想要的调用者
调用者是每一个li
call apply bind 总结
10.4 JS当中的严格模式 IE10+
开启严格模式
1.为脚本开启严格模式
2.为函数开启严格模式
严格模式下的语法规范
1. 变量规定
- 变量必须先声明,在使用 (正常模式不声明则默认为全局变量)
- 不能删除已经声明的变量 delete x;语法是错误的
2. 严格模式下,this的指向问题
- 全局作用域下的this指向undefined !! (正常模式下是window)
- 构造函数不加new调用,this会报错
- 定时器this还是指向window
3.函数变化
- 函数不能有重名参数 function (a,a){} ×
- 函数必须声明在顶层,且不允许在非函数的代码块声明函数 // 为了与新版本接轨
10.5 高阶函数,
callback&&callback()意思是 若callback存在就执行callback()
1.回调函数是最后执行的,等函数里所有代码执行完之后才执行回调函数
2.闭包就是典型的高阶函数,将一个函数作为返回值。
10.6 闭包closure-------内部函数访问外部函数的局部变量
重点:被访问的函数才是闭包函数
闭包产生条件:
- 内部函数
- 访问外部函数的局部变量
在JS中闭包和异步 是两大难点
实现闭包的两种方式:
1.内部函数访问外部函数的局部变量
2.外面的作用域访问函数内部的局部变量 (这种方式需要return一个函数出去)
闭包的主要作用:延长了变量的作用范围和生命周期
闭包的应用———解决变量泄露的问题(循环,定时器等)
异步任务三种情况:
- 定时器中的回调函数
- DOM事件中的回调函数
- ajax中的回调函数
异步任务只有触发了,才会执行 (如3秒之后,点击之后)
而for循环属于同步任务会立马执行,i已经加加完了才执行异步任务
而这时可以使用小闭包(立即执行函数)来存i值 或者for用let 声明 i
应用1:点击li打印当前索引
这里不适合使用闭包
应用2: 3秒之后打印li的内容
应用2:计算打车价格
<!-- 面向对象:闭包应用 计算打车价格
用户输入公里数 计算打车价格 起步价13(3公里内) 之后每多一公里加5元
堵车的话另外收加10元 -->
<script>
// function fn (){}
// fn() 我写一个函数需要调用才执行
// 但立即执行函数不需要调用
var car = (function () { //这个匿名函数就是闭包
var start = 13; //起步价
var total = 0; //总价
// 功能1:按公里计费
return {
// 立即执行函数返回一个装多个功能函数的对象
// 外部调用就能使用函数内的变量了
getTotal: function (n) { //用户传进公里数
if (n <= 3) {
total = start; //内部函数使用了外部变量 闭包
} else {
total = start + (n - 3) * 5;
}
return total;
},
// 功能2: 拥堵之后的费用
yd: function (flag) {
return flag ? total + 10 : total;
},
};
})();
//巧妙之处就在于:立即执行函数 无需小括号调用 否则普通函数需要car().yd()才能调用
car.getTotal(5); //car返回的是一个对象,直接点调用里面的函数
car.yd()
</script>
闭包考题
思考题1:
思考题2:
闭包总结
10.7 递归 (函数内部自己调用自己) 求数学题!
超出了栈的最大容量,会报错
10.7.1 利用递归求阶乘
核心思路:
不管是求1~n之间的阶乘,还是求1~n之间的累加和,都是用 前一项n ×或+ 后一项,只不过后一项是通过递归不断调用求得fn(n-1)。
我×我自己减1 我再×我自己减1....每一个我都是减一后的我 直到我符合条件终止递归
10.7.2 利用递归求斐波那契数列 (每次调用返回的最终都是1累加起来的结果)
10.7.3 利用递归遍历数据 !!(这里不需要终止条件,直接利用条件判断是否需要执行递归)
var data = [
{
id: 1,
name: "家电",
goods: [
{
id: 11,
gname: "冰箱",
goods: [{ id: 111, ggname: "海尔" }],
},
{
id: 12,
gname: "洗衣机",
},
],
},
{
id: 2,
name: "服饰",
},
];
// console.log(data);
// 用forEach遍历数组里的每一项item
function getId(arr, id) {
var o = {};
arr.forEach(function (item) {
//第一层 有这个id的话就返回
if (item.id === id) {
// console.log(item);
o = item;
}
//第一层没有的话就去第二层找
//里面有goods这个数组且长度不为0
else if (item.goods && item.goods.length > 0) {
o = getId(item.goods, id);
//得到的o只是return给了当前这个getId函数,最外层没有接受到o值,需要o接收
}
});
return o; //把最终的值return出去使用
}
console.log(getId(data, 111));
10.8 浅拷贝和深拷贝
10.8.1 浅拷贝 只拷贝基本数据或复杂数据的地址
浅拷贝 拷贝复杂数据会影响源对象 其中一个变另一个也跟着变
新增 Object.assign(拷贝给谁,拷贝谁)
obj[k]里存的是地址 o[k]接收的也是地址 浅拷贝
10.8.2 深拷贝 里层利用递归实现深层拷贝
最终都是转换成基本数据的拷贝
11. 正则表达式 多用于表单的验证
边界符
字符类
[] 含有就行
[^ $]限定多选一 ,只能由其中一个 ^&一起精确匹配
[^]取反,不能含有里面的任何一个
量词符
量词重复某个模式出现的次数
括号总结
网址里都很多小工具,包括正则表达式测试工具,验证工具里面有很多正则例子
预定义类
表单验证
验证的过程基本是一样的 ,可以封装成一个函数。
正则表达式中的替换
12.ES6
let const声明的变量只能声明再使用
12.1 let关键字
全局i
块级作用域i
12.2 const关键字 声明常量
const声明的常量 若是 基本数据类型不可以更改值,若是复杂数据类型不可以更改地址,但里面的值可以更改;即复杂数据类型不可以重新被赋值。
const声明的变量的值不可以发生变化,所以javascript引擎不需要实时监测值的变化,所以使用const效率更高,能使用const尽量使用const。
12.3 解构赋值
12.3.1数组解构
中括号在等号左边代表解构
12.3.2 对象解构
{}在左边代表解构 以下两种写法:
12.4 箭头函数
参数只有一个的时候,小括号可以省略;
代码只有一句的时候,大括号和return可以省略。
箭头函数没有this,箭头函数当中的this指向定义时候爸爸的this
对象不是函数,不生成作用域。
12.5 剩余参数
当实参个数大于形参个数的时候,对于普通函数来说可以使用arguments,
但由于箭头函数没有arguments,所以需要借助剩余参数...
12.6 剩余参数和解构配合使用
13. ES6的新增内置对象
13.1 数组的新增方法
13.1.2 扩展运算符 ————相当于把数组的中括号去掉
应用1:作为参数传递
应用2:合并数组
arr1.push(参数1,参数2,....) 在数组尾部追加元素
应用3:
将伪数组(只有长度没有方法,有length属性)转换成真正的数组[ ] ,就可调用数组的方法了
方法1:
方法2:
13.1.3 构造函数的方法: Array.from( )
13.1.4 实例的方法 find()
index没用到可以省略不写
13.1.5 实例方法 : findIndex()
区分: some()方法返回的是布尔值
13.1.6 实例方法:includes()
数组包含2吗?
13.2 String的扩展方法
13.2.1 模板字符串
模板字符串里的 变量或函数 要写在 ${ } 里面
13.2.2 实例方法:startWith() 和 endWith()
13.2.3 实例方法:repeat()
13.3 Set数据结构 数组去重原理
Set相当于数组数据结构,但里面存储的没有重复的值
可以用...扩展符将其转换成数组 arr = [ ...s ]
jq的size相当于length
从Set结构中取值,需要用遍历
应用:搜索关键字