原型链
在js中我们没有类型这个说法,只有对象这个概念,后面es6中使用class创建对象 并实现继承。但是class只是语法糖,class本质背后还是原型机制 构造函数实现继承
继承:一个对象可以访问另外一个对象中的属性和方法
javaScript仅仅在对象当中引入了一个原型的属性,就实现了语言的继承机制,基于原型的继承省去了很多基于类继承时的繁文缛节,简洁而优美 --- 李兵
原型继承是如何实现的
proto 称为该对象的原型(prototype) __proto__指向的对象称为该对象的原型对象 通过__proto__产生的链为原型链
javaScript每个对象都包含一个隐藏属性__proto__,我们就把该隐藏属性__proto__称之为对象的原型(prototype),javaScript每个对象都包含一个隐藏属性__proto__指向了内存中的另外一个对象, 我们就把__proto__指向的对象称为该对象的原型对象,那么该对象就可以直接访问其原型对象的方法或者属性
我们看到使用 C.name 和 C.color 时,给人的感觉属性name和color都是对象c本身的属性,但实际上这些属性都是位于原型对象上,我们把这个查找属性的路径称为原型链,他像一个链条一样,将几个原型链接起来
使用__proto__实现继承
var animal = {
type: "Default",
color: "Default",
getInfo: function () {
return `Type is: ${this.type},color is ${this.color}.`
}}
var dog = { type: "Dog", color: "Black",}
// 实现继承
dog.__proto__ = animal
// 这样之后DOG就可以访问animal属性啦
dog.getInfo()
注意:虽然__proto__可以实现继承,但是隐藏属性不能直接用来使用的。虽然现代浏览器留了口子但是不推荐使用,因为很耗性能
- 隐藏属性,并不是标准定义的
- 使用该属性造成严重的性能问题
这个__proto__是不可行的,我们只能另找其他方法了
首先,构造函数是怎么创建对象的?
比如创建一个dog对象,先创建一个DogFactory的函数,属性通过参数进行传递,在函数体内,通过this设置属性值。
function DogFactory(type, color) {
this.type = type
this.color = color
}
然后再结合new关键字,就可以创建对象啦
var dog = new DogFactory('Dog','black')
new后面配合一个函数(叫构造函数),javascript虚拟机便会返回一个对象,为什么就会返回一个对象呢,接着往下看
v8有所处理,v8在处理上面这段代码是,V8会在背后悄悄的做了以下几件事情,类似下面模拟代码
var dog = {}
dog.__proto__ = DogFactory.prototype
DogFactory.call(dog, 'Dog', 'Black')
看图我们加深理解
- 创建一个空白对象 dog
- 将 DogFacttory的prototype属性设置为dog的原型对象,这就给dog对象设置原型对象的关键一步。
- 再使用dog来调用DogFactory,这时候DogFactory函数中的this就指向了对象dog,然后在DogFactory函数中,利用this对对象dog执行属性填充操作,最终创建了dog对象
- 我们应该知道:函数其实有三个隐藏属性,name,code (这个是v8用来做函数执行优化的)还有一个prototype。
- 当函数作为构造函数来创建一个新的对象时,新创建的对象的原型对象就指向了该函数的prototype属性。
- 普通函数prototype不起作用。
我们很自然的就知道,当通过一个构造函数创建多个对象的时候,这几个对象的原型都指向了该函数的prototype属性
function DogFactory(type,color){
this.type = type
this.color = color
//Mammalia
}
DogFactory. prototype.constant_temperature = 1
var dog1 = new DogFactory('Dog','Black')
var dog2 = new DogFactory('Dog','Black')
var dog3 = new DogFactory('Dog','Black')
这样三个dog对象的原型对象都指向了prototype,而prototype又包含了constant_temperature,这就实现了一个对象方位另外一个对象的属性,也就是实现了继承
一段关于new的历史
javascript和java是同一时期出来的,但是java当时如日中天,javascript只是为了浏览器的页面能够动起来简单脚本语言。当时为了蹭java热度,就叫javascript 同时为了进一步吸引java程序员,在语法上也蹭java的热点,加上了不协调的new来创造对象,和java类似
总结
javascript的对象都有一个隐藏属性__proto__, 这个属性的值就是这个对象的原型对象,通过__proto__形成的链就是原型链,从原型链上,就可以对象使用一层一层原型对象的属性。 继承的概念简单的讲就是,一个对象可以访问另一个对象的属性,就是继承 然而直接使用对象的__proto__来实现继承并不可取,因为他不是一个标准定义的,而且使用它来继承性能特别差 所以我们使用构造函数来创建对象,构造函数前面加一个new javascript就会返回一个对象。这里注意函数有隐藏属性code name prototype,如果一个函数是 构造函数的时候,新创建的原型对象就指向了构造函数的prototype属性。即obj.proto = Object.prototype,只要把属性放到构造函数里面,创建的新对象就完成了继承,即基于原型继承
- 对象有一个隐藏属性,proto 这个属性指向原型对象
- 函数有一个隐藏属性,prototype 当函数为构造函数时,这个函数创建出来的对象的__proto__属性指向构造函数的prototype 指向原型对象
继承还是有很多可以面试的东西,上面说的都是一些v8 一个继承的基本原理的浅出,还需要大家自己结合区深入,深挖。 那里