JS高级
构造函数
- 概念
- 是一种特殊的函数,主要用来初始化对象,即为对象成员变量赋初始值,它总与new一起使用。
- 在JS中,使用构造函数时要注意:
- 构造函数用于创建某一类对象,其首字母要大写
- 构造函数和new在一起使用才有意义
- new在执行时会做四件事:
- 在内存中创建一个新的空对象
- 让this指向这个新的对象
- 执行构造函数里面的代码,给这个新对象添加属性和方法
- 返回这个新对象(所以构造函数中不需要return)
- 在JS中,使用构造函数时要注意:
- 是一种特殊的函数,主要用来初始化对象,即为对象成员变量赋初始值,它总与new一起使用。
- 构造函数的原型prototype
- prototype是一个对象,也称为原型对象
- 原型的作用是共享方法
- 对象原型
- 实例对象有一个属性
_proto_
,指向prototype原型对象
- 实例对象有一个属性
- constructor构造函数
- 构造函数原型对象里面有一个属性constructor,constructor我们称为构造函数,因为它指向构造函数本身
- 构造函数、实例对象、原型对象的关系
- 构造函数的prototype属性指向了构造函数原型对象
- 实例对象是由构造函数创建的,实例对象的
_proto_
属性指向了构造函数的原型对象 - 构造函数的原型对象的constructor属性指向了构造函数,实例对象的原型的constructor属性也指向了构造函数
- 原型链
- 不管构造函数中的this,还是原型对象中的this,都指向new出来的实例对象
- 构造函数继承
- 继承属性 call()方法
- 继承方法 使用原型对象继承方法
-
- 将子构造函数所共享的方法提取出来,让子构造函数的prototype=new 父构造函数()
- 将子类的constructor重新指向子类的构造函数
- 本质就是子构造函数的原型对象等于是实例化父构造函数,这样不会影响父构造函数的原型对象
-
类
- 定义类
class 类名{}
- 利用类创建对象
var 对象名 = new 类名();
- 类的构造函数constructor
- constructor() 方法是类的构造函数(默认方法),用于传递参数,返回实例对象,通过 new 命令生成对象实例时,自动调用该方法。
- 一个类必须有constructor方法,如果没有显式定义,一个空的constructor方法会被默认添加。
- 注意点:
- 通过class 关键字创建类, 类名我们还是习惯性定义首字母大写
- 类里面有个constructor 函数,可以接受传递过来的参数,同时返回实例对象
- constructor 函数 只要 new 生成实例时,就会自动调用这个函数, 如果我们不写这个函数,类也会自动生成这个函数
- 多个方法之间不需要添加逗号分隔
- 生成实例 new 不能省略
- 语法规范, 创建类 类名后面不要加小括号,生成实例 类名后面加小括号, 构造函数不需要加function
- 类的继承
- 语法:
class Father {
}
class Son extends Father {
}
- super关键字
- 用于访问和调用父类上的函数,可以调用父类的构造函数,也可以调用父类的普通函数。
-
调用父类的构造函数
如果子类显式定义了constructor构造函数,那么在其构造函数中,必须调用super(),否则会报错。
这是因为子类自己的this对象,必须先通过父类的构造函数完成塑造,得到与父类同样的实例属性和方法,然后再对其进行加工,加上子类自己的实例属性和方法。如果不调用super方法,子类就得不到this对象。 -
调用父类的普通函数
-
// super 关键字调用父类普通函数
class Father {
say() {
return '我是爸爸';
}
}
class Son extends Father {
say() {
// super.say() 就是调用父类中的普通函数 say()
console.log(super.say() + '的儿子');
}
}
var son = new Son();
son.say();
- 继承中属性和方法的查找规则
- 就近原则
// 1. 继承中,如果实例化子类输出一个方法,先看子类有没有这个方法,如果有就先执行子类的
// 2. 继承中,如果子类里面没有,就去查找父类有没有这个方法,如果有,就执行父类的这个方法(就近原则)
class Father {
say() {
return '我是爸爸';
}
}
class Son extends Father {
say() {
console.log('我是儿子');
}
}
var son = new Son();
son.say();
* 子类构造函数中的super()必须放在this之前
- 使用类的注意事项
- 类没有变量提升,所以必须先定义类才能通过类实例化对象
- 属性和方法前要加this
- this的指向问题
- constructor中的this指向实例对象
- 类中自定义的方法一般指向实例对象
- 事件处理函数中,this指向的是事件源
- 静态成员和实例成员
- 实例成员就是构造函数内部通过this添加的成员,实例成员只能通过实例化的对象来访问
- 构造函数本身也是1个对象!静态成员是在构造函数本身上添加的成员,只能通过构造函数来访问
- ES5新增方法
-
数组方法ForEach遍历数组
arr.forEach(function(value, index, array) { //参数一是:数组元素 //参数二是:数组元素的索引 //参数三是:当前的数组 }) //相当于数组遍历的 for循环 没有返回值
-
数组方法filter过滤数组
var arr = [12, 66, 4, 88, 3, 7]; var newArr = arr.filter(function(value, index,array) { //参数一是:数组元素 //参数二是:数组元素的索引 //参数三是:当前的数组 return value >= 20; }); console.log(newArr);//[66,88] //返回值是一个新数组
-
数组方法some
some 查找数组中是否有满足条件的元素 var arr = [10, 30, 4]; var flag = arr.some(function(value,index,array) { //参数一是:数组元素 //参数二是:数组元素的索引 //参数三是:当前的数组 return value < 3; }); console.log(flag);//返回值是布尔值,只要查找到满足条件的一个元素就立马终止循环
-
ForEach和some区别
- 如果查询数组中唯一的元素,用some方法更合适,在some里面遇到return true 会终止遍历,迭代效率高
- 在forEach里面return不会终止迭代
-
初阶函数
- 定义函数
- 命名函数
function 函数名() {}
- 匿名函数
var fn = function(){}
new Function()
(不推荐)
- 命名函数
- 调用函数
/* 1. 普通函数 */
function fn() {
console.log('人生的巅峰');
}
fn();
/* 2. 对象的方法 */
var o = {
sayHi: function() {
console.log('人生的巅峰');
}
}
o.sayHi();
/* 3. 构造函数*/
function Star() {};
new Star();
/* 4. 绑定事件函数*/
btn.onclick = function() {}; // 点击了按钮就可以调用这个函数
/* 5. 定时器函数*/
setInterval(function() {}, 1000); 这个函数是定时器自动1秒钟调用一次
/* 6. 立即执行函数(自调用函数)*/
(function() {
console.log('人生的巅峰');
})();
-
函数内部的this指向
-
改变this指向
- call()方法
- 函数名.call(this指向的对象,实参1,实参2…)
- apply()方法
- 函数名.apply(this指向的对象,数组)
- bind()方法
- 函数名.bind(this指向的对象,实参1,实参2…)
- 三者异同
- 共同点 : 都可以改变this指向
-
不同点:
- call 和 apply 会调用函数, 并且改变函数内部this指向.
- call 和 apply传递的参数不一样,call传递参数使用逗号隔开,apply使用数组传递
- bind 不会调用函数, 可以改变函数内部this指向.
-
应用场景
- call 经常做继承.
- apply经常跟数组有关系. 比如借助于数学对象实现数组最大值最小值
- bind 不调用函数,但是还想改变this指向. 比如改变定时器内部的this指向.
- call()方法
高阶函数
- **定义:**高阶函数是对其他函数进行操作的函数,它接收函数作为参数或将函数作为返回值输出。函数也是一种数据类型,同样可以作为参数,传递给另外一个参数使用。最典型的就是作为回调函数。同理函数也可以作为返回值传递回来
闭包
- **概念:**闭包(closure)指有权访问另一个函数作用域中变量的函数。简单理解就是 ,一个作用域可以访问另外一个函数内部的局部变量。
- **作用:**扩大变量的作用范围
递归函数
- 定义: 如果一个函数在内部可以调用其本身,那么这个函数就是递归函数。简单理解:函数内部自己调用自己, 这个函数就是递归函数
- 注意: 递归函数的作用和循环效果一样,由于递归很容易发生“栈溢出”错误(stack overflow),所以必须要加退出条件return。
- 递归的应用
- 浅拷贝和深拷贝
- 浅拷贝只拷贝最外层,更深层次对象级别的只拷贝引用(地址),如果修改拷贝中的对象属性中的内容,会影响原对象
- 深拷贝可以拷贝多层,从最外层到最里层的数据都会拷贝
- 浅拷贝和深拷贝