04-继承和函数的进阶

2020-12-29-继承和函数的进阶

作者:zhzh
时间: 2020-12-29
书籍/博客/视频:前端39期视频–JavaScript高级
网站地址:##

摘要

重点:JavaScript中继承的三种方法,
call函数的 使用
难点:原型和原型对象之间的关系

总结

继承的概念很容易理解,但就是在js中,原型和原型对象之间的关系有点点绕

目录

1、对象之间的继承:

1、用复制的方法实现王sc对王健林的属性的拷贝

    var wjl = {
        name : '王健林',
        money: 10000000,
        cars: ['玛莎拉蒂','特斯拉'],
        houses:['b别墅','dabieshu '],
        play:function () {
            console.log('打高尔夫');
        }
    }
    var wsc = {
        name : '王cs',
    }
    //复制对象的成员给另一个对象
    for (var key in wjl){
        //不给wsc复制名字
        if (wsc[key]){
            continue;
        }
        wsc[key] = wjl[key];
    }
    console.dir(wsc);

2、把复制的代码封装到一个函数中,数据就不会只能是wsc和wjl了,对象的拷贝这里不是继承

    var wjl = {
        name : '王健林',
        money: 10000000,
        cars: ['玛莎拉蒂','特斯拉'],
        houses:['b别墅','dabieshu '],
        play:function () {
            console.log('打高尔夫');
        }
    }
    var wsc = {
        name : '王cs',
    }
    function extend(parent,child) {
        for (var key in parent){
            //不给wsc复制名字
            if (child[key]){
                continue;
            }
            child[key] = parent[key];
        }
    }
    extend(wjl,wsc);
    console.dir(wsc);


2、对象拷贝的应用

1、原来的贪吃蛇案例是通过向数组创建一个和最后一个一样的对象

           //贪吃蛇案例中 吃食物长大的部分
           this.body.push({
               x:last.x,
               y:last.y,
               color: last.color
           })

2、通过调用创建的extend函数来,拷贝最后一个对象的属性

            //创建一个新的对象
            var obj = {};
            //对象拷贝
            extend(last,obj);
            this.body.push(obj);

3、原型继承

继承:是类型和类型之间的关系

JavaScript中 本身并没有继承语法,都是 通过特殊的语法实现相同的效果,模拟继承的效果

把学生和老师的公共属性放到一个person类中

//parent:
	    function person() {
        this.name = 'zs';
        this.age = '';
        this.sex = '';
    }
    function Student() {
        // this.name = 'zs';
        // this.age = '18';
        // this.sex = '男';
        this.score = 100;
    }
//原型继承:无法设置构造函数的参数
Student.prototype = new person();
Student.prototype.constructor = Student;//给原型属性赋值的时候一定要设置constructor
//找不到再去原型属性中去找
var s1 = new Student();

原型链继承的缺点:

​ 1、对原型中引用类型值的误修改:1.1实例中存在和原型对象上同名的属性时,会自动屏蔽原型对象上的同名属性;

​ 1.2原型上任何类型的属性值都不会通过实例被重写,但是引用类型的属性值会受到

​ 实例的影响而修改.

​ 2、原型链不能实现子类向父类中传参.


4、call

call函数的作用和 bind 的作用类似,都是改变函数中this 的指向,并且返回一个新的函数(不可调用函数)

	//bind 改变函数的this,并且返回一个新的函数
    function fn(x,y) {
        console.log(this);
        console.log(x+y);
    }
    window.fn(5,6);

    //改变成指定的
    var o = {
        name : 'zs'
    };
    //bind 改变函数的this,并且返回一个新的函数(不可调用)
    var f = fn.bind(o,1,2);
    f();
    //call,也是改变函数中的this,直接调用函数
    fn.call();

5、借用构造函数

*在子类函数中,通过call ( ) 方法调用父类函数后,子类实例 student, 可以访问到 Person 构造函数里的所有属性和方法。这样就实现了子类向父类的继承,解决了原型对象上对引用类型值的误修改操作

这里如果在实例对象中创建函数在 Student 中就无法访问到实例对象中的方法,如果作为属性放入person中,虽然调用是可以的,但是当每一个实例去调用它的时候就都会去拷贝一份方法,会消耗大量内存,而且同时当需求发生改变的时候就不能够及时的更新。

    function person(name,age,sex) {
        this.name = name;
        this.age = age;
        this.sex = sex;
    }

    // person.prototype.sayHi = function () {
    //     console.log('sayhi');
    // }
    //子类型
    function Student(name,age,sex,score) {
     //用call来改变person中this的指向
        person.call(this,name,age,sex);//这里的this的指向是直接指向Student
       this.socre = score;
    }
    var s1 = new Student('zs',18,'nan',100);
    console.dir(s1);

6、组合继承,7继承的原型图

组合继承 = 原型继承 + 借用构造函数继承

    //组合继承:借用构造函数 + 原型继承
    function Person(name,age,sex) {
        this.name = name;
        this.age = age;
        this.sex = sex;
    }

    Person.prototype.sayHi = function () {
        console.log('大家好,我是' + this.name);
    }
    function Student(name,age,sex,score){
    //借用构造函数
        Person.call(this,name,age,sex);
        this.socre = score;
    }
    //
    Student.prototype = Person.prototype;
    Student.prototype.constructor = Student;
    Student.prototype.exam = function () {
        console.log('考试');
    }
    //这里的person的原型和student的原型都是指向同一个地方,所有在子类型原型中添加一个方法后,其他的也能够调用
    var s1 = new Student('zs',18,'nan',100);
    console.dir(s1);
    var p1 = new Person('ls',18,'男');
    console.dir(p1);

    function Teacher(name,age,sex,salary) {
        Person.call(this,name,age,sex);
        this.salary = salary;
    }
    Teacher.prototype = Person.prototype;
    Teacher.prototype.constructor = Teacher;
    var t1 = new Teacher('ww','nan','1W');
    console.dir(t1);

输出结果:image-20201229155619190

​ 上面这种方式就会导致Teacher在调用person.prototype的时候就会引用到exam方法

解决办法:

//通过原型,让子类型创建一个父类型的方法
Student.prototype = new Person();

输出的结果:image-20201229161016819

原型图:

基础的简单的原型对象:

image-20201229160412605

后面 new 了一个方法后的对象,因为sayhi的方法在person的原型中所以会出现在t1的下一级的下一级,虽然这里t1对象中没有 SayHi 的方法但是在原型链上有sayhi的方法,就可以访问到

image-20201229161526711
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值