15_JS閉包、對象、原型

閉包

在程序語言中,所謂閉包,是指語法域位于某個特定的區(qū)域,具有持續(xù)參照(讀寫)位于該區(qū)域內(nèi)自身范圍之外的執(zhí)行域上的非持久型變量值能力的段落。這些外部執(zhí)行域的非持久型變量神奇地保留他們在閉包最初定義(或創(chuàng)建)時的值。
  白話: 我們可以用一個函數(shù) 去訪問 另外一個函數(shù)的內(nèi)部變量的方式就是閉包。

  • 變量作用域
function outFun() {
        var num = 10;  //  outFun 的一個變量
        function inFun() {
            var key = 10;
            console.log(num);  //   外部函數(shù)的變量可以被內(nèi)部函數(shù)所使用
        }
        console.log(key);    // 這樣是不可以的,內(nèi)部函數(shù)的變量不可以被外部函數(shù)所使用
    }
  • 閉包常用寫法
function outFun(){
        var num = 10;// 讓fun 函數(shù)以外的函數(shù) 的使用 num 的值  就可以創(chuàng)建閉包
        function inFun(){
            console.log(num);
        }
        return inFun;// 返回的是 inFun函數(shù)體  核心
}
//        使用
var demo = outFun();
console.log(demo);
demo();//輸出10,這個10是另外一個函數(shù)的變量
  • 閉包練習
        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
  • **閉包的優(yōu)缺點 : **
  • 優(yōu)點:不產(chǎn)生全局變量,實現(xiàn)屬性私有化。
  • 缺點:閉包中的數(shù)據(jù)會常駐內(nèi)存,在不用的時候要刪掉否則會導致內(nèi)存溢出。

例:閉包案例,事件參數(shù)傳遞

<!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");
            //以前的傳統(tǒng)寫法
            /*
            var speed = 5;
            btn1.onclick = function () {
                box.style.left = box.offsetLeft+speed+"px";
            }
            btn2.onclick = function () {
                box.style.left = (box.offsetLeft-speed)+"px";
            }
            */
            //封裝函數(shù)的寫法
            /*
            btn1.onclick = function () {
                move(5);
            }
            btn2.onclick = function () {
                move(-5);
            }
            function move(speed){
                box.style.left = box.offsetLeft+speed+"px";
            }
            */
            //閉包傳遞參數(shù)的寫法
            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>

修改為閉包的立即執(zhí)行,修改之后

<!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){//閉包的立即執(zhí)行
                        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欄切換添加函數(shù)節(jié)流

<!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){//閉包的立即執(zhí)行+函數(shù)節(jié)流
                        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>

例:立即執(zhí)行函數(shù)

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

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

例:函數(shù)節(jié)流

        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){//閉包,節(jié)流
                var timer = null;
                return function () {
                    clearInterval(timer);
                    timer = setTimeout(fn,delay);
                }
            }
        }

對象(object)

對象是什么?
基本數(shù)據(jù)類型 :string number boolean null undefined
Array對象
對象數(shù)據(jù)類型: 對象就是帶有屬性和方法的數(shù)據(jù)類型

var num = 10;   // 變量
var arr = [];  // 數(shù)組
arr.index = 10;  // 數(shù)組arr 的 一個 index  屬性

但是有個問題, 我們想要某些屬性或者方法的時候,用數(shù)組不合適。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);  // 調(diào)用屬性
console.log(obj.age);
obj.showName();   //  調(diào)用方法
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的函數(shù),this指向新的對象,而不是window

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

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

new

我們經(jīng)常利用new 關(guān)鍵字 去聲明新的對象
  new運算符的作用是創(chuàng)建一個對象實例。這個對象可以是用戶自定義的,也可以是帶構(gòu)造函數(shù)的一些系統(tǒng)自帶的對象。
  new 關(guān)鍵字可以讓 this 指向新的對象
  所謂"構(gòu)造函數(shù)",其實就是一個普通函數(shù),但是內(nèi)部使用了this變量。對構(gòu)造函數(shù)使用new運算符,就能生成實例,并且this變量會綁定在實例對象上。

prototype

共同的 相同的 部分
主要解決:函數(shù)因為使用非常非常多,重復(fù)執(zhí)行效率太低。

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

例:下拉菜單,面向?qū)ο蟀?/p>

<!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>
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容