在Mozilla的mdn上关于Javascript是这样描述的
JavaScript 是一种基于原型的面向对象语言,而不是基于类的
所以指针的引用访问如果没有搞清楚,就很容易混淆其访问顺序,特别是当你的认识一支半截的时候(本文不会特别阐述原型链和作用域等问题,但会提及)。
回到原型上来!.
从ECMAScript的描述中我们得知,创建一个函数时会自动带有一个prototype的属性,该属性是指向函数原型对象的指针,每个原型对象都会有一个constructor属性(从传统的编程语言上,我们可以认为这个是该对象的构造函数,传统高级编程语言一般都需要显示的申明其构造函数)
当我们创建一个实例时,会自动带有一个__proto__的属性(可以理解为private),该属性指向其原型对象
Javascript中对象的prototype属性的解释是:返回对象类型原型的引用
所以每一个对象都有他的原型,这个原型有他自己的原型,直到最顶层的原生类型最后会返回(Null);那么在外部调用时,会首先去找自身属性,看其是否有,如果没有,就去找原型中是否有该属性,如果原型中没有,就会再往上层找原型的原型所具有的属性,找不到则返回undefined.
简单点来讲这就是原型链。举个例子:
假如你是一个10岁儿童,你要买糖,先摸下口袋里有没有钱,发现没有,就去找你老娘要,你老娘发现包里也没钱,让你去奶奶那里要要看。
如果你有呢?同时你老妈也有呢!你当然会先找自己包里的钱,因为你已经等不及要去买糖了(你真伟大,是我,就去老娘那里抠一点过来再说!) 。这种情况叫"属性遮盖"
当然,如果你对this理解不清楚,如果理解了上面的部分反而更容易犯错(挺纠结的,爱恨交织!)
放一段代码来看看
1 function Base() {2 this.desc = "Javis"; 3 }4 5 Base.prototype.desc = "I'm not Jarvis! ";6 7 //xxoo8 console.log(new Base().desc);
猜一猜再去检验!
之前我的认识this指向name是Base的静态属性,通过new 创建的实例本身不具有该属性,但是他的原型属性中定义了name的值。那么它应该是”I'm not Jarvis“
> Jarvis
哦。no!!! 那I'm not Jarvis被覆盖了。我靠?,找一找
> console.log(new Base().__proto__.desc);
> I'm not Jarvis改下代码:
1 function Base() { 2 this.desc = "我是真的Jarvis"; 3 } 4 Base.prototype = { 5 desc: "我是Jarvis", 6 addDesc: function(desc) { 7 this.desc= desc; 8 } 9 }10 11 var myInstance = new Base();12 myInstance.addDesc("你是假的");13 console.log(myInstance.desc);14 console.log(Base.hasOwnProperty('desc'));
哦!false!Base没有该属性..this 指向的是上下文。
也许你到这里都是轻松过关。。那么如果把Base换成Object类型呢?
var Base = { desc: "我是真的Jarvis", updateDesc: function() { this.desc = "你是假的"; } }Base.updateDesc();console.log(Base.desc);console.log(Base.hasOwnProperty('desc'));
//想到答案了吗?哇靠这还不简单。
把this换成Base.
Base.desc = "你是假的";
答案也一样!
不行,不行我还得换一换!
var Base = { desc: "我是真的Jarvis", updateDesc: function() { this.desc = "你是假的"; }};var Child = function () { this.desc = "哈哈,我是来看戏的!"; this.updateDesc = function() { this.desc = "靠!越演越有爱了!"; };}Child.prototype.updateDesc = Base.updateDesc;var b = new Child();console.log(b.desc);b.updateDesc();console.log(b.desc);
好了。到了这里属性遮盖也出现了。。