继承和进阶函数

18 篇文章 1 订阅
2 篇文章 0 订阅


前言

这部分学习继承和进阶函数,深化js学习。


一、继承

1.对象拷贝

通过for in的方式将父级的内容拷贝给子级。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <script>
        var laoli = {
            name: "laoli",
            money: 1000000,
            house: ["商铺","住宅"],
            tech: function () {
                console.log("厨艺");
            }
        };
        var xiaoli = {
            name: "xiaoli"
        };
        //封装一个继承的函数
        function extend(parent,child) {
            for (var k in parent){
            //判断子级是否含有父级的元素
            if (child[k]) {
                continue;
            }
            child[k] = parent[k];
            }
        }
        //调用函数 实现继承
        extend(laoli,xiaoli);
        console.log(xiaoli);
    </script>
</body>
</html>

2.原型继承

通过原型来继承。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <script>
        //人类类型
        function Person(name,age,sex) {
            this.name = name;
            this.age = age;
            this.sex = sex;
        }
        //学生类型
        function Student(score) {
            this.score = score;
        }
        //老师类型
        function Teacher(salary) {
            this.salary = salary;
        }
        //通过原型让学生继承人类
        Student.prototype = new Person("zs",18,"男");
        Student.prototype.constructor = Student;
        var s1 = new Student(88);
        var s2 = new Student(100);
        console.log(s2);
    </script>
</body>
</html>

3.构造函数属性继承

(1)call方法
功能:既能执行函数,又能将this的指向改变
参数:第一个参数是this指向的内容,第二个及后续参数是执行函数的参数

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <script>
        //call方法有两个功能
        //1.能够将内容指向this
        //2.执行函数
        function fn(a,b) {
            console.log(this);
            console.log(a+b);
        }
        var o = {
            name: "lm"
        }
        //call有两个参数,第一个参数是指向this,第二个及以后的参数是正常的需要执行函数的参数
        fn.call(o,3,4);
    </script>
</body>
</html>

(2)构造函数属性继承(通过使用call方法)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <script>
        //人类类型
        function Person(name,age,sex) {
            this.name = name;
            this.age = age;
            this.sex = sex;
        }
        //学生类型
        function Student(name,age,sex,score) {
            Person.call(this,name,age,sex);
            this.score = score;
        }
        //老师类型
        function Teacher(name,age,sex,salary) {
            Person.call(this,name,age,sex);
            this.salary = salary;
        }
        var s1 = new Student("zs",17,"男",88);
        var s2 = new Student("ls",19,"男",90);
        console.dir(s1);
        console.dir(s2);
        
    </script>
</body>
</html>

4.构造函数方法继承

(1)第一种方式:拷贝继承

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <script>
        //人类类型
        function Person(name,age,sex) {
            this.name = name;
            this.age = age;
            this.sex = sex;
        }
        Person.prototype.sayHi = function () {
            console.log("你好");
        };
        //学生类型
        function Student(name,age,sex,score) {
            Person.call(this,name,age,sex);
            this.score = score;
        }
        //第一种方式:拷贝继承
        for (var k in Person.prototype) {
            //将constructor重新指向Student
            if (k === "constructor") {
                Student.prototype.constructor = Student;
            }
            Student.prototype[k] = Person.prototype[k];
        }
        //第二种方式:原型继承
        // Student.prototype = new Person();
        // Student.prototype.constructor = Student;
        //老师类型
        function Teacher(name,age,sex,salary) {
            Person.call(this,name,age,sex);
            this.salary = salary;
        }
        var s1 = new Student("zs",17,"男",88);
        var s2 = new Student("ls",19,"男",90);
        console.dir(s1);
        console.dir(s2);
        s1.sayHi();
    </script>
</body>
</html>

(2)第二种方式:原型继承

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <script>
        //人类类型
        function Person(name,age,sex) {
            this.name = name;
            this.age = age;
            this.sex = sex;
        }
        Person.prototype.sayHi = function () {
            console.log("你好");
        };
        //学生类型
        function Student(name,age,sex,score) {
            Person.call(this,name,age,sex);
            this.score = score;
        }
        //第一种方式:拷贝继承
        // for (var k in Person.prototype) {
        //     //将constructor重新指向Student
        //     if (k === "constructor") {
        //         Student.prototype.constructor = Student;
        //     }
        //     Student.prototype[k] = Person.prototype[k];
        // }
        //第二种方式:原型继承
        Student.prototype = new Person();
        Student.prototype.constructor = Student;
        //老师类型
        function Teacher(name,age,sex,salary) {
            Person.call(this,name,age,sex);
            this.salary = salary;
        }
        var s1 = new Student("zs",17,"男",88);
        var s2 = new Student("ls",19,"男",90);
        console.dir(s1);
        console.dir(s2);
        s1.sayHi();
    </script>
</body>
</html>

5.组合继承

组合继承:属性继承在构造函数内部继承,方法继承通过原型对象继承。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <script>
        //组合继承:属性继承在构造函数内部继承,方法继承通过原型对象继承
        function Person(name,age) {
            this.name = name;
            this.age = age;
        }
        Person.prototype.sayHi = function () {
            console.log("你好");
        };
        //一个子级继承父级的属性和方法
        function Student(name,age,score) {
            //继承父级的属性
            Person.call(this,name,age);
            this.score = score;
        }
        //继承父级方法
        Student.prototype = new Person();
        Student.prototype.constructor = Student;
        //创建实例
        var s1 = new Student("gg",22,100);
        console.log(s1.name);
        s1.sayHi();
    </script>
</body>
</html>

二、函数进阶

1.函数的调用和this

函数调用根据目前的学习,在五种情况下,有五种不同的调用方法,同时this的指向也不同,但this的具体指向要根据实际调用的情况来决定。
在这里插入图片描述
接下来通过代码来体验不同方式调用函数的方式以及this的指向。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <script>
        //五种不同的函数调用方式
        //1.普通函数调用通过变量名加()来调用
        //默认this指向window
        function fun() {
            console.log("普通函数调用");
        }
        fun();
        //2.构造函数通过new方式调用
        //this指向实例对象
        function Person(name) {
            this.name = name;
        }
        var fn = new Person("gg");
        //3.对象函数通过对象打点调用
        //this指向该方法所使用的对象
        var funs = {
            sayHi: function () {
                console.log("对象函数");
            }
        };
        funs.sayHi();
        //4.事件函数,当事件执行时就自动进行调用
        //this指向事件函数
        document.onclick = function () {
            console.log("事件函数");
        }
        //5.定时器和延时器,在规定时间内自动进行调用
        //this指向window
        setInterval(function () {
            console.log("定时器");
        },1000)
    </script>
</body>
</html>

2.改变this指向的三种方法

(1)call
(2)apply
(3)bind
下面通过代码来看各种方法的功能、参数及返回值。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <script>
        function fn(a,b) {
            console.log(this);
            console.log(a+b);
        }
        var o = {
            name: "hg"
        };
        //call方法
        //1.功能:更改this指向的对象,执行函数并传参数
        //2.参数:第一个参数是this指向的对象,第二个以后的参数指向的是参数列表
        //3.返回值:返回的是函数执行的结果
        fn.call(o,1,2);
        //apply方法
        //1.功能:更改this指向的对象,执行函数并传参数
        //2.参数:第一个参数是this指向的对象,第二个以后的参数是参数数组
        //3.返回值:返回的是函数执行的结果
        fn.apply(o,[2,3]);
        //bind方法
        //1.功能:更改this指向的对象,不能执行函数,但可以传参数
        //2.参数:第一个参数是this指向的对象,第二个以后的参数指向的是参数列表,参数可以接收存储
        //3.返回值:this的指向
        var fn = fn.bind(o,2,5);
        console.log(fn);
        fn(6,8);
    </script>
</body>
</html>

3.call的应用

使用call方法改变this的指向,可以将this指向数组,从而给对象添加一些数组可以使用的方法,那么对象就也可以使用数组的方法了。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <script>
        var o = {
            0: 10,
            1: 20,
            2: 30,
            length: 3
        }
        //将this指向数组,借用数组的push方法,给对象添加最后一项数据
        Array.prototype.push.call(o,40);
        console.log(o);

    </script>
</body>
</html>

4.apply的应用

同样的,可以利用apply方法将this指向Math,从而给数组添加一些数组没有的方法。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <script>
        var arr = [1,2,6,9,3];
        //数组本身是不具备给数组中的数找最大值的,但是Math中的max方法可以找最大值
        //那么我们就可以将this指向max,从而让数组也可以找最大值
        console.log(Math.max.apply(null,arr));

        //可以将数组输出为零散的数,而不是一个数组
        console.log(arr);
        console.log.apply(null,arr);
    </script>
</body>
</html>

5.bind的应用

在只指定this并且不需要执行函数的时候使用,那么就可以应用于事件函数更改this和定时器内部函数更改this,接下来用代码进行进一步的理解。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <script>
        //更改定时内部函数的this
        var o = {
            name: "zs",
            age: 18,
            timer: function () {
                setInterval(function () {
                    console.log(this.age);
                }.bind(this),1000);
            }
        }
        o.timer();

        //更改事件函数内部的this
        document.onclick = function () {
            console.log(this);
        }.bind(o);

    </script>
</body>
</html>

6.高阶函数

两种情况下是高阶函数:
(1)参数作为另一个函数的参数
(2)函数的返回值是一个函数

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <script>
        //高阶函数
        //函数作为另一个函数的参数
        function eat(fn) {
            console.log("吃饭");
            fn();
        }
        eat(function () {
            console.log("看书");
        });
        //函数的返回值是一个函数
        function outer(n) {
            return function inner(m) {
                console.log(m+n);
            }
        }
        var fun = outer(100);
        fun(3);
        fun(20);
        var fun1 = outer(1000);
        fun1(2);
        fun1(30);
    </script>
</body>
</html>

三、闭包

1.闭包的理解和应用

一个函数和对其周围状态(lexical environment,词法环境)的引用捆绑在一起(或者说函数被引用包围),这样的组合就是闭包(closure)。也就是说,闭包让你可以在一个内层函数中访问到其外层函数的作用域。在 JavaScript 中,每当创建一个函数,闭包就会在函数创建的同时被创建出来。
闭包的用途:可以在函数外部读取内部成员,让函数内的成员始终存活在内存中。
函数定义时天生就能记住自己生成的作用域环境和函数自己,将它们形成一个密团的环境,这就是闭包。不论函数以任何方式在任何地方进行调用,都会回到自己定义时的密闭环境进行执行。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <script>
        function outer() {
            var a = 10;
            function inner() {
                console.log(a++);
            }
            return inner;
        }
        var fun = outer();
        fun();
        fun();
    </script>
</body>
</html>

2.闭包的问题

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <script>
        var arr = [];
        for (var i = 0 ; i <= 10 ; i++ ) {
            (function (i) {
                arr[i] = function () {
                    console.log(i);
                }
            })(i);
        }
        arr[0]();
        arr[1]();
        arr[2]();

    </script>
</body>
</html>

总结

这部分学习了继承和函数的进阶,能够更好地掌握函数,能更加熟练的书写js代码,使代码更加简洁。每天坚持学习前端~
在这里插入图片描述

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值