构造函数、原型链、继承、类
构造函数
什么是构造函数?
其实构造函数和普通函数没有特别的区别,任何普通函数只要使用了new操作符就是构造函数。(一般构造函数名的首字母是大写,普通函数小写),如下
使用new操作符创建构造函数的实例整个过程?
例如上面例子,
1.首先在内存显式创建一个新对象。
2.将新对象的[[prototype]]属性赋值为构造函数的prototype属性。
3.构造函数内部的this赋值为这个新对象(这个就是this指向的第四种情况)
4.执行构造函数内部的代码,给新对象添加属性。
5.如果构造函数返回非空对象,则返回该对象;否则,返回刚创建的对象。
注意:
dog的constructor属性会指向Dog构造函数
Dog的prototype属性和dog的 proto 指向同一个原型对象。
构造函数存在的问题?
当构造函数里面有定义方法时,创建实例时都会创建方法,而不是指向同一个方法?
解决方法?
实际上
this.sayName=function(){console.log(this.name); }等价于this.sayName=new function(){console.log(this.name);}
所以每个实例的方法都不是指向同一个
这样就可以了,this指向是第二种隐式绑定
上面问题用原型解决更好,使用原型对象的好处就是在原型对象上定义的属性和方法都可以被对象共享(所以在原型对象上定义sayName方法就可以实现应用同一个函数)
[[prototype]]是什么?
所有对象在创建时都会生成一个[[prototype]]属性(包括函数,对象,数组等Object类型),几乎都会被赋予一个非空的值。
介绍一下各种跟原型相关的方法
A.isPrototypeOf(B) 检查A是否是B的原型
Object.getPrototypeOf(B)获取B原型对象
Object.setPrototypeOf(A,B) 把对象B设置为对象A的原型对象
B=Object.create(A) 把对象A设置为对象B的原型
A.hasOwnProperty(“属性”) A上是否有对应属性,若属性来自原型链则为false
“属性” in 对象 A上是否有对应属性,不管来自本对象还是原型链有就是true
hasPrototypeProperty(A,”属性”) 是否只有A的原型有该属性,若A上也有则false
for…in… 遍历对象查找的是整条prototype链(不可枚举的Enumberable:false不可以访问)
Object.keys(A) 遍历A上可枚举的属性包括prototype链
Object.getOwnPropertyNames(A) 遍历A上所有属性无论能否枚举包括prototype链
Object.values() 接收一个对象返回它们内容的数组,对象值的数组
Object.entries() 接收一个对象返回它们内容的数组,键值对数组
[[prototype]]链应该就是原型链
Dog原型链的整个结构基本如下(但是这个还不是真正的继承)
继承
原型链继承
举个简单的例子
具体原型链如下图
其中,实现继承的句子是Sub.prototype=new Super(),实现Sub继承Super
最后,s.getSuper(),通过3步搜索s—->Sub.prototype—>Super.prototype最后一步找到这个方法
补充:因为所有的引用类型都继承自Object,所以后面省略的是Object.prototype,Object.prototype的方法等等。
判断继承关系
- A instanceof B A是否是B的实例(是 true,否 false)
- A.prototype.isPrototypeOf(B) A是否是B的原型
存在的问题
1.所有继承的属性和方法都会在对象实例间共享,无法做到实例私有(就是一个实例改变了原型链上的属性或方法,其他实例也会改变)
2.子类型在实例化时不能给父类型的构造函数传参
盗用构造函数
利用call或apply方法和改变this指向,实现继承
优点:解决属性共享问题和向父类构造函数传参问题
缺点:必须在构造函数中定义方法,函数不能重用。子类也不能访问父类原型上定义的方法。
组合继承(最流行的方法
使用原型链继承原型上的属性和方法,通过盗用构造函数继承实例属性(就是方法在原型链上可以重用,属性用盗用构造函数各个实例可不同)
缺点:有效率问题,会对父类构造函数调用两次,一次是创建子类原型时,二次是在子类构造函数中调用。
原型式继承
object函数的原型链图
这种继承适合有一个对象,想在它的基础上在创建一个新对象。类似于复制一个对象,然后再对其进行添加。
Object.create()和object方法效果相同。
寄生式继承
其实就是对原型式继承的封装而已,缺点是难以重用。
寄生式组合继承(这种应该是最有效的继承方式了)
其实就是通过寄生式继承来继承父类原型,然后将返回的新对象赋值给子类原型。