閉包
在程序語言中,所謂閉包晃听,是指語法域位于某個特定的區(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ù)的變量
- 閉包練習(xí)
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)缺點(diǎn) : **
- 優(yōu)點(diǎn):不產(chǎn)生全局變量,實(shí)現(xiàn)屬性私有化膨处。
- 缺點(diǎn):閉包中的數(shù)據(jù)會常駐內(nèi)存见秤,在不用的時候要刪掉否則會導(dǎo)致內(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";//留下當(dāng)前的
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";//留下當(dāng)前的
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";//留下當(dāng)前的
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運(yùn)算符的作用是創(chuàng)建一個對象實(shí)例羞酗。這個對象可以是用戶自定義的,也可以是帶構(gòu)造函數(shù)的一些系統(tǒng)自帶的對象紊服。
new 關(guān)鍵字可以讓 this 指向新的對象
所謂"構(gòu)造函數(shù)"檀轨,其實(shí)就是一個普通函數(shù),但是內(nèi)部使用了this變量欺嗤。對構(gòu)造函數(shù)使用new運(yùn)算符裤园,就能生成實(shí)例,并且this變量會綁定在實(shí)例對象上剂府。
prototype
共同的 相同的 部分
主要解決:函數(shù)因?yàn)槭褂梅浅7浅6嗯±浚貜?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("張學(xué)友",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>無標(biāo)題文檔</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"); // 實(shí)例化了一個對象 叫 list
list.init();
</script>