Javascript深入理解之继承与原型链

2017-01-07 11:22:59来源:CSDN作者:zza000000人点击

Javascript深入理解之继承与原型链

1.构造函数、原型、实例的关系
* 每个构造函数都有一个原型对象,原型对象都包含一个指向构造函数的指针,而实例都包含一个指向原型对象的内部指针[[Prototype]] *

function Foo() {    this.a = 123;}Foo.prototype.b = 456;let AA = new Foo();console.dir(Foo.prototype);console.dir(Foo.prototype.constructor);console.dir(AA.__proto__);// Foo为构造函数// AA为实例// Foo.prototype为原型对象// Foo.prototype的constructor指向构造函数// AA的__proto__指向原型对象

1.原型链

* 关于原型链的定义,我们来看一下MDN里面的定义“在 javaScript 中,每个对象都有一个指向它的原型(prototype)对象的内部链接。这个原型对象又有自己的原型,直到某个对象的原型为 null 为止(也就是不再有原型指向),组成这条链的最后一环。这种一级一级的链结构就称为原型链(prototype chain)。” *

2.原型链实例与继承

function Foo() {    this.nameOne = 123;    this.toOne = function() {        return this.nameOne;    }}function FooTwo() {    this.nameTwo = 456;    this.toTwo = function() {        return this.nameTwo;    }}FooTwo.prototype = new Foo();/* 当我们对对象的prototype属性进行替换时,可能会对对象constructor属性产生一定的副作用,因此,在对prototype进行替换后,要对对象的constructor进行重置,避免陷入原型陷进。*/ FooTwo.prototype.constructor = FooTwo;let aa = new FooThree();console.log(aa.nameOne);    // => 123console.log(aa.nameTwo);    // => 456console.log(aa.toOne());    // => 132console.log(aa.toTwo());    // => 456   

关于原型陷阱请看JavaScript深入理解之原型
* 上例中:定义了两个类型:Foo和FooTwo,每个类型分别有一个属性和方法,且FooTwo继承了Foo,继承是通过创建Foo的实例,并将该实例赋给Foo.prototype实现的。实现的本质是重写原型对象,代之以一个新类型的实例,即原来存在于Foo的实例中的方法现在也存在于FooTwo.prototype中了,这样就继承了Foo的属性和方式,实现了继承。通俗一点说,A构造函数要继承B构造函数的属相和方法,则将B的实例赋值给A的prototype属性。*

看下面一个例子

function Foo() {    this.name = 123;    this.toString = function() {        return this.name;    }}function FooTwo() {    this.nameTwo = 456;}function FooThree() {    this.name = 789;    this.toStr = function() {        return this.name;    }}FooTwo.prototype = new Foo();FooThree.prototype = new FooTwo();FooTwo.prototype.constructor = FooTwo;FooThree.prototype.constructor = FooThree;let aa = new FooThree();console.log(aa.nameTwo);        // => 456console.log(aa.toString());     // => 789console.log(aa.toStr());        // => 789// aa同时是三个构造器的实例console.log(aa instanceof Foo);         // => trueconsole.log(aa instanceof FooTwo);      // => trueconsole.log(aa instanceof FooThree);    // => true

* 上例中:两个输出都打印789,因为在继承中,继承的方法和属性, 而且是单纯的方法和属性,FooThree实际上是下面这样:*

function FooThree() {    this.nameTwo = 456;    this.name = 789;            // 因为我们设置constructor指向FooThree    this.toStr = function() {        return this.name;    }}

3.构造函数模式继承

function Foo(name) {    this.name = name;    this.say() = function() {        return this.name;    }}function FooTwo() {    // 继承Foo,同时还传递参数    Foo.call(this, 123);}let aa = new FooTwo();console.log(aa.name);   // => 123console.log(aa.say());  //TypeError: say is not a function

* 构造函数模式缺点在于只能继承属性,不能继承方法 *

4.组合继承

function Foo(name) {    this.name = name;}Foo.prototype.say = function() {    return this.name}function FooTwo(name, age) {    // 继承属性    Foo.call(this, name);    this.age = age;}// 继承方法FooTwo.prototype = new Foo();FooTwo.prototype.constructor = FooTwo;FooTwo.prototype.say = function() {    return this.name;}let aa = new FooTwo('aa', 26);console.log(aa.name);       // => aaconsole.log(aa.age);        // => 26console.log(aa.say());      // => aa

5.其它继承方式还有:原型式继承、寄生式继承等

最新文章

123

最新摄影

微信扫一扫

第七城市微信公众平台