js面向对象 及 原型链的知识点,求补充
发布于 2天前 作者 albin3 261 次浏览 来自 分享

原型链简介

JavaScript不包含传统的继承,因此引入原型链模型模拟继承功能。

__proto__属性

__proto__属性是隐藏属性,不应该出现在日常的编码中,这里只是为了理解原型链提到这个属性。

下面是例子

var bar;
console.log(bar.attr);
//undefined

上面代码的工作原理是

  1. 寻找定义在bar上的attr属性,若找到则返回,若找不到,继续
  2. 寻找定义在bar.__proto__上找attr属性,若找到则返回,若找不到则继续
  3. 寻找定义在bar.__proto__.__proto__上的attr属性,若找到则返回,若找不到则继续
  4. 直到找到的bar.__proto__....__ptoto__为null,若还未找到,则返回undefined

理解JavaScript中了寻找属性的流程,我们来看实例化一个类时new做了些什么。

new关键字与prototype

new一个对象的实际过程如下

var bar = new Bar();
// function new () {
//   var bar = {};
//   bar.__proto__ = Bar.prototype;
//   Bar.apply(bar, arguments);
//   return bar;
// }
  1. 将Bar的prototype对象直接赋值给bar的__proto__
  2. 以bar为this,apply运行Bar这个函数

这么做了的结果是**定义在Bar.prototype上的属性和方法将能被bar访问到!**比如:

function Bar () {
  this.bar = 'bar';
}
Bar.prototype.attr = 'value';
Bar.prototype.getAttr = function() { return this.attr };

var bar = new Bar();
bar.getAttr();
// bar中不包含getAttr,但是bar.__proto__包含这个函数,执行成功。
// value

这里着重理解bar.__proto__ = Bar.prototype;正因为在new的过程中,bar的__proto__被赋值为Bar的prototype,所以定义在Bar的prototype上的属性和方法能被bar访问到。这样,达到了Bar作为类,实例化了一个bar对象的目的。

PS: 这里的赋值实际上是引用,意思是bar的__proto__和Bar的prototype指向同一个对象,其中给一个改变了,另一个也跟着改变。要理解这个,需要看看JavaScript中引用和赋值的问题。

多级继承例子

下面介绍多级继承的例子

var Foo = function() {
  this.foo = 'foo';
}
Foo.prototype.isFoo = true;

var Bar = function() {
  Foo.apply(this, arguments);
  this.bar = 'bar';
}
Bar.prototype.__proto__ = Foo.prototype;
Bar.prototype.isBar = true;

var bar = new Bar();
console.log(bar);
//{bar: 'bar'}
console.log(bar.foo);
//**bar.__proto__隐含了属性foo**
//'foo'
console.log(bar.isFoo);
//**bar.__proto__.__proto__隐含了属性isFoo**
//true

求补充,直接评论

4 回复

Bar.prototype = new Foo();书上说这样干不好,会生成一个实例。

Bar.prototype.__proto__ = Foo.prototype;
//不过没内部属性foo, 需要在Bar 里 call 一下.

Bar.prototype.isBar = true;这样不好吧,这样一变影响原型链上所有。 一般原型链上只挂function。

@hezedu

我的理解是,就是要生成实例的,而且这里只在继承的时候生成一次不会影响性能哦……继承以后这是个Bar.prototype是Foo的实例,修改这个实例不影响Foo原来的东西,同时还保证了,这个子类永远会引用到Foo.prototype上的东西,达到继承效果。我知道的另一种写法是Bar.prototype = Foo.prototype,但是那样会很乱,改了Bar的prototype会影响到Foo,更推荐的写法是怎么写呢?

第二点我也不知道好不好,囧,不过在Bar.prototype上挂的东西是在实例里的隐藏属性…这个属性console不出来,但是能访问到,既然方法能挂,属性应该也没问题吧。

使用 zupu 查看两种方法不同:

var Foo = function() {
  this.foo = 'foo';
}
Foo.prototype.getfoo = function(){
  return this.foo;
}

// 方法一 Bar
var Bar = function() {
  this.bar = 'bar';
}
Bar.prototype = new Foo();
var bar = new Bar();

//方法二  Bar2
var Bar2 = function() {
  Foo.call(this);
  this.bar2 = 'bar2';
}
Bar2.prototype.__proto__ = Foo.prototype;
var bar2 = new Bar2();


var test ={
  foo:new Foo(),
  bar:new Bar(),
  bar2:new Bar2()
}
document.write(zupu(test));

结果: cnnode.png 第一种方法 Foo的内部属性 foo 也跑到原型链上了

回到顶部