认识构造函数
为什么有构造函数
因为一般的创建对象的方式一次只能创建一个对象, 利用工厂模式创建的对象,对象的类型都是Object类型
什么是构造函数
构造函数也称之为构造器(constructor),通常是我们在创建对象时会调用的函数。
在其他面向对象语言里面,构造函数是存在于类中的的一个方法,称之为构造方法。
在 JavaScript 中,用 new 关键字来调用的函数,称为构造函数。构造函数首字母一般大写。
构造函数与普通函数的区别
- 名字:构造函数首字母建议大写;普通函数首字母建议小写
- this指向:在构造函数内部,this指向新对象。在普通函数内部,this指向的是全局对象
- 返回值:构造函数不用return返回值,默认返回新的实力对象。普通函数如果没有return返回值,返回undefined
- 调用:构造函数使用new关键词调用;普通函数直接调用
new操作符调用
new关键字会进行如下操作
- 创建一个简单的javaScript对象
- 为步骤一的新对象添加属性__proto__,并连接至构造函数的原型对象
- 将创建的对象作为this的上下文(上下文:当前执行环境的作用域)
- 如果函数没有返回对象则返回this
原型对象
什么是原型对象
prototype(原型对象就是一个容器)
可以让对象实例共享它包含的属性和方法
原型对象与函数与实力对象之间的关系
每个函数都有一个prototype属性指向原型对象。
每个原型对象都有一个constructor属性指向构造函数。
每个对象又有一个特殊的内置属性[[prototype]]指向原型对象,可以通过对象的__proto__属性或者通过Object.getPrototypeOf方法获取
原型链
什么是原型链
就是实例对象和原型对象之间的链接,每一个对象都有原型,原型本身又是对象,原型又有原型,以此类推形成一个链式结构.称为原型链
原型链查找
当我们从一个对象上获取属性,如果当前对象没有获取到,我们就会去它的原型上获取。
构造函数Object.prototype 是原型链的最末端。它的__proto__指向null
类
认识class定义类
在ES6(ECMAScript2015)新标准中使用了class关键字来直接定义类
基本上,ES6中的class可以看作只是一个语法糖
使用class声明类
- 类声明
class Person {} - 类表达式
var Student = class {}
class的继承
- Class通过extends关键字实现继承
- 子类必须在constructor方法中调用super方法否者新建实例时会报错。
这是因为子类方法没有自己的this对象,而是继承父类的this对象然后对其进行加工,如果不吊用super方法,子类就得不到this对象
super关键字
super这个关键字既可以当函数使用,也可以当对象使用
- 第一种情况,super作为函数调用时,代表父类的构造函数,作为函数时,super()只能用在子类的构造函数中
- 第二种情况,super作为对象时在普通方法中指向父类的原型对象;在静态方法中指向父类
*ES6规定,通过super调用父类方法时,super会绑定子类的this
类的prototype属性和__proto__属性
- 子类的__proto__属性表示构造函数的继承,总是指向父类
- 子类prototype属性的__proto__属性表示方法的继承,总是指向父类的prototype
ES5继承机制与ES6继承机制的不同
ES5的继承实质上是先创造子类的实例对象,然后将父类的方法添加到this上面(Parent.apply(this))。ES6的继承机制完全不同,实质上是先创造父类的实例对象this(所以必须先调用super方法),然后再用子类的构造函数修改this
实现继承的方案
原型链继承(以父类实例为原型)
- 首先定义父类构造函数
- 在父类构造函数上添加方法
- 定义子类构造函数
- 创建父类实例对象,并且作为子类构造函数的原型对象
- 在子类原型对象上添加内容
弊端:
- 通过直接打印的方式看不到继承属性
- 属性被多个对象共享,如果是引用类型会造成问题
- 不能给父类构造函数(Person)传递参数,因为这个对象是一次性创建的(无法定制化)
借用构造函数继承
- 借用继承的做法很简单:在子类型构造函数内部调用父类构造函数,通过call()方法执行构造函数
弊端:
不能继承父类原型上的属性和方法
组合式继承
原型链继承 + 借用构造函数继承
弊端
- 会调用两次父类构造函数
- 一次是在创建子类原型的时候
- 一次是在子类构造函数内部
- 子类的实例会有两份父类属性
- 一份在当前实例中
- 一份在子类对应的原型对象中
- 无需担心两份属性的访问问题,因为默认访问实例本身这一部分
原型式继承
- 这种继承方法不是通过构造函数来实现的。
与ES6中的Object.create()方法效果相同。
最终目的是新对象的原型指向原对象
寄生式继承
寄生式继承的思路是结合原型式继承和工厂模式的一种方式
即创建一个封装继承过程的函数,该函数在内部以某种方式来增强对象,最后将这个对象返回
寄生组合式继承
组合式继承+原型继承+寄生继承
子类构造函数的原型是以父类构造函数原型为原型创建出来的新对象
能不能直接让子类型的原型对象 = 父类型的原型对象呢?不要这么做, 因为这么做意味着以后修改了子类型原型对象的某个引用类型的时候, 父类型原生对象的引用类型也会被修改