javascript—本身属性与原型属性关联

最基础的组织函数与实例的关联:


var Sub = function (color,list) { this.color = color; this.list = list } var sub1 = new Sub("red",[1]); var sub2 = new Sub("green",[2]); sub1.color = "new"; alert(sub1.color);//"new" alert(sub2.color);//"green",说清楚明了sub2.color不会被sub1影响 sub1.list.push(4); alert(sub1.list);//[1,4] alert(sub2.list);//[2],申明援用范例array依旧不会被sub1影响

能够看出组织函数自身的属性(不管直接范例照样援用范例),都是赋值一份copy给它的一切instance,因而每个instance 的修正相互不影响。我们继续看:

自身属性和prototype属性的辨别:


var Super = function(color,list) { this.color = color; this.list = list } Super.prototype.newList = [10,10,10,10]; //建立Super的instance:①super1;②我们能够把Sub.prototype算作是Super的instance。 var super1 = new Super("red",[1,1,1,1]); var Sub = function () {}; Sub.prototype = new Super("green",[1]);//到这里我们能够算作 Sub.prototype和super1都是Super的instance var sub1 = new Sub(); var sub2 = new Sub(); //修正Super的`自身属性` Sub.prototype.list.push(4);//不影响兄弟(super1),但会影响自身的instance(sub1,sub2) alert(sub1.list);//[1,4] alert(sub2.list);//[1,4] alert(super1.list);//[1,1,1,1] 组织函数`自身属性`是直接赋值给它的一切instance,也就是说Super自身的属性(color,list,不管是直接范例照样援用范例)都是离别复制一份给super1和Sub.prototype,因而修正了Sub.prototype的属性(list)并不会影响到super1。反之亦然。 //修正Super的`prototype属性` Sub.prototype.newList.push(2,2,2,2); sub1.newList;//[10,10,10,10,2,2,2,2] super1.newList;//[10,10,10,10,2,2,2,2];组织函数的prototype里的属性只是供应一个指针给一切的instance,因而修正了Sub.prototype的属性(newList:援用范例; 直接范例是没法修正的,只能覆写)会影响到super1。修正Sub.prototype相称因而直接修正Super.prototype属性,由于它们经由历程原型链援用着同一个属性。

我们在来理清关于组织函数自身属性prototype属性与instance之间的关联,先看图:
《javascript—本身属性与原型属性关联》
我们来总结一下:

  1. Sub.prototype 和 super1 都是经由历程 new Super()发生的,我们把它们两个叫做兄弟;同理sub1和sub2也是兄弟
  2. 自身属性(图中a,B):不管是直接范例照样援用范例,兄弟间互不影响,各自具有一份父函数的copy。修正只是在自身作用域里修正。比如说③和⑤都是①的实例,都具有①中一切属性的copy,修正③的属性相称于在③中修正,不会影响其他人。
var Super = function(color,list) {
    this.color = color;
    this.list = list
}
Super.prototype.newList = [10,10,10,10];

//建立Super的instance:①super1;②我们能够把Sub.prototype算作是Super的instance。
var super1 = new Super("red",[1,1,1,1]);
var Sub = function () {};
Sub.prototype = new Super("green",[1]);//到这里我们能够算作 Sub.prototype和super1都是Super的instance

var sub1 = new Sub();
var sub2 = new Sub();

//修正Super的`自身属性`
Sub.prototype.list.push(4);//不影响兄弟(super1),但会影响自身的instance(sub1,sub2),由于关于sub1,sub2来讲list是原型属性而不是自身属性了,这里明白起来能够有点乱。
alert(sub1.list);//[1,4]
alert(sub2.list);//[1,4]
alert(super1.list);//[1,1,1,1] 组织函数`自身属性`是直接赋值给它的一切instance,也就是说Super自身的属性(color,list,不管是直接范例照样援用范例)都是离别复制一份给super1和Sub.prototype,因而修正了Sub.prototype的属性(list)并不会影响到super1。反之亦然。

//覆写
Sub.prototype.list = [0];
sub1.list;//[0]
sub2.list;//[0]
super1.list;//[1,1,1,1]
  • prototype属性(图中XXXXX):* 修正:比如说经由历程⑥去修正①的prototype的属性——sub1.newList.push(2,2,2,2),那末由于原型属性是援用而非复制,因而sub1.newList.push(2,2,2,2) ==> Sub.prototype.newList.push(2,2,2,2) ==> Super.prototype.newList.push(2,2,2,2),也就是sub1会沿着原型链一向查找到终究的Super.prototype,在Super.prototype里去修正newList属性,因而原型链上一切援用了改属性的实例都会被影响。

var Super = function(color,list) { this.color = color; this.list = list } Super.prototype.newList = [10,10,10,10];//建立Super的instance:①super1;②我们能够把Sub.prototype算作是Super的instance。 var super1 = new Super("red",[1,1,1,1]); var Sub = function () {}; Sub.prototype = new Super("green",[1]);//到这里我们能够算作 Sub.prototype和super1都是Super的instance var sub1 = new Sub(); var sub2 = new Sub(); //修正Super的<code>prototype属性</code> Sub.prototype.newList.push(2,2,2,2); sub1.newList;//[10,10,10,10,2,2,2,2] super1.newList;//[10,10,10,10,2,2,2,2];组织函数的prototype里的属性只是供应一个指针给一切的instance,因而修正了Sub.prototype的属性(newList:援用范例)会影响到super1。修正Sub.prototype相称因而直接修正Super.prototype属性,由于它们经由历程原型链援用着同一个属性。
  • 覆写:如果我们不是修正属性,而是直接覆写属性,那末状况也会不一样:
    1.instance要领重载:

var Super = function(color,list) { this.color = color; this.list = list } Super.prototype.newList = [10,10,10,10]; //建立Super的instance:①super1;②我们能够把Sub.prototype算作是Super的instance。 var super1 = new Super("red",[1,1,1,1]); var Sub = function () {}; Sub.prototype = new Super("green",[1]);//到这里我们能够算作 Sub.prototype和super1都是Super的instance var sub1 = new Sub(); var sub2 = new Sub(); sub1.newList = [2,2,2,2];//覆写 sub1.newList;//[2,2,2,2] sub2.newList;//[10,10,10,10] super1.newList;//[10,10,10,10] sub2和super1不受影响,实例覆写要领只会在sub1自身的作用域里增加此要领,而不会修正到Super.prototype的要领

由因而覆写而不是修正,因而不会沿着原型链查找,而是在当前的作用域里增加该属性,而本来原型链上的谁人属性依旧还在,不受影响。这就完成了要领的重载。

2.父函数要领覆写:如果是在Super.prototype里对newList举行覆写,那末一切援用该属性的实例都将被影响。


var Super = function(color,list) { this.color = color; this.list = list } Super.prototype.newList = [10,10,10,10]; //建立Super的instance:①super1;②我们能够把Sub.prototype算作是Super的instance。 var super1 = new Super("red",[1,1,1,1]); var Sub = function () {}; Sub.prototype = new Super("green",[1]);//到这里我们能够算作 Sub.prototype和super1都是Super的instance var sub1 = new Sub(); var sub2 = new Sub(); Super.prototype.newList = [2,2,2,2]; sub1.newList;//[2,2,2,2] sub2.newList;//[2,2,2,2] super1.newList;//[2,2,2,2]

3.完整对prototype覆写:当我们运用XXX.prototype = YYY;对XXX.prototype举行完整覆写时,会彻底改变原型链。然则我们应当注重一点,覆写前的instance依旧保持着对原有prototype的援用,因而原有的prototype中的属性不会被GC,依旧保留在内存中,完整覆写后我们依旧能够接见本来的instance所援用的属性和要领;而新建立的instance会指向新的prototype,因而没法再接见覆写前prototype中的属性。


var Super = function(color,list) { this.color = color; this.list = list } Super.prototype.newList = [10,10,10,10]; new Super; var Sub = function () {}; Sub.prototype.sayHello = function(){return "hello"}; var sub1 = new Sub();//完整覆写Sub.prototype前建立的instance Sub.prototype = new Super("green",[1]);//这里能够明白为对Sub的prototype举行完整覆写,因而会从新建立一个新的prototype指向Super.prototype var sub2 = new Sub();//完整覆写Sub.prototype后建立的instance //考证 sub1.__proto__.constructor == Sub;//true。依旧援用着本来的原型链 sub2.__proto__.constructor == Super;//true。新的instance援用了新的原型链 sub1.sayHello();//"hello",依旧能接见原有的属性,申明还保留在内存中。 sub2.sayHello();//"对象不支持sayHello",新的实例没法再援用原有的prototype

到这里全部关联就理清了,置信照样很多人看不懂,但如果你真的愿望学好javascript,这篇文章充足你读10遍,理清原型关联将是你可否跨上另一个台阶的关卡,不理清这一层关联的话,后患无穷。我画了一张神一样的图,看得懂的话基础就可以理清原型继续关联了。
ps: 图申明的是覆写的历程,请辨别覆写和修正的辨别。(Sub.prototype.list.push(1)是修正,Sub.prototype.list = [1]是覆写)
《javascript—本身属性与原型属性关联》

    原文作者:Enm
    原文地址: https://segmentfault.com/a/1190000000648089
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞