【学习打卡】JavaScript原型的自我总结与疑惑(一)

  初学原型是从老师的视频入门的,根据老师的讲解,我理解到的是,构造函数里面定义复杂对象或者函数的时候,每次new一个新对象就得复制一遍,浪费空间;为了解决这个问题呢,就有了原型。通过引入原型,使得每个对象拥有一个原型对象,我的理解是原型对象是共享的,对象可以访问但是不能修改他的原型对象。但是这些都仅仅是我的猜想,那么针对这些猜想,我做了一些实验。

  猜想一:new对象的时候,构造函数里面的变量会复制给新对象,对象改变自身方法或者属性,并不会影响构造函数;【是的】

  猜想二:原型对象可自身修改自身;【是的】

  猜想三:原型对象是共享的,对象只能访问但不能修改原型对象;【共享,对象可以修改原型对象】

  【实验之前的准备:知识储备】来源:https://developer.mozilla.org/zh-CN/docs/Learn/JavaScript/Objects/Object_prototypes

  定义一个构造函数(例如Father),那么他自带一个原型对象(即Father.prototype),new一个Father对象时(例如son),那么son可以访问这个原型对象的属性和方法,每个浏览器访问的方式都不同,文中用的时son.__proto__,这不是一个标准,不推荐用作开发。每个原型对象也会拥有原型,并且从中继承方法和属性,一层一层、以此类推。这种关系常被称为原型链 (prototype chain),这些属性和方法定义在Object的构造器函数(constructor functions)之上的prototype属性上,而非对象实例本身。在 JavaScript 中并不如此复制——而是在对象实例和它的构造器之间建立一个链接(它是__proto__属性,是从构造函数的prototype属性派生的),之后通过上溯原型链,在构造器中找到这些属性和方法。

  【开始实验咯】

  猜想一,实验如下:

   第一步:Father的gender的值直接固定为“m”,最后console.log(son.gender)的输出结果为m;

 1 <script>
 2         function Father(first, last, age, gender) {
 3             this.name = {
 4                 'first': first,
 5                 'last': last
 6             };
 7             this.age = age;
 8             this.gender = "m"
 9         }
10         var son = new Father('Mei', 'Lee', 18, 'f');
11         console.log(son.name);
12         console.log(son.age);
13         console.log(son.gender);
14     </script>

  第二步:son.gender重新赋值,比较Father.gender和son.gender的异同。代码如下:son.gender的输出为f,Father的gender值并未改变。

    也就是说,改变对象并不会影响构造函数。即:猜想一成立。

var son = new Father('Mei', 'Lee', 18, 'f');
son.gender = 'f';
console.log(Father);
console.log(son.gender);

  猜想二:原型对象可自身修改自身;实验如下:

  这个其实可以不用证明的,如果不能修改自身,那它怎么定义嘛,但是为了后文的发展,简单验证一下吧。第一段代码中,Father.prototype是没有speak属性的,第二段代码里面是有的。那么猜想二是正确的。

<script>
        function Father(first, last, age, gender) {
            this.name = {
                'first': first,
                'last': last
            };
            this.age = age;
            this.gender = 'm'
        }
        console.log(Father.prototype);
    </script>

  

<script>
        function Father(first, last, age, gender) {
            this.name = {
                'first': first,
                'last': last
            };
            this.age = age;
            this.gender = 'm'
        }
        Father.prototype.speak = 'chinese';
        console.log(Father.prototype);
    </script>

  另外附上一点疑惑,Father.prototype增加speak属性的时候,增加speak之前和之后分别打印Father.prototype,之前是要展开函数才能看到Chinese,之后是函数最外层就能看到;而且之前访问speak是访问不到的,不知道是什么原因。后来在挚友的帮助下,用IE执行了这段代码就不会有这种令人迷惑的问题,可能时chrome的内部执行顺序的问题,不知道会不会在项目执行中出啥问题。

<script>
        function Father(first, last, age, gender) {
            this.name = {
                'first': first,
                'last': last
            };
            this.age = age;
            this.gender = 'm'
        }
        console.log(Father.prototype);
        console.log(Father.prototype.speak);
        Father.prototype.speak = 'chinese';
        console.log(Father.prototype);
console.log(Father.prototype.speak);
</script>

  运行结果如图:

 

   猜想三:原型对象是共享的,对象只能访问但不能修改原型对象;共享是正确的,MDN文档中有提到【原型链中的方法和属性没有被复制到其他对象】,此处做个验证。但是对象可以修改其原型对象

 

 

   分别通过对象son1和son2修改原型对象的speak属性,会发现属性真的会变化!也正如文档所说,原型链中的方法和属性没有被复制到其他对象,其他对象可以修改这些对象方法。

 1 <script>
 2         function Father(first, last, age, gender) {
 3             this.name = {
 4                 'first': first,
 5                 'last': last
 6             };
 7             this.age = age;
 8         }
 9         Father.prototype.speak = 'chinese';
10         var son1 = new Father('Mei', 'Lee', 18);
11         son1.__proto__.speak = 'english';
12         console.log(Father.prototype.speak);
13         console.log(son1.speak)
14         var son2 = new Father('Lei', 'Lee', 18);
15         son2.__proto__.speak = 'japanese';
16         console.log(Father.prototype.speak);
17         console.log(son2.speak)
18     </script>

运行结果:

 

   针对猜想3的一点延申:如果一个对象真的想用原型对象的一个属性或者方法,如果要修改,请自己重新定义,不要影响别的对象哦。如下面,如果真的想学外语,可以给自己定义个speak。

    Father.prototype.speak = 'chinese';
        var son1 = new Father('Mei', 'Lee', 18);
        son1.speak = 'english';
        console.log(Father.prototype.speak);
        console.log(son1.speak)
        var son2 = new Father('Lei', 'Lee', 18);
        son2.speak = 'japanese';
        console.log(Father.prototype.speak);
        console.log(son2.speak)
                    

  本文之外的一点疑惑,如果Father在函数体之外定义了一个属性或者方法,那么要怎样才能访问到这个方法?new的对象是否可以访问到这个方法,chrome的运行结果如下,菜鸡很疑惑。

 1         function Father(first, last, age, gender) {
 2             this.name = {
 3                 'first': first,
 4                 'last': last
 5             };
 6             this.age = age;
 7             this.gender = 'm'
 8         }
 9         console.log(Father);
10         console.log(Father.prototype);
11         var son1 = new Father('Mei', 'Lee', 18, 'f');
12         Father.speak = 'chinese';
13         var son2 = new Father('Lei', 'Lee', 18, 'f');
14         console.log(Father);
15         console.log(Father.speak);
16         console.log(son1);
17         console.log(son1.speak);
18         console.log(son2);
19         console.log(son2.speak);

 

posted @ 2020-08-20 11:51  余来余去  阅读(131)  评论(1)    收藏  举报