原型链设计
Javascript里面都是对象,必须有一种机制,将所有对象联系起来。所以,Brendan Eich最后还是设计了"继承"。
但是js并没有引入Class类的概念。
Java使用new命令时,都会调用"类"的构造函数(constructor)
JS中new命令后面跟的不是类,而是构造函数。
```
通过new命令,就会生成一个这个Animal对象的实例。
(构造函数中的this关键字,它就代表了新创建的实例对象)
function Animal(name){
this.name = name
this.color = 'red'
}
var test1 = new Animal('小猫')
var test2 = new Animal('小狗')
console.log(test1.color) //red
console.log(test1.color = 'green')
console.log(test1.color) //green
console.log(test2.color) // red
每一个实例对象,都有自己的属性和方法的副本。这不仅无法做到数据共享,也是极大的资源浪费。
```
prototype属性的引入。
构造函数设置一个prototype属性,所有实例对象需要共享的属性和方法,都放在这个对象里面;那些不需要共享的属性和方法,就放在构造函数里面。
Prototype模式
Javascript规定,每一个构造函数都有一个prototype属性,指向另一个对象。这个对象的所有属性和方法,都会被构造函数的实例继承。
这意味着,我们可以把那些不变的属性和方法,直接定义在prototype对象上。
面向实现继承的方法
-
方法1 通过apply() 或者call()实现
function Father(){ this.type = "动物" } function Sun(){ // Father.call(this) //通过call实现继承 Father.apply(this) // 通过apply实现继承 console.log('i am sun ') } let sun = new Sun(); console.log(sun.type) 通过call 或者 apply传输参数 两者的区别在于传参数,call直接传输参数即可,apply需要通过数据传输参数。 function Father(type){ this.type = type } function Sun(){ // Father.call(this,"动物") //通过call实现继承 Father.apply(this,["我是动物"]) // 通过apply实现继承 console.log('i am sun ') } let sun = new Sun(); console.log(sun.type) 打印结果: i am sun 动物 -
方法2 通过propotype实现继承
通过子类的prototype对象,指向一个父类的实例,
function Father(type){ this.type = type } function Sun(){ console.log('i am sun ') } Sun.prototype = new Father("我是动物") //将Sun的prototype对象指向一个Father的实例。相当于完全删除了prototype 对象原先的值,然后赋予一个新值。 Sun.prototype = Sun 任何一个prototype对象都有一个constructor属性,指向它的构造函数。 如果没有Sun.prototype = new Father("我是动物") Sun.protptype.constructor指向的是Sun 加完之后,指向了Father,这样容易导致原型链错乱。 更重要的是,每一个实例也有一个constructor属性,默认调用prototype对象的constructor属性。 既 sun.constructor = Sun.prototype.constructor 这显然会导致继承链的紊乱(sun明明是用构造函数Sun生成的),因此我们必须手动纠正,将Sun.prototype对象的constructor值改为Sun既 let sun = new Sun() -
方法3 直接继承prototype
由于Animal对象中,不变的属性都可以直接写入Father.prototype。所以,我们也可以让Sun()跳过 Father(),直接继承Father.prototype。
function Father(){ } Father.prototype.species = "动物"; function Sun(){} Sun.prototype = Father.prototype; //然后,将Sun的prototype对象,然后指向Father的prototype对象,这样就完成了继承。   Sun.prototype.constructor = Sun; 与前一种方法相比,这样做的优点是效率比较高(不用执行和建立Father的实例了),比较省内存。缺点是 Sun.prototype和Father.prototype现在指向了同一个对象,那么任何对Sun.prototype的修改,都会反映到Father.prototype。 如:Sun.prototype.species = '11' console.log(Father.protptype.species) //打印结果为 11 -
方法4 利用空对象作为中介
var F = function(){}; F是空对象,所以几乎不占内存。这时,修改Sun的prototype对象,就不会影响到Father的prototype对象 F.prototype = Father.prototype; Sun.prototype = new F(); Sun.prototype.constructor = Cat;