面向对象
特性:继承,封装,多态
对象
对象是一组无序的相关的属性和方法的集合,所有的事物都是对象,对象是由属性和方法组成的。
属性:事物的特征,在对象中用属性来表示。
方法:事物的行为,在对象中用方法来表示
类class
泛指某一大类
抽取(抽象)对象共有的属性和方法封装成一大类
创建类
class 类名{
}
//创建实例对象
var xx=new 类名();
//类必须使用实例化对象
constructor构造函数
constructor()方法是类的构造函数用于传递参数返回实例对象
通过new命令生成对象实例时,自动调用该方法,如果不定义则自动创建。
class 类名{
constructor(参数1,参数2....){
this.参数1=参数1;
this.参数2=参数2;
.....
}
}
var xx=new 类名();
xx.参数1;
在类中添加方法,方法之间不加逗号分隔,同时方法不需要function关键字
类的继承
class Father{
}
class Son extends Father{
//extends关键字可以继承父类中的属性和方法
}
super关键字
super关键字用于访问和调用对象父类上的函数,可以调用父类的构造函数,也可以调用父类的普通函数,
注:子类在构造函数中使用super必须放到this前面(必须先调用父类的构造函数再使用子类的构造函数)
1.在ES6中类没有变量提升,所以先定义类才能通过类实例化对象
2.类里面的共有的属性和方法一定要加this使用
3.类里面的this指向问题
4.constructor里面的this指向实例化对象方法里的this指向这个方法的调用者。
构造函数(ES6之前)
在ES6之前通过构造函数创建对象的
构造函数是一种特殊的函数,主要用来初始化对象,即为对象成员变量赋初始值它总与new关键字一起使用。
实例成员与静态成员
静态成员:在构造函数本身上添加的成员称为静态成员,只能由构造函数本身访问
实例成员:在构造函数内部创建的对象成员称为实例成员,只能由实例化的对象访问
构造函数方法很好用,但存在浪费内存的问题。
构造函数原型prototype
function Star(name){
this.name=name
}
Star.prototype.sing=function(){
}
1.构造函数通过原型分配的函数是所有对象所共享
2.每个构造函数都有一个prototype,指向另一个对象
3.我们可以那些不变的方法直接定义在prototype对象上,这样所有的对象实例可共享。
4.一般我们的公共属性定义到构造函数里面,公共的方法我们放到原型对象身上。
对象原型
对象都会有一个__proto__属性指向构造函数的prototype原型对象,之所以我们对象可以使用构造函数prototype原型对象的属性和方法就是因为有—proto—原型的存在。
—proto—对象原型和原型对象protype等价(true)
—proto—对象原型执行机制
constructor构造函数
对象原型和构造函数原型对象里面都有一个属性constructor属性,主要用来记录该对象引用于拿哪个构造函数它可以让原型对象重新指向原来的构造函数。
原型对象的this指向
构造函数中的this指向我们实例对象
原型对象里面放的是方法,这个方法里面的this指向的是这个方法的调用者也就是实例对象。
继承
ES6前构造函数+原型对象模拟实现继承,被称为组合继承
call()
调用这个函数并且修改函数运行时this的指向
fn.call(thisArg,arg1…);
借用构造函数继承父类的属性和方法
借用父构造函数继承属性
原理:通过call()把父类的this指向子类的this可以实现子类继承父类的属性
// 1. 父构造函数
function Father(uname, age) {
// this 指向父构造函数的对象实例
this.uname = uname;
this.age = age;
}
// 2 .子构造函数
function Son(uname, age, score) {
// this 指向子构造函数的对象实例
Father.call(this, uname, age);
this.score = score;
}
var son = new Son('刘德华', 18, 100);
console.log(son);
借用父构造函数继承方法
原理:1.将子类所共享的方法提取出来,让子类的prototype原型对象=new父类()
2.本质:子类原型对象等于是实例化父类因为父类实例化之后另外开辟空间不影响原来的父类原型对象
3.将子类的constructor从新指向子类的构造函数
// 1. 父构造函数
function Father(uname, age) {
// this 指向父构造函数的对象实例
this.uname = uname;
this.age = age;
}
Father.prototype.money = function() {
console.log(100000);
};
// 2 .子构造函数
function Son(uname, age, score) {
// this 指向子构造函数的对象实例
Father.call(this, uname, age);
this.score = score;
}
// Son.prototype = Father.prototype; 这样直接赋值会有问题,如果修改了子原型对象,父原型对象也会跟着一起变化
Son.prototype = new Father();
// 如果利用对象的形式修改了原型对象,别忘了利用constructor 指回原来的构造函数
Son.prototype.constructor = Son;
// 这个是子构造函数专门的方法
Son.prototype.exam = function() {
console.log('孩子要考试');
}
var son = new Son('刘德华', 18, 100);
console.log(son);
console.log(Father.prototype);
console.log(Son.prototype.constructor);
类的本质
本质就是一个函数(构造函数的另一种写法)
有原型对象prototype里面有constructor指向类本身
可以通过原型对象添加方法
类创建的实例对象有—proto—原型指向类的实例化对象
ES5中新增的方法
数组方法
遍历迭代方法:forEach()、map()、filter()、some()、every()
arr.forEach()
arr.forEach(function(value,index,arr){});
value:每个数组元素
index:索引
arr:整个数组元素
arr.filter()
创建一个新的数组,新数组中的元素是通过检查指定数组中符合条件的元素
arr.filter(function(value,index,arr){});
返回一个新数组
arr.some()
检测数组中元素是否满足指定条件
arr.some(function(value,index,arr){});
返回true或false
some和forEach区别
在forEach里面return不会终止迭代
在some里面遇到return true 终止遍历迭代效率高
字符串方法
trim()去除字符串两端的空格
不会影响原字符串本身,返回的是一个新的字符串
对象方法
Object.keys()
返回一个所有元素为字符串的数组
Object.defineProperty()
定义新属性或修改原有的属性
Object.defineProperty(obj,prop,descriptor);
obj:必须,目标对象
prop:必须:需定义或修改的属性的名字
descriptor:必须目标属性所拥有的特性
函数进阶
函数的定义与调用
1.普通函数
2.对象的方法
3.构造函数
4.绑定事件
5.定时器函数
6.立即执行函数
函数内this的指向
函数 | 指向 |
---|---|
1.普通函数 | window |
2.对象的方法 | 实例化对象 |
3.构造函数 | 该方法所属的对象 |
4.绑定事件 | 绑定事件对象 |
5.定时器函数 | window |
6.立即执行函数 | window |
改变函数内部this的指向
call()
fn.call(thisArg, arg1,arg2…);
thisArg:this指向
arg1:指定参数
可以调用函数,改变this指向,主要用于继承父类的属性
apply()
fn.apply(thisArg, [arg1]);
thisArg:this指向
arg1:参数必须为数组
可以调用函数,改变this指向,
返回值就是函数的返回值
bind()
fn.bind(thisArg, arg1,arg2…);
thisArg:this指向
arg1:指定参数
不可以调用函数,改变this指向,
严格模式
可以应用到整个脚本或函数中
1.为脚本开启严格模式
2.为函数开启严格模式
使用:在所有的语句之前放一个特定的语句"use strict"
变化
1.变量必须先定义在使用
2.严禁删除已经声明的变量
3.严格模式下全局作用域中函数this指的是undefined
4.构造函数不加new实例化赋值会报错
5.new实例化的构造函数指向创建的对象实例
6.定时器this指向window
7.函数名中不能有重名的参数,函数必须声明在顶层
8.不允许在非函数的代码块内声明函数
高阶函数
对其他函数进行操作的函数,它接收函数作为参数或者将函数的返回值输出
//1.函数作为参数输出
function fn(a, b, callback) {
console.log(a + b);
// callback && callback();
if (callback) {
callback();
}
}
//2.函数的返回值
function fn(){
return function(){
}
}
闭包
指有权访问另一个函数作用域中变量的函数(一个作用域可以访问另一个函数内部的局部变量);
function fn() {
var num = 10;
var u = function() {
console.log(num);
}
return u;
};
console.log(fn());
递归
一个函数在内部可以调用其本身,这个函数就是递归函数
注:递归函数的作用和循环效果一样,由于递归很容易发生栈溢出错误,所以必须加退条件return
// 利用递归函数求1~n的阶乘 1 * 2 * 3 * 4 * ..n
function fn(n) {
if (n == 1) {
return 1;
}
return n * fn(n - 1);
}
console.log(fn(3));
浅拷贝
浅拷贝只是拷贝一层, 更深层次对象级别的只拷贝引用。
深拷贝
深拷贝拷贝多层, 每一级别的数据都会拷贝。
正则表达式
创建
方式一:通过调用RegExp对象的构造函数创建
var regexp = new RegExp(/123/);
console.log(regexp);
方式二:利用字面量创建 正则表达式
var rg = /123/;
测试
test() 正则对象方法,用于检测字符串是否符合该规则,该对象会返回 true 或 false,其参数是测试字符串。
边界符
边界符 | 说明 |
---|---|
^ | 表示匹配行首的文本(以谁开始) |
$ | 表示匹配行尾的文本(以谁结束) |
字符类
[] 方括号
表示有一系列字符可供选择,只要匹配其中一个就可以了
[-]方括号内部范围
var reg = /^[a-z]$/ //26个英文字母任何一个字母返回 true - 表示的是a 到z 的范围
[^]方括号内部取反符
//取反 方括号内部加上 ^ 表示取反,只要包含方括号内的字符,都返回 false 。
var reg2 = /^[^a-zA-Z0-9]$/;
字符组合
var reg1 = /^[a-zA-Z0-9]$/; // 26个英文字母(大写和小写都可以)任何一个字母返回 true
量词符
量词 | 说明 |
---|---|
* | 重复0次或更多次 |
+ | 重复1次或更多次 |
? | 重复0次或1次 |
{n} | 重复n次 |
{n,} | 重复n次或更多次 |
{n,m} | 重复n到m次 |
预定义类
量词 | 说明 |
---|---|
\d | 匹配0-9之间的任一数字 |
\D | 匹配0-9之间的以外字符 |
\w | 匹配任意的字母、数字、下划线 |
\W | 匹配任意的字母、数字、下划线以外的字符 |
\s | 匹配空格(包括换行符、制表符、空格符等) |
\S | 匹配非空格的字符 |
正则替换replace
replace() 方法可以实现替换字符串操作,用来替换的参数可以是一个字符串或是一个正则表达式。
ES6
let
- let关键字就是用来声明变量的
- 使用let关键字声明的变量具有块级作用域
- 在一个大括号中 使用let关键字声明的变量才具有块级作用域 var关键字是不具备这个特点的
- 防止循环变量变成全局变量
- 使用let关键字声明的变量没有变量提升
- 使用let关键字声明的变量具有暂时性死区特性
const
声明常量,常量就是值(内存地址)不能变化的量
具有块级作用域
if (true) {
const a = 10;
}
console.log(a) // a is not defined
声明常量时必须赋值
const PI; // Missing initializer in const declaration
常量赋值后,值不能修改
const PI = 3.14;
PI = 100; // Assignment to constant variable.
const ary = [100, 200];
ary[0] = 'a';
ary[1] = 'b';
console.log(ary); // ['a', 'b'];
ary = ['a', 'b']; // Assignment to constant variable.
小结
-
const声明的变量是一个常量
-
既然是常量不能重新进行赋值,如果是基本数据类型,不能更改值,如果是复杂数据类型,不能更改地址值
-
声明 const时候必须要给定值
let、const、var 的区别
- 使用 var 声明的变量,其作用域为该语句所在的函数内,且存在变量提升现象
- 使用 let 声明的变量,其作用域为该语句所在的代码块内,不存在变量提升
- 使用 const 声明的是常量,在后面出现的代码中不能再修改该常量的值
解构
ES6中允许从数组中提取值,按照对应位置,对变量赋值,对象也可以实现解构
数组解构
let [a, b, c] = [1, 2, 3];
console.log(a)//1
console.log(b)//2
console.log(c)//3
//如果解构不成功,变量的值为undefined
对象解构
let person = { name: 'zhangsan', age: 20 };
let { name, age } = person;
console.log(name); // 'zhangsan'
console.log(age); // 20
let {name: myName, age: myAge} = person; // myName myAge 属于别名
console.log(myName); // 'zhangsan'
console.log(myAge); // 20
总结
- 解构赋值就是把数据结构分解,然后给变量进行赋值
- 如果结构不成功,变量跟数值个数不匹配的时候,变量的值为undefined
- 数组解构用中括号包裹,多个变量用逗号隔开,对象解构用花括号包裹,多个变量用逗号隔开
- 利用解构赋值能够让我们方便的去取对象中的属性跟方法
箭头函数
ES6中新增的定义函数的方式。
() => {} //():代表是函数; =>:必须要的符号,指向哪一个代码块;{}:函数体
const fn = () => {}//代表把一个函数赋值给fn
//函数体中只有一句代码,且代码的执行结果就是返回值,可以省略大括号
function sum(num1, num2) {
return num1 + num2;
}
//es6写法
const sum = (num1, num2) => num1 + num2;
//如果形参只有一个,可以省略小括号
function fn (v) {
return v;
}
//es6写法
const fn = v => v;
箭头函数不绑定this关键字,箭头函数中的this,指向的是函数定义位置的上下文this
const obj = { name: '张三'}
function fn () {
console.log(this);//this 指向 是obj对象
return () => {
console.log(this);//this 指向 的是箭头函数定义的位置,那么这个箭头函数定义在fn里面,而这个fn指向是的obj对象,所以这个this也指向是obj对象
}
}
const resFn = fn.call(obj);
resFn();
- 箭头函数中不绑定this,箭头函数中的this指向是它所定义的位置,可以简单理解成,定义箭头函数中的作用域的this指向谁,它就指向谁
- 箭头函数的优点在于解决了this执行环境所造成的一些问题。比如:解决了匿名函数this指向的问题(匿名函数的执行环境具有全局性),包括setTimeout和setInterval中使用this所造成的问题
剩余参数
剩余参数语法允许我们将一个不定数量的参数表示为一个数组,不定参数定义方式,这种方式很方便的去声明不知道参数情况下的一个函数
function sum (first, ...args) {
console.log(first); // 10
console.log(args); // [20, 30]
}
sum(10, 20, 30)
剩余参数和解构配合使用
let students = ['wangwu', 'zhangsan', 'lisi'];
let [s1, ...s2] = students;
console.log(s1); // 'wangwu'
console.log(s2); // ['zhangsan', 'lisi']
ES6内置对象扩展
Array 的扩展方法
扩展运算符(展开语法)
扩展运算符可以将数组或者对象转为用逗号分隔的参数序列
let ary = [1, 2, 3];
...ary // 1, 2, 3
console.log(...ary); // 1 2 3,相当于下面的代码
console.log(1,2,3);
扩展运算符可以应用于合并数组
// 方法一
let ary1 = [1, 2, 3];
let ary2 = [3, 4, 5];
let ary3 = [...ary1, ...ary2];
// 方法二
ary1.push(...ary2);
将类数组或可遍历对象转换为真正的数组
let oDivs = document.getElementsByTagName('div');
oDivs = [...oDivs];
构造函数方法:Array.from()
将伪数组或可遍历对象转换为真正的数组
//定义一个集合
let arrayLike = {
'0': 'a',
'1': 'b',
'2': 'c',
length: 3
};
//转成数组
let arr2 = Array.from(arrayLike); // ['a', 'b', 'c']
方法还可以接受第二个参数,作用类似于数组的map方法,用来对每个元素进行处理,将处理后的值放入返回的数组
let arrayLike = {
"0": 1,
"1": 2,
"length": 2
}
let newAry = Array.from(arrayLike, item => item *2)//[2,4]
注意:如果是对象,那么属性需要写对应的索引
实例方法:find()
用于找出第一个符合条件的数组成员,如果没有找到返回undefined
let ary = [{
id: 1,
name: '张三'
}, {
id: 2,
name: '李四'
}];
let target = ary.find((item, index) => item.id == 2);//找数组里面符合条件的值,当数组中元素id等于2的查找出来,注意,只会匹配第一个
实例方法:findIndex()
用于找出第一个符合条件的数组成员的位置,如果没有找到返回-1
let ary = [1, 5, 10, 15];
let index = ary.findIndex((value, index) => value > 9);
console.log(index); // 2
实例方法:includes()
判断某个数组是否包含给定的值,返回布尔值。
[1, 2, 3].includes(2) // true
[1, 2, 3].includes(4) // false
String 的扩展方法
模板字符串
模板字符串中可以解析变量
模板字符串中可以换行
在模板字符串中可以调用函数
//模板字符串中可以解析变量
let name = '张三';
let sayHello = `hello,my name is ${name}`; // hello, my name is zhangsan
//模板字符串中可以换行
let result = {
name: 'zhangsan',
age: 20,
sex: '男'
}
let html = ` <div>
<span>${result.name}</span>
<span>${result.age}</span>
<span>${result.sex}</span>
</div> `;
//在模板字符串中可以调用函数
const sayHello = function () {
return '哈哈哈哈 追不到我吧 我就是这么强大';
};
let greet = `${sayHello()} 哈哈哈哈`;
console.log(greet); // 哈哈哈哈 追不到我吧 我就是这么强大 哈哈哈哈
实例方法:startsWith() 和 endsWith()
- startsWith():表示参数字符串是否在原字符串的头部,返回布尔值
- endsWith():表示参数字符串是否在原字符串的尾部,返回布尔值
let str = 'Hello world!';
str.startsWith('Hello') // true
str.endsWith('!') // true
实例方法:repeat()
repeat方法表示将原字符串重复n次,返回一个新字符串
'x'.repeat(3) // "xxx"
'hello'.repeat(2) // "hellohello"
Set 数据结构
ES6 提供了新的数据结构 Set。它类似于数组,但是成员的值都是唯一的,没有重复的值。
Set本身是一个构造函数,用来生成 Set 数据结构
const s = new Set();
Set函数可以接受一个数组作为参数,用来初始化。
const set = new Set([1, 2, 3, 4, 4]);//{1, 2, 3, 4}
实例方法
- add(value):添加某个值,返回 Set 结构本身
- delete(value):删除某个值,返回一个布尔值,表示删除是否成功
- has(value):返回一个布尔值,表示该值是否为 Set 的成员
- clear():清除所有成员,没有返回值
const s = new Set();
s.add(1).add(2).add(3); // 向 set 结构中添加值
s.delete(2) // 删除 set 结构中的2值
s.has(1) // 表示 set 结构中是否有1这个值 返回布尔值
s.clear() // 清除 set 结构中的所有值
//注意:删除的是元素的值,不是代表的索引
遍历
Set 结构的实例与数组一样,也拥有forEach方法,用于对每个成员执行某种操作,没有返回值。
s.forEach(value => console.log(value))