15_JS闭包、对象、原型

闭包

在程序语言中,所谓闭包,是指语法域位于某个特定的区域,具有持续参照(读写)位于该区域内自身范围之外的执行域上的非持久型变量值能力的段落。这些外部执行域的非持久型变量神奇地保留他们在闭包最初定义(或创建)时的值。
  白话: 我们可以用一个函数 去访问 另外一个函数的内部变量的方式就是闭包。

  • 变量作用域
function outFun() {
        var num = 10;  //  outFun 的一个变量
        function inFun() {
            var key = 10;
            console.log(num);  //   外部函数的变量可以被内部函数所使用
        }
        console.log(key);    // 这样是不可以的,内部函数的变量不可以被外部函数所使用
    }
  • 闭包常用写法
function outFun(){
        var num = 10;// 让fun 函数以外的函数 的使用 num 的值  就可以创建闭包
        function inFun(){
            console.log(num);
        }
        return inFun;// 返回的是 inFun函数体  核心
}
//        使用
var demo = outFun();
console.log(demo);
demo();//输出10,这个10是另外一个函数的变量
  • 闭包练习
        function outerFun(){
            var a = 0;
            function innerFun(){
                a++;
                alert(a);
            }
            return innerFun;
        }
        var o1 = outerFun();
        o1();//1
        o1();//2

        var o2 = outerFun();
        o2();//1
        o2();//2
  • 简写
  function outerFun(){
            var a = 0;
            function innerFun(){
                a++;
                alert(a);
            }
            return innerFun;
        }

可以这样简写

        function outerFun(){
            var a = 0;
            return function(){
                a++;
                alert(a);
            }
        }
  • 闭包传参
        function outerFun(x){
            function innerFun(){
                console.log(x);
            }
            return innerFun;//不能带括号
        }
        var obj = outerFun(4);
        obj();

        function outerFun(x){
            function innerFun(y){
                console.log(x+y);
            }
            return innerFun;//不能带括号
        }
        var obj = outerFun(4);
        obj();//NaN
        obj(2);//6
  • **闭包的优缺点 : **
  • 优点:不产生全局变量,实现属性私有化。
  • 缺点:闭包中的数据会常驻内存,在不用的时候要删掉否则会导致内存溢出。

例:闭包案例,事件参数传递

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title></title>
    <style type="text/css">
        .box{
            position: absolute;
            left: 0;
            width: 100px;
            height: 100px;
            background-color: red;
        }
    </style>
    <script type="text/javascript">
        window.onload = function () {
            var btn1 = document.getElementById("btn1");
            var btn2 = document.getElementById("btn2");
            var box = document.getElementById("box");
            //以前的传统写法
            /*
            var speed = 5;
            btn1.onclick = function () {
                box.style.left = box.offsetLeft+speed+"px";
            }
            btn2.onclick = function () {
                box.style.left = (box.offsetLeft-speed)+"px";
            }
            */
            //封装函数的写法
            /*
            btn1.onclick = function () {
                move(5);
            }
            btn2.onclick = function () {
                move(-5);
            }
            function move(speed){
                box.style.left = box.offsetLeft+speed+"px";
            }
            */
            //闭包传递参数的写法
            function move(speed){
                return function () {
                    box.style.left = box.offsetLeft+speed+"px";
                }
            }
            btn1.onclick = move(5);
            btn2.onclick = move(-5);
        }
    </script>
</head>
<body>
    <button id="btn1">右走</button>
    <button id="btn2">左走</button>
    <div class="box" id="box"></div>
</body>
</html>

例:tab栏切换,使用闭包

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title></title>
    <style type="text/css">
        body,ul,li{
            margin: 0;
            padding: 0;
        }
        ul,li{
            list-style: none;
        }
        .box{
            width: 500px;
            height: 430px;
            margin: 15px auto;
        }
        .tab-btn{
            width: 500px;
            height: 30px;
        }
        .tab-btn li{
            float: left;
            width: 100px;
            height: 30px;
            line-height: 30px;
            background-color: #ccc;
            color: #333;
            text-align: center;
        }
        .tab-btn .current{
            background-color: red;
            color:#fff;
        }
        .tab-con div{
            width: 500px;
            height: 400px;
            background-color: red;
            display: none;
        }
        .tab-con .show{
            display: block;
        }
    </style>
    <script type="text/javascript">
        window.onload = function () {
            function $(id){return document.getElementById(id);}
            function tab(id){
                var lis = $(id).getElementsByTagName("li");
                var cons = $(id).getElementsByClassName("tab-con")[0].getElementsByTagName("div");
                for(var i=0; i<lis.length; i++){
                    lis[i].index = i;
                    lis[i].onmouseover = tab(i);
                }

                //使用了闭包
                function tab(num){
                    return function () {
                        for(var j=0; j<lis.length; j++){//清除所有
                            lis[j].className = "";
                            cons[j].className = "";
                        }
                        lis[num].className = "current";//留下当前的
                        cons[num].className = "show";
                    }
                }
            }
            tab("one");//第一个tab栏
            tab("two");//第二个tab栏
        }
    </script>
</head>
<body>
<div class="box" id="one">
    <div class="tab-btn">
        <ul>
            <li class="current">首页</li>
            <li>新闻时事</li>
            <li>体育</li>
            <li>购物</li>
            <li>游戏</li>
        </ul>
    </div>
    <div class="tab-con">
        <div class="show">首页</div>
        <div>新闻时事</div>
        <div>体育</div>
        <div>购物</div>
        <div>游戏</div>
    </div>
</div>
<div class="box" id="two">
    <div class="tab-btn">
        <ul>
            <li class="current">首页</li>
            <li>新闻时事</li>
            <li>体育</li>
            <li>购物</li>
            <li>游戏</li>
        </ul>
    </div>
    <div class="tab-con">
        <div class="show">首页</div>
        <div>新闻时事</div>
        <div>体育</div>
        <div>购物</div>
        <div>游戏</div>
    </div>
</div>
</body>
</html>

修改为闭包的立即执行,修改之后

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title></title>
    <style type="text/css">
        body,ul,li{
            margin: 0;
            padding: 0;
        }
        ul,li{
            list-style: none;
        }
        .box{
            width: 500px;
            height: 430px;
            margin: 15px auto;
        }
        .tab-btn{
            width: 500px;
            height: 30px;
        }
        .tab-btn li{
            float: left;
            width: 100px;
            height: 30px;
            line-height: 30px;
            background-color: #ccc;
            color: #333;
            text-align: center;
        }
        .tab-btn .current{
            background-color: red;
            color:#fff;
        }
        .tab-con div{
            width: 500px;
            height: 400px;
            background-color: red;
            display: none;
        }
        .tab-con .show{
            display: block;
        }
    </style>
    <script type="text/javascript">
        window.onload = function () {
            function $(id){return document.getElementById(id);}
            function tab(id){
                var lis = $(id).getElementsByTagName("li");
                var cons = $(id).getElementsByClassName("tab-con")[0].getElementsByTagName("div");
                for(var i=0; i<lis.length; i++){
                    lis[i].index = i;
                    lis[i].onmouseover = function(num){//闭包的立即执行
                        return function () {
                            for(var j=0; j<lis.length; j++){//清除所有
                                lis[j].className = "";
                                cons[j].className = "";
                            }
                            lis[num].className = "current";//留下当前的
                            cons[num].className = "show";
                        }
                    }(i);
                }
            }
            tab("one");//第一个tab栏
            tab("two");//第二个tab栏
        }
    </script>
</head>
<body>
<div class="box" id="one">
    <div class="tab-btn">
        <ul>
            <li class="current">首页</li>
            <li>新闻时事</li>
            <li>体育</li>
            <li>购物</li>
            <li>游戏</li>
        </ul>
    </div>
    <div class="tab-con">
        <div class="show">首页</div>
        <div>新闻时事</div>
        <div>体育</div>
        <div>购物</div>
        <div>游戏</div>
    </div>
</div>
<div class="box" id="two">
    <div class="tab-btn">
        <ul>
            <li class="current">首页</li>
            <li>新闻时事</li>
            <li>体育</li>
            <li>购物</li>
            <li>游戏</li>
        </ul>
    </div>
    <div class="tab-con">
        <div class="show">首页</div>
        <div>新闻时事</div>
        <div>体育</div>
        <div>购物</div>
        <div>游戏</div>
    </div>
</div>
</body>
</html>

tab栏切换添加函数节流

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title></title>
    <style type="text/css">
        body,ul,li{
            margin: 0;
            padding: 0;
        }
        ul,li{
            list-style: none;
        }
        .box{
            width: 500px;
            height: 430px;
            margin: 15px auto;
        }
        .tab-btn{
            width: 500px;
            height: 30px;
        }
        .tab-btn li{
            float: left;
            width: 100px;
            height: 30px;
            line-height: 30px;
            background-color: #ccc;
            color: #333;
            text-align: center;
        }
        .tab-btn .current{
            background-color: red;
            color:#fff;
        }
        .tab-con div{
            width: 500px;
            height: 400px;
            background-color: red;
            display: none;
        }
        .tab-con .show{
            display: block;
        }
    </style>
    <script type="text/javascript">
        window.onload = function () {
            function $(id){return document.getElementById(id);}
            function tab(id){
                var lis = $(id).getElementsByTagName("li");
                var cons = $(id).getElementsByClassName("tab-con")[0].getElementsByTagName("div");
                for(var i=0; i<lis.length; i++){
                    lis[i].index = i;
                    var timer = null;
                    lis[i].onmouseover = function(num){//闭包的立即执行+函数节流
                        return function () {
                            clearTimeout(timer);
                            timer = setTimeout(function () {
                                for(var j=0; j<lis.length; j++){//清除所有
                                    lis[j].className = "";
                                    cons[j].className = "";
                                }
                                lis[num].className = "current";//留下当前的
                                cons[num].className = "show";
                            },300);
                        }
                    }(i);
                    lis[i].onmouseout = function () {
                        clearTimeout(timer);
                    }
                }
            }
            tab("one");//第一个tab栏
            tab("two");//第二个tab栏
        }
    </script>
</head>
<body>
<div class="box" id="one">
    <div class="tab-btn">
        <ul>
            <li class="current">首页</li>
            <li>新闻时事</li>
            <li>体育</li>
            <li>购物</li>
            <li>游戏</li>
        </ul>
    </div>
    <div class="tab-con">
        <div class="show">首页</div>
        <div>新闻时事</div>
        <div>体育</div>
        <div>购物</div>
        <div>游戏</div>
    </div>
</div>
<div class="box" id="two">
    <div class="tab-btn">
        <ul>
            <li class="current">首页</li>
            <li>新闻时事</li>
            <li>体育</li>
            <li>购物</li>
            <li>游戏</li>
        </ul>
    </div>
    <div class="tab-con">
        <div class="show">首页</div>
        <div>新闻时事</div>
        <div>体育</div>
        <div>购物</div>
        <div>游戏</div>
    </div>
</div>
</body>
</html>

例:立即执行函数

<script type="text/javascript">
        var fun = function(){}
        //方式一
        fun();//立即执行
        //方式二
        function(){}();//立即执行
    </script>

案例:如上tab栏的修改之后

例:函数节流

        window.onload = function () {
            var box = document.getElementById("box");
            var num = 0;

            window.onresize = throttle(function () {
                num++;
                box.innerHTML = window.innerWidth||document.documentElement.clientWidth;
                console.log(num);
            },30);

            function throttle(fn,delay){//闭包,节流
                var timer = null;
                return function () {
                    clearInterval(timer);
                    timer = setTimeout(fn,delay);
                }
            }
        }

对象(object)

对象是什么?
基本数据类型 :string number boolean null undefined
Array对象
对象数据类型: 对象就是带有属性和方法的数据类型

var num = 10;   // 变量
var arr = [];  // 数组
arr.index = 10;  // 数组arr 的 一个 index  属性

但是有个问题, 我们想要某些属性或者方法的时候,用数组不合适。arr.lenght
我们想要自己id属性和方法 。 要求这个一定是个对象才行。

声明对象

我们有两种声明对象的方式.

var obj = new Object();

但是我们更提倡用第二种方法: 字面量式声明对象

var obj = {};

var obj = {};  // 声明对象
obj.name = "刘德华";  // 属性
obj.age = 55;
obj.showName = function() {   // 声明方法    方法一定带有 ()
    alert("俺是刘德华");
}
obj.showAge = function() {
    alert("俺今年18岁");
}

使用对象

console.log(obj.name);  // 调用属性
console.log(obj.age);
obj.showName();   //  调用方法
obj.showAge();

this


    <script type="text/javascript">
        function fn(){
            console.log(this);//this指向window对象
        }
        fn();

        function fn1(){
            this.x = 12;
        }
        fn1();
        console.log(window.x);//打印12

        new fn();//使用new的函数,this指向新的对象,而不是window

        function person(){
            this.x = 20;
        }

        var demo = new person();
        console.log(demo.x);//打印20
        console.log(window.x);//打印12
    </script>

new

我们经常利用new 关键字 去声明新的对象
  new运算符的作用是创建一个对象实例。这个对象可以是用户自定义的,也可以是带构造函数的一些系统自带的对象。
  new 关键字可以让 this 指向新的对象
  所谓"构造函数",其实就是一个普通函数,但是内部使用了this变量。对构造函数使用new运算符,就能生成实例,并且this变量会绑定在实例对象上。

prototype

共同的 相同的 部分
主要解决:函数因为使用非常非常多,重复执行效率太低。

Person.prototype.showName = function() {  // 用的共同的父亲
    alert("我的名字是"+ this.name);
}

类.prototype.方法 = function() {} 具体格式

可以把那些不变的属性和方法,直接定义在prototype对象上
使用方法:类名.prototype.方法

<script type="text/javascript">
        Array.prototype.run = function () {
            console.log(this);
            console.log(this.length);
        }
        var demo1 = [1,2,3,5];
        demo1.run();

        var demo2 = [5];
        demo2.run();
    </script>

        function Person(name,age){
            this.name = name;
            this.age = age;
        }
        Person.prototype.showName = function () {
            alert("名称="+this.name);
        }
        var p1 = new Person("刘德华",24);
        var p2 = new Person("张学友",23);
        p1.showAge = function () {
            alert("年龄="+this.age);
        }
        p2.showAge = function () {
            alert("年龄="+this.age);
        }

        alert(p1.showAge == p2.showAge);//false
        alert(p1.showName == p2.showName);//true
        alert(p1.showName === p2.showName);//true

上面第一个打印false,第二个打印true,第三个打印true

例:下拉菜单,面向对象版

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>无标题文档</title>
<style type="text/css">
*{ padding:0; margin:0; list-style:none;}
.all{ width:330px; height:30px; background:url(img/bg.jpg) no-repeat; margin:100px auto; line-height:30px; text-align:center; padding-left:10px; margin-bottom:0;}
.all ul li{ width:100px; height:30px; background:url(img/libg.jpg); float:left; margin-right:10px; position:relative; cursor:pointer;}
.all ul ul{ position:absolute; left:0; top:30px; display:none;}
</style>
</head>

<body>
<div class="all" id="list">
    <ul>
        <li>一级菜单
            <ul>
                <li>二级菜单</li>
                <li>二级菜单</li>
                <li>二级菜单</li>
            </ul>
        </li>
        <li>一级菜单
            <ul>
                <li>二级菜单</li>
                <li>二级菜单</li>
                <li>二级菜单</li>
            </ul>
        </li>
        <li>一级菜单
            <ul>
                <li>二级菜单</li>
                <li>二级菜单</li>
                <li>二级菜单</li>
            </ul>
        </li>
    </ul>
</div>
</body>
</html>
<script>
    // 获取对象     遍历对象操作     显示模块   隐藏模块

    function List(id) {  //  获取对象
        this.id = document.getElementById(id);  // 取 id 值
        this.lis = this.id.children[0].children;  // 获取一级菜单所有的li
    }
    // init 初始化
    List.prototype.init = function() {  // 遍历所有的li 显示和隐藏
        var that  = this;
        for(var i=0;i<this.lis.length;i++)
        {
            this.lis[i].index = i;
            this.lis[i].onmouseover = function() {
                that.show(this.children[0]);  //  显示出来
            }
            this.lis[i].onmouseout = function() {
                that.hide(this.children[0]);  // 隐藏起来
            }
        }
    }
    //  显示模块
    List.prototype.show = function(obj) {
        obj.style.display = "block";
    }
    // 隐藏模块
    List.prototype.hide = function(obj) {
        obj.style.display = "none";
    }
    var list = new List("list");  // 实例化了一个对象 叫  list
    list.init();
</script>
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 157,198评论 4 359
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,663评论 1 290
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 106,985评论 0 237
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,673评论 0 202
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 51,994评论 3 285
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,399评论 1 211
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,717评论 2 310
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,407评论 0 194
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,112评论 1 239
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,371评论 2 241
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,891评论 1 256
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,255评论 2 250
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,881评论 3 233
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,010评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,764评论 0 192
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,412评论 2 269
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,299评论 2 260

推荐阅读更多精彩内容