javascript构造函数和原型

创建对象:ES5 VS ES6
ES5:

  1. 字面量
  2. Object
  3. 构造函数
<script>
        // 1. 利用 new Object() 创建对象

        var obj1 = new Object();

        // 2. 利用 对象字面量创建对象

        var obj2 = {};

        // 3. 利用构造函数创建对象
        function Star(uname, age) {
            this.uname = uname;
            this.age = age;
            this.sing = function() {
                console.log('我会唱歌');

            }
        }

        var ldh = new Star('刘德华', 18);
        var zxy = new Star('张学友', 19);
        console.log(ldh);
        ldh.sing();
        zxy.sing();
    </script>

ES6:
class方式

class name {
  // class body
}       
var xx = new name();     


这两种方式创建对象的结果以及内部的原型链都一样,只是ES6的写起来简单很多,class name,name的本质还是function,一个函数。

下面讲讲ES5创建对象的原型链。

静态成员和实例成员的区别:
静态成员:只能在构造函数本身上添加的成员,只能通过构造函数本身来访问
实例成员:只能在构造函数内部是创建,只能通过实例化对象来访问。

为什么会有原型链?
当我们使用构造函数时,实例化的对象有共同的方法时,
在这里插入图片描述
就会占用的不是同一块内存,浪费空间。
原型链就是把所有共同的方法都集中在一起,所有实例化的对象都从他这里调用。共享内存。

在这里插入图片描述
这是构造函数,实例化对象,原型链之间的关系。

原型链
在这里插入图片描述
JS的成员查找机制
优先级是:对象实例 > star构造函数 > star原型对象 > Object原型对象。

this指向问题
原型对象和构造函数的this都指向对象实例。

拓展内置对象
只能用Array.prototype.sum = function() {} ,不能用覆盖式的Array.prototype = 。。。。这样来写。

比如实例化,var ldh = new Star();
因为我们的原型对象.contructor是指向我们的Star的,Star.prototype 就是原型对象,当我们添加方法时。太多的方法我们就用。

Star.prototype = {
            // 如果我们修改了原来的原型对象,给原型对象赋值的是一个对象
            //,则必须手动的利用constructor指回原来的构造函数
            constructor: Star,
            sing: function() {
                console.log('我会唱歌');
            },
            movie: function() {
                console.log('我会演电影');
            }
        }

采取赋值来添加,这样就覆盖了constructor,就不能正确指向我们的构造函数,所以在上面我们要手动赋值。

继承
ES5并没有给我们提供extends来继承,我们就采取构造函数+原型对象的“组合继承”。
通过call(参数1(this指向),参数2(正常参数),参数3…)方法。把父类的this指向子类型的this。

继承属性

<script>
        // 借用父构造函数继承属性
        // 1. 父构造函数
        function Father(uname, age) {
            // this 指向父构造函数的对象实例
            this.uname = uname;
            this.age = age;
        }
        // 2 .子构造函数 
        function Son(uname, age, score) {
            // this 指向子构造函数的对象实例
            Father.call(this, uname, age);
            this.score = score;
        }
        var son = new Son('刘德华', 18, 100);
        console.log(son);
    </script>

继承方法

<script>
        // 借用父构造函数继承属性
        // 1. 父构造函数
        function Father(uname, age) {
            // this 指向父构造函数的对象实例
            this.uname = uname;
            this.age = age;
        }
        Father.prototype.money = function() {
            console.log(100000);

        };
        // 2 .子构造函数 
        function Son(uname, age, score) {
            // this 指向子构造函数的对象实例
            Father.call(this, uname, age);
            this.score = score;
        }
        // Son.prototype = Father.prototype;  这样直接赋值会有问题
        //,如果修改了子原型对象,父原型对象也会跟着一起变化
        Son.prototype = new Father();
        // 如果利用对象的形式修改了原型对象,别忘了利用constructor 
        //指回原来的构造函数
        Son.prototype.constructor = Son;
        // 这个是子构造函数专门的方法
        Son.prototype.exam = function() {
            console.log('孩子要考试');

        }
        var son = new Son('刘德华', 18, 100);
        console.log(son);
        console.log(Father.prototype);
        console.log(Son.prototype.constructor);
    </script>

原理:

  1. 将共享方法提取出来,Son.prototype = new Father();
  2. 本质是开辟新的空间,不影响父类正常的原型对象。
  3. 再将constructor指回 son
    在这里插入图片描述
    上图的Son原型对象也有constructor指回Son构造函数

下面是不开辟新空间的后果在这里插入图片描述
这样的话,Son和Father的原型对象就是占同一个空间,会有不好的后果,一修改则全修改。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值