闭包和继承(javascript)

闭包和继承



闭包

先不急着定义:


假设我们要做银行系统:


方案一:

var money =100;
money -=10;
console.log(money);

这样写有一个坏处:变量在全局是容易被覆盖的(全局污染);



改进:我们放在局部中

function fn(){
    var money =100;
}

这种情况下我们消费不了(全局无法操作局部变量)。


改进:

function fn(){
    var money = 100;
    return money;
}
var m = fn();
console.log(m);//查询余额

查询和消费:

//消费和查询
function fn(handler,num){
    var money =100;
    if(handler=="消费"){
        money -=num;
    }
    return money;
}
console.log(fn());
console.log(fn("消费",10));
console.log(fn());//消费完又变成100了

局部操作不行,每次查询都是最初始的值


改进:放在局部的局部

function fn(){
    var money =100;
    function fun(handler,num){
        if(handler=="消费"){
            num -=num;
        }
        return money;
    }
     return fun();
}
//查询余额
var m = fn();
console.log(m);

消费不了,调用不了局部函数(下面小改进,将局部返回值改为函数):

function fn(){
    var money =100;
    function fun(handler,num){
        if(handler=="消费"){
            num -=num;
        }
        return money;
    }
     return fun;
}
//改版后查询
var m =fn();
var yue = m();
console.log(yue);
//消费
m('消费',10);
console.log(yue);
//再查询
var yue = m();
console.log(yue);

90,没变成100;因为我们没有调用fn初始化money,一直调用fun



闭包:闭包就是能够读取其他函数内部变量的函数。

总结上面式子,得出闭包的形成条件:大函数返回了一个小函数,小函数使用了大函数的变量



闭包变量的特点:

//未闭包
function ax(){
    var a =1;
    a++;
    return a;
}
console.log(ax());
console.log(ax());
console.log(ax());
console.log(ax());
//都是2,每次运行a都是1,并且a执行完就销毁




//闭包:
//闭包
function big(){
    var a = 1;
    function small(){
        a++;
        return a;
    }
    return small;
}
var  f = big();
console.log(f());
console.log(f());
console.log(f());
console.log(f());
console.log(f());
//不断累加,a的空间没有销毁

闭包的特点:

  1. 变量生命周期变长了
  2. 内部的局部空间没有销毁(一直不销毁内存溢出)
  3. 变量私有化(保护变量不被全局污染)
  4. 全局可以访问并操作局部变量



闭包案例:星星评分

1
2
3
4

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title></title>
</head>

<body>
    <img src="./rank_3.gif" alt=""><img src="./rank_4.gif" alt="">
    <img src="./rank_3.gif" alt=""><img src="./rank_4.gif" alt="">
    <img src="./rank_3.gif" alt=""><img src="./rank_4.gif" alt="">
    <img src="./rank_3.gif" alt=""><img src="./rank_4.gif" alt="">
    <img src="./rank_3.gif" alt=""><img src="./rank_4.gif" alt="">
</body>
<script>
    var imgs = document.querySelectorAll("img");


    for (var i = 0; i < imgs.length; i++) {
        imgs[i].onmouseover = fn(i);  //第一层函数  
    //以前的写法
    /* function (){imgs[i].οnmοuseοver=function(){console.log(i)}都是10
    

        (function(i){
             局部作用域中有i,和下面的闭包是一样的,变量不会被覆盖
            imgs[i].onmouseover = function(){
                console.log(i);
            }
        })


     */
    }
    function fn(i) {//相当于执行了很多次,每次都有自己的作用域,闭包的好处(i一直活着,不会像之前一样死掉)
        return function () {//第二层函数,形成闭包
            //console.log(i);
            for (var j = 0; j <= i; j++) {
                if (j % 2 == 0) {
                    imgs[j].src = "./rank_1.gif";
                } else {
                    imgs[j].src = "./rank_2.gif";
                }
            }
            for (var j = i+1; j < imgs.length; j++) {
                if (j % 2 == 0) {
                    imgs[j].src = "./rank_3.gif";
                } else {
                    imgs[j].src = "./rank_4.gif";
                }
            }
        }
    }
</script>

</html>





继承的概念

一个对象想要另一个对象的属性和方法,就继承另一个对象


俗称换爸爸。

function Animal(){
    this.tui = "2条腿";
}
function Person(){
    this.tedian="能思考";
}
var a = new Animal();
console.log(a);
var zhangsan = new Person();
console.log(zhangsan);


//希望张三属于动物,自动具有两条腿(张三拥有a的特点:属性)
console.log(zhangsan.tui);//undefined,对象里面没有就是undefined


//换原型(换爸爸,原型继承,给原型赋值)
zhangsan.__proto__ =a;
console.log(zhangsan);
console.log(zhangsan.tui);



原型继承

    function ChengLong(){
        this.money = '1000000000000';
    }
    function FanBingBing(){
        this.meise ="美";
    } 
    var cl = new ChengLong();
    console.log(cl);
    var fbb = new FanBingBing();
    console.log(fbb);

//fbb想要cl的钱就需要认他做爸爸
fbb.__proto__ = cl;

原型继承:利用构造函数将原型改成想要的对象

FanBingBing.prototype=cl;

console.log(fbb);



再举个例子:

   function Animal (name,age){
        this.tui = '2条腿',
        this.name = name;
        this.age = age;
    }
    function Person(){
         
    }
  Perosn.prototype = new Animal();
    var man = new Person();
    console.log(man);

继承的缺点:无法动态的给父元素添加属性和方法

推荐的继承缺点链接:点击跳转

下面是引用上面链接的内容

  1. 引用值共享
因为使用的是同一个原型,只要一个修改了原型的值,
那么另一个引用原型的值也会随着更改
  1. 不能传参
Parent.prototype.grand = 'grand';

function Parent (name) {
     this.name = name || 'parent';
     this.color = ['red', 'orange', 'yellow'];
 }

 function Child () {

 }

 Child.prototype = new Parent();
 var child1 = new Child('child1');
 var child2 = new Child('child2');


上面传过去的child1,child2全部没用,都输出parent





上下文调用模式继承(借用函数继承)

function Animal (name,age){
        this.tui = '2条腿',
        this.name = name;
        this.age = age;
    }
    function Person(name,age){
        //animal相当于调用了,调用就会执行里面代码 
        /* 
        this.tui="两条腿",
        this.name = name,
        this.age = age,
        中this被call给改了,改成当前构造函数中的this,man
        */
         Animal.call(this,name,age);
    }

Animal.prototype.eat =function(){
    console.log(this,name,age);
}
    

    //上下文调用模式解决原型继承的缺点 
    Person.prototype = new Animal();
    var man = new Person("张三",12);
    console.log(man);
    console.log(man.eat())

解决了原型继承的引用值和不能传参问题
缺点:

  1. 继承不了原型的原型的方法
  2. 多执行了一次call

参考链接:点击参考好文链接,里面解释非常详细





解决方案:混合继承(原型继承+上下文调用模式继承)

function Animal(name,age){
    this.tui = "2条腿",
    this.name = name;
    this.age = age
}
Animal.prototype.eat=function(){
    console.log("动物方法:看到人看不到的东西");
}
function Person(name,age){
//再上下文调用模式继承
Animal.apply(this,[name,age]);
}

//先原型继承
Person.prototype = new Animal();
var p = new Person("张三",12);
console.log(p.eat())

还剩下几种没有介绍感兴趣点击链接查看:点击此处跳转








es6的class语法

类:抽象的对象

对象:万物皆对象


在初中还是高中生物里面说过:什么什么属于什么科,属之类的话(记不太清了)

拿豌豆举例子,豌豆是对象,属于豌豆属(类)。豌豆是具体的东西,但是豌豆属是将豌豆的特征集合起来的一个定义。你可以根据豌豆属知道豌豆大致具备什么信息。

老例子了:人是对象,但人类不是具体的事物,是人的概念(从人身上抽象出来的)



代码中:

对象 = new 构造函数;

构造函数又叫做类,es6中专门提供了一个语法,专门用来定义类,叫做class

//之前的面向对象写法
function Person() = {
    this.name="张三"
}
var p = new Person();//new 操作叫做实例化
console.log(p);





//es6的面向对象
class Person {//定义好的类是专门用来实例化对象的
//如果要设置这个类中出来的属性----定义一个特殊固定方法:constructor(){}
constructor(name) {
   //new 的时候就是在执行这个constructor 
    this.name =name;
    //所有属性必须写在这个方法中
}
//定义方法
eat(){
    console.log("吃月饼");
}
}
var p = new Person("张三");
console.log(p);
p.eat();


以后面向对象的格式:

class{
    constructor(){
        this.属性名=}
    方法名(){

    }
}






es6面向对象版轮播图

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>面向对象版轮播图</title>
</head>
<style>
    ul,
    ol {
        list-style: none;
    }

    .box {
        width: 500px;
        height: 300px;
        margin-left: 20px;
        position: relative;
    }

    * {
        margin: 0;
        padding: 0;
    }

    ul {
        width: 500px;
        height: 300px;
        border: 1px solid red;

    }

    ul li {
        display: none;
    }

    ul li.active {
        display: block;
    }

    ul li a img {
        width: 500px;
        height: 300px;
    }

    a {
        text-decoration: none;
        color: black;
        font-size: 30px;
    }

    ol {
        width: 200px;
        height: 26px;
        position: absolute;
        background-color: green;
        border-radius: 26px;
        left: calc(50% - 100px);
        bottom: 20px;
        display: flex;
        justify-content: space-evenly;
        align-items: center;
    }

    ol li {
        background-color: gray;
        width: 26px;
        height: 26px;
        border-radius: 26px;
    }

    ol li.active {
        background-color: red;
    }

    .left,
    .right {
        position: absolute;
        left: 0;
        top: calc(50% - 13px);
        height: 50px;
        width: 30px;
        background-color: rgba(0, 0, 0, .5);
        text-align: center;
        line-height: 50px;
    }

    .right {
        left: calc(100% - 28px);
    }
</style>

<body>
    <div class="box">
        <ul>
            <li class="active"><a href="#"><img
                        src="https://ss0.bdstatic.com/70cFuHSh_Q1YnxGkpoWK1HF6hhy/it/u=2493695704,2540399818&fm=26&gp=0.jpg"
                        alt=""></a></li>
            <li><a href=""><img
                        src="https://ss2.bdstatic.com/70cFvnSh_Q1YnxGkpoWK1HF6hhy/it/u=1242578728,2152118644&fm=26&gp=0.jpg"
                        alt=""></a></li>
            <li><a href=""><img
                        src="https://ss2.bdstatic.com/70cFvnSh_Q1YnxGkpoWK1HF6hhy/it/u=3213912571,2486886761&fm=26&gp=0.jpg"
                        alt=""></a></li>
        </ul>
        <ol>
            <li class="active"></li>
            <li></li>
            <li></li>
        </ol>
        <a href="javascript:;" class="left">&lt;</a>
        <a href="javascript:;" class="right">&gt;</a>
    </div>

</body>
<script>
    class Carousel {
        constructor(classname) {
            //在这里写的东西其实就是之前在构造函数中写的东西
            this.box = document.querySelector("." + classname);
            this.ulis = this.box.querySelectorAll("ul li ");
            this.olis = this.box.querySelectorAll("ol li ");
            this.leftBtn = this.box.querySelector("a.left");
            this.rightBtn = this.box.querySelector("a.right");
            this.index = 0;
            this.timerId = null;
        }
        init(){
            this.rightBtn.onclick = function () {
                this.rightMove();
            };
            this.rightBtn.onclick = () => {
                this.rightMove();
            };
            this.leftBtn.onclick = () => {
                this.leftMove();
            };
            for (let i = 0; i < this.olis.length; i++) {
                this.olis[i].onclick = () => {
                    this.dotMove(i);
                }
            };
            this.autoMove();
            this.box.onmouseover=()=>{
                clearInterval(this.timerId);
            };
            this.box.onmouseout=()=>{
                this.autoMove();
            };
        }
        autoMove() {
            this.timerId = setInterval(() => {
                this.rightMove()
            }, 2000)
        };
        rightMove() {
            this.index++;
            if (this.index == this.ulis.length) {
                this.index = 0;
            }
            this.move();
        }
        leftMove() {
            this.index--;
            if (this.index < 0) {
                this.index = this.ulis.length - 1;
            }
            this.move();
        }
        dotMove(i) {
            this.index = i;
            this.move();
        }
        move() {
            for (var i = 0; i < this.ulis.length; i++) {
                this.ulis[i].style.display = "none";
                this.olis[i].style.backgroundColor = "gray";
            }
            this.ulis[this.index].style.display = "block";
            this.olis[this.index].style.backgroundColor = "red";
        }
    }
    var c = new Carousel("box");
    c.init();
</script>

</html>

init不是强求这么写的,但是为了显得专业还是这么写吧。






ES6的继承

class Animal{
    constructor(name,age){
        this.name=name;
        this.age=age;
    }
    eat(){
        console.log("吃月饼");
    }
}
//es6中的继承使用extends关键字 
/* 
子类 extends 父类

*/
class Person extends Animal{
    //se6中继承,子类里面的 constructor的第一行必须调用一个函数叫super
    constructor(name,age){
        super(name,age);//super其实就是在调用父类animal的constructor
    }
}
var p = new Person("张三",12);//new 其实就是在执行constructor
console.log(p);
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值