如果您想訂閱本博客內容,每天自動發到您的郵箱中, 請點這里
首先先介紹一下作用域等一些基礎概念。
每個JavaScript函數都是一個對象,對象中有些屬性我們可以訪問,但有些不可以,這些屬性僅供JavaScript引擎存取,[[scope]]就是其中一個。
[[scope]] : 指的就是我們所說的作用域,其中存儲了執行期上下文的集合
作用域鏈 : [[scope]] 中所存儲的執行期上下文對象的集合,這個集合呈鏈式鏈接,我們把這種鏈接叫做作用域鏈。
運行期上下文 : 當函數執行時,會創建一個稱為執行期上下文的內部對象(AO)。一個執行期上下文定義了一個函數執行的環境,函數每次執行時對應的執行環境都是的,所以多次調用一個函數會導致創建多個執行上下文,當函數執行完畢,它所產生的執行上下文被銷毀。
查找變量 :從作用域鏈的頂端依次向下查找。
下面舉一些例子:
之前學過函數的定義、函數表達式,還有一種函數叫做立即執行函數。
立即執行函數:函數執行過后立即被銷毀。
立即執行函數的官方寫法:
針對初始化功能的函數,可以有參數。
只有表達式才能被執行符號執行,能被執行符號執行的表達式,函數名字會被自動忽略。
下面是一道曾阿里面試題
下面是幾道經典的例題,可以參考一下:
那么采用立即執行函數呢?會有怎樣的結果呢?
閉包的現象:當內部函數保存到外部時會產生閉包。
閉包會導致原有的作用域鏈不釋放,造成內存泄漏
(內存泄漏:內存占用(比如:手握沙子,握得越緊手里剩得就越少))
閉包觸發的情況:
兩個或多個函數互相嵌套,把里面的函數保存到外部,這樣的情況一定會產生閉包。從外面還可以調用里面的函數。
閉包的作用:
實現公有變量
eg:函數累加器
可以做緩存(存儲結構)
eg:eater
可以實現封裝,屬性私有化
eg:person()
模塊化開發,防止污染全局變量
附加一個逗號操作符:
先看前面的表達式,再看后面的表達式,把后面表達式的計算結構返回
例題:
作用域
立即執行函數
大家可以自行思考一下。
閉包
如果您想訂閱本博客內容,每天自動發到您的郵箱中, 請點這里
注釋內容以樣式為例,如下:
上面是除了IE瀏覽器外所有瀏覽器都識別這個樣式,另外CSS-TRICKS的《How To Create an IE-Only Stylesheet》一文中提供了另一種寫法:
這種方法是樣式表使用在低于IE10的瀏覽器,換句話說除了IE10以外的所有IE版本都將被支持。
也可以寫成
前面我們也說過了lt和lte的區別,
上面這幾種方法,使用的是低于(lt)和低于或等于(lte)的方法來判斷,我們也可以使用大于
或
參考:
HTML條件注釋用法詮釋
1、支持所有IE瀏覽器
<!--[if IE]>
<link rel="stylesheet" href="all-ie-only.css" type="text/css"/>
<![endif]-->
2、支持非IE瀏覽器
<!--[if !IE]>
<link rel="stylesheet" href="not-ie.css" type="text/css"/>
<![endif]-->
<!--[if !IE]><!--> <link rel="stylesheet" type="text/css" href="not-ie.css" /> <!--<![endif]-->
3、僅僅支持IE10
<!--[if IE 10]>
<link rel="stylesheet" type="text/css" href="ie10.css">
<![endif]-->
4、支持IE10以下版本(IE9以及IE9以下版本)
<!--[if lt IE 10]>
<link rel="stylesheet" type="text/css" href="ie9-and-down.css">
<![endif]-->
<!--[if lte IE 9]>
<link rel="stylesheet" type="text/css" href="ie9-and-down.css">
<![endif]-->
lt表示小于版本號,不包括條件版本號本身;而lte是小于或等于版本號,包括了版本號自身
。
gt
和大于或等于gte
達到上面的效果:
5、高于IE9的版本(IE10以及IE10以上版本)
<!--[if gt IE 9]>
<link rel="stylesheet" type="text/css" href="ie10-and-up.css">
<![endif]-->
<!--[if gte IE 10]>
<link rel="stylesheet" type="text/css" href="ie10-and-up.css">
<![endif]-->
6、指定多種IE版本
<!--[if (IE 6)|(IE 7)|(IE 8)]>
<link rel="stylesheet" type="text/css" href="ie6-7-8.css">
<![endif]-->
https://www.cnblogs.com/hushufang/p/3708704.html
如果您想訂閱本博客內容,每天自動發到您的郵箱中, 請點這里
在微信登錄中,如何和獲取網頁授權。
一、登錄微信測試公眾品平臺,修改網頁授權基本信息,輸入授權回調頁面域名(自己的域名)。
然后重新建立一個tp框架 編寫方法如圖:
在公共模塊中新建function.php
在自己的手機端訪問,就能獲取access_token;
如果您想訂閱本博客內容,每天自動發到您的郵箱中, 請點這里
在 JavaScript 中
如果我們有一個對象
二者的作用完全一樣,知識接受 參數 的方式不太一樣。
在 Javascript 中,多次
三種方法的作用
call
、apply
和 bind
是 Function 對象自帶的三個方法,都是為了改變函數體內部 this
的指向。
call
、apply
和 bind
三者第一個參數都是 this
要指向的對象,也就是想指定的上下文。
call
、apply
和 bind
三者都可以利用后續參數傳參。
bind
是返回對應 函數,便于稍后調用;apply
、call
則是立即調用 。
舉個栗子
function fruits() {}
fruits.prototype = {
color: 'red',
say: function() { console.log('My color is ' + this.color);
}
} var apple = new fruits;
apple.say(); // 此時方法里面的this 指的是fruits // 結果: My color is red
banana= {color : 'yellow'}
,我們不想重新定義 say 方法,那么我們可以通過 call
或 apply
用 apple 的 say 方法:
var banana = { color: 'yellow' };
apple.say.call(banana); // 此時的this的指向已經同過call()方法改變了,指向的是banana,this.color就是banana.color='yellow'; // 結果是My color is yellow
apple.say.apply(banana); // 同理,此時的this的指向已經同過apply()方法改變了,指向的是banana,this.color就是banana.color ='yellow'; // 結果是My color is yellow
apple.say.apply(null); // null是window下的,此時,this 就指向了window ,但是window下并沒有clolr這個屬性,因此this.clolr就是window.color=undefined; // 結果是My color is undefined
call
和 apply
的區別
call
是把參數按順序傳遞進去,而 apply
則是把參數放在 數組 里面。
var array1 = [12,'foo',{name:'Joe'},-2458]; var array2 = ['Doe' , 555 , 100]; Array.prototype.push.call(array1, array2); // 這里用 call 第二個參數不會把 array2 當成一個數組,而是一個元素 // 等價于 array1.push("'Doe' , 555 , 100"); // array1.length=5; Array.prototype.push.apply(array1, array2); // 這里用 apply 第二個參數是一個數組 // 等價于: array1.push('Doe' , 555 , 100); // array1.length=7;
類(偽)數組使用數組方法
var divElements = document.getElementsByTagName('div'); // 雖然 divElements 有 length 屬性,但是他是一個偽數組,不能使用數組里面的方法 Array.isArray(divElements);// false var domNodes = Array.prototype.slice.call(document.getElementsByTagName('div')); // 將數組對象 Array 里的 this 指向偽數組 document.getElementsByTagName('div'), // slice() 方法可從已有的數組中返回選定的元素,不傳參數是,返回整個數組 Array.isArray(domNodes);// true
驗證一個對象的類型可以用
Object.prototype.toString.call(obj)
bind()
方法
bind()
方法會創建一個 新函數,稱為綁定函數,當調用這個綁定函數時,綁定函數會以創建它時傳入 bind()
方法的第一個參數 作為 this,傳入 bind()
方法的 第二個以及以后的參數加上綁定函數運行時本身的參數按照順序作為原函數的參數來調用原函數。
注意
:bind()
方法創建的函數不會立即調用,在下面的例子中,最后 func()
才調用了函數,這是它與 call
和apply
的區別。
var bar = function(){ console.log(this.x);
} var foo = {
x:3 }
bar(); // undefined var func = bar.bind(foo); //此時this已經指向了foo,但是用bind()方法并不會立即執行,而是創建一個新函數,如果要直接調用的話 可以bar.bind(foo)() func(); // 3
bind()
是無效的。更深層次的原因, bind()
的實現,相當于使用函數在內部包了一個 call / apply
,第二次 bind()
相當于再包住第一次 bind()
,故第二次以后的 bind
是無法生效的。
var bar = function(){ console.log(this.x);
} var foo = {
x:3 } var sed = {
x:4 } var func = bar.bind(foo).bind(sed);
func(); //3 var fiv = {
x:5 } var func = bar.bind(foo).bind(sed).bind(fiv);
func(); //3
如果您想訂閱本博客內容,每天自動發到您的郵箱中, 請點這里
最近學習了Flex布局,
以下是阮一峰老師關于Flex的博客 。在此感謝他讓我get一項新技能!
Flex實戰篇:http://www.ruanyifeng.com/blog/2015/07/flex-examples.html
1、色子數:1
思路:讓圓點(即子元素)在橫軸上居中在豎軸上居中,分別用justify-content和align-items
實現代碼:
思路:豎列布局且在主軸方向采用justify-content的兩端對齊布局,這樣兩個圓點會在左邊呈現,然后采用align-items讓其居中
實現代碼:
思路:用到align-self屬性讓第二個和第三個圓點有自己的屬性設置,分別在縱軸方向上居中和低端對齊
實現代碼:
思路:先豎著放兩行圓點,每行圓點里橫著放兩個圓點,所以最外層父元素設置align,里面的父元素設置justify-content
實現代碼:
實現代碼:
思路:跟四點的一樣,先豎放三行在每行橫放兩個圓點
實現代碼:
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
<style> *{ margin:0; padding:0; } body{ background:#000; } .main { width: 200px; height: 200px; background: #fff; border-radius: 20px; margin: 100px auto; padding: 25px; -webkit-box-sizing: border-box; -moz-box-sizing: border-box; box-sizing: border-box; display: flex; justify-content: center; align-items:center; } .main >div{ width:40px; height:40px; background:#000; border-radius:40px; } </style>
</head>
<body>
<div class="main">
<div class="item"></div>
</div>
</body>
</html>
2、色子數:2
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
<style> *{ margin:0; padding:0; } body{ background:#000; } .main { width: 200px; height: 200px; background: #fff; border-radius: 20px; margin: 100px auto; padding: 25px; -webkit-box-sizing: border-box; -moz-box-sizing: border-box; box-sizing: border-box; display: flex; flex-direction: column; justify-content: space-between; align-items:center; } .main >div{ width:40px; height:40px; background:#000; border-radius:40px; } </style>
</head>
<body>
<div class="main">
<div class="item"></div>
<div class="item"></div>
</div>
</body>
</html>
3、色子數:3
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
<style> *{ margin:0; padding:0; } body{ background:#000; } .main { width: 180px; height: 180px; background: #fff; border-radius: 20px; margin: 100px auto; padding: 25px; -webkit-box-sizing: border-box; -moz-box-sizing: border-box; box-sizing: border-box; display: flex; } .main >div{ width:40px; height:40px; background:#000; border-radius:40px; } .item:nth-child(2){ align-self:center; } .item:nth-child(3){ align-self:flex-end; } </style>
</head>
<body>
<div class="main">
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
</div>
</body>
</html>
4、色子數:4
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
<style> *{ margin:0; padding:0; } body{ background:#000; } .main { width: 180px; height: 180px; background: #fff; border-radius: 20px; margin: 100px auto; padding: 25px; -webkit-box-sizing: border-box; -moz-box-sizing: border-box; box-sizing: border-box; display: flex; flex-wrap:wrap; align-content:space-between; } .column >div{ width:40px; height:40px; background:#000; border-radius:40px; } .column{ flex-basis:100%; display:flex; justify-content: space-between; } </style>
</head>
<body>
<div class="main">
<div class="column">
<div class="item"></div>
<div class="item"></div>
</div>
<div class="column">
<div class="item"></div>
<div class="item"></div>
</div>
</div>
</body>
</html>
5、色子數:5
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
<style> *{ margin:0; padding:0; } body{ background:#000; } .main { width: 180px; height: 180px; background: #fff; border-radius: 20px; margin: 100px auto; padding: 25px; -webkit-box-sizing: border-box; -moz-box-sizing: border-box; box-sizing: border-box; display: flex; flex-wrap:wrap; align-content:space-between; } .column > div{ width:40px; height:40px; background:#000; border-radius:40px; } .column{ flex-basis:100%; display:flex; justify-content: space-between; } .column:nth-child(2){ justify-content: center; } </style>
</head>
<body>
<div class="main">
<div class="column">
<div class="item"></div>
<div class="item"></div>
</div>
<div class="column">
<div class="item"></div>
</div>
<div class="column">
<div class="item"></div>
<div class="item"></div>
</div>
</div>
</body>
</html>
6、色子數:6
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
<style> *{ margin:0; padding:0; } body{ background:#000; } .main { width: 180px; height: 180px; background: #fff; border-radius: 20px; margin: 100px auto; padding: 15px; -webkit-box-sizing: border-box; -moz-box-sizing: border-box; box-sizing: border-box; display: flex; align-content:space-between; flex-wrap:wrap; } .column > div{ width:40px; height:40px; background:#000; border-radius:40px; } .column{ flex-basis:100%; display:flex; justify-content: space-between; } </style>
</head>
<body>
<div class="main">
<div class="column">
<div class="item"></div>
<div class="item"></div>
</div>
<div class="column">
<div class="item"></div>
<div class="item"></div>
</div>
<div class="column">
<div class="item"></div>
<div class="item"></div>
</div>
</div>
</body>
</html>
如果您想訂閱本博客內容,每天自動發到您的郵箱中, 請點這里
HTML5引入了應用程序緩存,意味web應用可以進行緩存,在沒有網絡的情況下使用
應用程序緩存為應用帶來的三大優勢:
離線訪問應用
速度更快——已緩存資源加載的更快
減少服務器負載——瀏覽器只從服務器下載更新過或更改過的資源
瀏覽器支持情況:主流瀏覽器都支持,IE要10以上的版本
HTML5通過在html文件添加manifest屬性,啟用應用程序緩存
例子:
<!DOCTYPE HTML>
<htmlmanifest="demo.appcache">
...
</html>
每個指定了 manifest 的頁面在用戶對其訪問時都會被緩存。如果未指定 manifest 屬性,則頁面不會被緩存(除非在 manifest 文件中直接指定了該頁面)。
manifest 文件的建議的文件擴展名是:".appcache"。
manifest 文件需要配置正確的 MIME-type,即 "text/cache-manifest"。必須在 web 服務器上進行配置。
Mainifest文件
manifest 文件是簡單的文本文件,它告知瀏覽器被緩存的內容(以及不緩存的內容)。
例子:
CACHE MANIFEST
# 2012-02-21 v1.0.0
CACHE:
cached.js
cached.css
NETWORK:
uncached.js
uncached.css
FALLBACK:
index.html 404.html
CACHE MANIFEST 寫在manifest文件開頭,是必須的
CACHE作用是標識出哪些文件需要緩存,可以是相對路徑也可以是絕對路徑
NETWORK可選,這一部分是要直接讀取的文件,可以使用通配符 * 。
FALLBACK可選,指定了一個后備頁面,當資源無法訪問時,瀏覽器會使用該頁面。
在線的情況下,瀏覽器發現html頭部有manifest屬性,會請求manifest文件,如果是第一次訪問應用,瀏覽器就會根據manifest文件的內容下載相應的資源并且進行離線存儲。如果已經訪問過應用并且資源已經離線存儲了,那么瀏覽器就會使用離線的資源加載頁面,然后瀏覽器會對比新的manifest文件與舊的manifest文件,如果文件沒有發生改變,就不做任何操作,如果文件改變了,那么就會重新下載文件中的資源并進行離線存儲。
離線的情況下,瀏覽器就直接使用離線存儲的資源。
注意:
1.服務器對離線的資源進行了更新,那么必須更新manifest文件之后這些資源才能被瀏覽器重新下載,如果只是更新了資源而沒有更新manifest文件的話,瀏覽器并不會重新下載資源,也就是說還是使用原來離線存儲的資源。
2.manifest文件進行緩存的時候需要十分小心,因為可能出現一種情況就是你對manifest文件進行了更新,但是http的緩存規則告訴瀏覽器本地緩存的manifest文件還沒過期,這個情況下瀏覽器還是使用原來的manifest文件,所以對于manifest文件最好不要設置緩存。
3.如果更新中某個資源下載失敗,則整個更新就視作失敗,瀏覽器會依舊采用原來的資源
4.站點離線存儲的容量限制是5M
瀏覽器在下載manifest文件中的資源的時候,它會一次性下載所有資源,如果某個資源由于某種原因下載失敗,那么這次的所有更新就算是失敗的,瀏覽器還是會使用原來的資源。
window.applicationCache對象常用事件
1. oncached:當離線資源存儲完成之后觸發這個事件
2. onchecking:當瀏覽器對離線存儲資源進行更新檢查的時候會觸發這個事件
3. ondownloading:當瀏覽器開始下載離線資源的時候會觸發這個事件
4. onprogress:當瀏覽器在下載每一個資源的時候會觸發這個事件,每下載一個資源就會觸發一次。
5. onupdateready:當瀏覽器對離線資源更新完成之后會觸發這個事件
6. onnoupdate:當瀏覽器檢查更新之后發現沒有資源更新的時候觸發這個事件
最后一點是該特性已經從web標準刪除,可能在未來某個時間停止,推薦使用Service Workers 代替。
如果您想訂閱本博客內容,每天自動發到您的郵箱中, 請點這里
JavaScript與HTML之間的交互是通過事件實現的。事件,就是文檔或瀏覽器窗口中發生的一些特定的交互瞬間??梢允褂脗陕犉鱽眍A訂事件,以便事件發生時執行相應的代碼。
示例:
如果點擊容器#btn,則彈出的順序是:btn-content-document;如果點擊的是容器#content,則彈出的是content-document;如果點擊的是document,彈出的是document。
由此可以看出JavaScript的事件流機制
前面說過,IE提出的是冒泡流,而網景提出的是捕獲流,后來在W3C組織的統一之下,JS支持了冒泡流和捕獲流,但是目前低版本的IE瀏覽器還是只能支持冒泡流(IE6,IE7,IE8均只支持冒泡流),所以為了能夠兼容更多的瀏覽器,建議大家使用冒泡流。
JS事件流原理圖如下:
示例:
這個時候,如果點擊一下textSpan這個元素,控制臺會打印出這樣的內容:
從上面所畫的事件傳播的過程能夠看出來,當點擊鼠標后,會先發生事件的捕獲
· 捕獲階段:首先window會獲捕獲到事件,之后document、documentElement、body會捕獲到,再之后就是在body中DOM元素一層一層的捕獲到事件,有wrapDiv、innerP。
· 目標階段:真正點擊的元素textSpan的事件發生了兩次,因為在上面的JavaScript代碼中,textSapn既在捕獲階段綁定了事件,又在冒泡階段綁定了事件,所以發生了兩次。但是這里有一點是需要注意,在目標階段并不一定先發生在捕獲階段所綁定的事件,而是先綁定的事件發生,一會會解釋一下。
· 冒泡階段:會和捕獲階段相反的步驟將事件一步一步的冒泡到window
上述代碼中的兩個屬性:e.target和e.currentTarget
target和currentTarget都是event上面的屬性,target是真正發生事件的DOM元素,而currentTarget是當前事件發生在哪個DOM元素上。
可以結合控制臺打印出來的信息理解下,目標階段也就是 target == currentTarget的時候。我沒有打印它們兩個因為太長了,所以打印了它們的nodeName,但是由于window沒有nodeName這個屬性,所以是undefined。
那可能有一個疑問,我們不用addEventListener綁定的事件會發生在哪個階段呢,我們來一個測試,順便再演示一下我在上面的目標階段所說的目標階段并不一定先發生捕獲階段所綁定的事件是怎么一回事。
控制臺打印如下:
· textSpan是被點擊的元素,也就是目標元素,所有在textSpan上綁定的事件都會發生在目標階段,在綁定捕獲代碼之前寫了綁定的冒泡階段的代碼,所以在目標元素上就不會遵守先發生捕獲后發生冒泡這一規則,而是先綁定的事件先發生。
· 由于wrapDiv不是目標元素,所以它上面綁定的事件會遵守先發生捕獲后發生冒泡的規則。所以很明顯用onclick直接綁定的事件發生在了冒泡階段。
1、直接獲取元素綁定:
優點:簡單和穩定,可以確保它在你使用的不同瀏覽器中運作一致;處理事件時,this關鍵字引用的是當前元素,這很有幫助。
缺點:只會在事件冒泡中運行;一個元素一次只能綁定一個事件處理函數,新綁定的事件處理函數會覆蓋舊的事件處理函數;事件對象參數(e)僅非IE瀏覽器可用。
2、直接在元素里面使用事件屬性
3、W3C方法:
優點:該方法同時支持事件處理的捕獲和冒泡階段;事件階段取決于addEventListener最后的參數設置:false (冒泡) 或 true (捕獲);在事件處理函數內部,this關鍵字引用當前元素;事件對象總是可以通過處理函數的第一個參數(e)捕獲;可以為同一個元素綁定你所希望的多個事件,同時并不會覆蓋先前綁定的事件
缺點:IE不支持,你必須使用IE的attachEvent函數替代。
IE下的方法:
優點:可以為同一個元素綁定你所希望的多個事件,同時并不會覆蓋先前綁定的事件。
注意:不是意味這低版本的ie沒有事件捕獲,它也是先發生事件捕獲,再發生事件冒泡,只不過這個過程無法通過程序控制。
通用:
IE:
在支持addEventListener()的瀏覽器中,可以調用事件對象的stopPropagation()方法以阻止事件的繼續傳播。如果在同一對象上定義了其他處理程序,剩下的處理程序將依舊被調用,但調用stopPropagation()之后任何其他對象上的事件處理程序將不會被調用。不僅可以阻止事件在冒泡階段的傳播,還能阻止事件在捕獲階段的傳播。
IE9之前的IE不支持stopPropagation()方法,而是設置事件對象cancelBubble屬性為true來實現阻止事件進一步傳播。
實際上我們點擊的是textSpan,但是由于在捕獲階段事件就被阻止了傳播,所以在textSpan上綁定的事件根本就沒有發生,冒泡階段綁定的事件自然也不會發生,因為阻止事件在捕獲階段傳播的特性,e.stopPropagation()很少用到在捕獲階段去阻止事件的傳播,大家就以為e.stopPropagation()只能阻止事件在冒泡階段傳播。
e.preventDefault()可以阻止事件的默認行為發生,默認行為是指:點擊a標簽就轉跳到其他頁面、拖拽一個圖片到瀏覽器會自動打開、點擊表單的提交按鈕會提交表單等等,因為有的時候我們并不希望發生這些事情,所以需要阻止默認行為。
IE9之前的IE中,可以通過設置事件對象的returnValue屬性為false達到同樣的效果。
在JavaScript中,添加到頁面上的事件處理程序數量將直接關系到頁面的整體運行性能。導致這一問題的原因是多方面的。首先,每個函數都是對象,都會占用內存;內存中的對象越多,性能就越差。其次,必須事先指定所有事件處理程序而導致的DOM訪問次數,會延遲整個頁面的交互就緒時間。
對“事件處理程序過多”問題的解決方案就是事件委托。事件委托利用了事件冒泡,只指定一個事件處理程序,就可以管理某一類型的所有事件。例如,click事件會一直冒泡到document層次。也就是說,我們可以為整個頁面指定一個onclick事件處理程序,而不必給每個可單擊的元素分別添加事件處理程序。
如果點擊頁面中的li元素,然后輸出li當中的顏色,我們通常會這樣寫:
利用事件流的特性,我們只綁定一個事件處理函數也可以完成:
事件委托還有一個好處就是添加進來的元素也能綁定事件:
沒有使用事件委托:
使用了事件委托:
1事件流
事件流的起源:就是在瀏覽器發展到第四代的時候,瀏覽器開發團隊遇到一個問題:頁面的哪一部分會擁有某個特定的事件?要明白這個問題問的是什么,可以想象畫在一張紙上的一組同心圓。如果你把手指放在圓心上,那么你的手指指向的不是一個圓,而是紙上的所有圓。也就是說如果單擊了頁面的某個按鈕,同時也單擊了按鈕的容器元素,甚至單擊了整個頁面。不過呢,IE提出的是冒泡流,而網景提出的是捕獲流。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>事件流</title> <style type="text/css"> #content{width: 150px;height: 150px;background-color: red;} #btn{width: 80px;height: 80px;background-color: green;} </style> </head> <body> <div id="content">content <div id="btn">button</div> </div> <script type="text/javascript"> var content = document.getElementById("content"); var btn = document.getElementById('btn');
btn.onclick = function(){ alert("btn");
};
content.onclick = function(){ alert("content");
};
document.onclick = function(){ alert("document");
} </script> </body> </html>
2事件冒泡與事件捕獲
由此可以知道:
1、一個完整的JS事件流是從window開始,最后回到window的一個過程
2、事件流被分為三個階段(1~5)捕獲過程、(5~6)目標過程、(6~10)冒泡過程
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> <style type="text/css"> #wrapDiv, #innerP, #textSpan{ margin: 5px;padding: 5px;box-sizing: border-box;cursor: default; } #wrapDiv{ width: 300px;height: 300px;border: indianred 3px solid; } #innerP{ width: 200px;height: 200px;border: hotpink 3px solid; } #textSpan{ display: block;width: 100px;height: 100px;border: orange 3px solid; } </style> </head> <body> <div id="wrapDiv">wrapDiv <p id="innerP">innerP <span id="textSpan">textSpan</span> </p> </div> <script> var wrapDiv = document.getElementById("wrapDiv"); var innerP = document.getElementById("innerP"); var textSpan = document.getElementById("textSpan"); // 捕獲階段綁定事件 window.addEventListener("click", function(e){ console.log("window 捕獲", e.target.nodeName, e.currentTarget.nodeName);
}, true);
document.addEventListener("click", function(e){ console.log("document 捕獲", e.target.nodeName, e.currentTarget.nodeName);
}, true);
document.documentElement.addEventListener("click", function(e){ console.log("documentElement 捕獲", e.target.nodeName, e.currentTarget.nodeName);
}, true);
document.body.addEventListener("click", function(e){ console.log("body 捕獲", e.target.nodeName, e.currentTarget.nodeName);
}, true);
wrapDiv.addEventListener("click", function(e){ console.log("wrapDiv 捕獲", e.target.nodeName, e.currentTarget.nodeName);
}, true);
innerP.addEventListener("click", function(e){ console.log("innerP 捕獲", e.target.nodeName, e.currentTarget.nodeName);
}, true);
textSpan.addEventListener("click", function(e){ console.log("textSpan 捕獲", e.target.nodeName, e.currentTarget.nodeName);
}, true); // 冒泡階段綁定的事件 window.addEventListener("click", function(e){ console.log("window 冒泡", e.target.nodeName, e.currentTarget.nodeName);
}, false);
document.addEventListener("click", function(e){ console.log("document 冒泡", e.target.nodeName, e.currentTarget.nodeName);
}, false);
document.documentElement.addEventListener("click", function(e){ console.log("documentElement 冒泡", e.target.nodeName, e.currentTarget.nodeName);
}, false);
document.body.addEventListener("click", function(e){ console.log("body 冒泡", e.target.nodeName, e.currentTarget.nodeName);
}, false);
wrapDiv.addEventListener("click", function(e){ console.log("wrapDiv 冒泡", e.target.nodeName, e.currentTarget.nodeName);
}, false);
innerP.addEventListener("click", function(e){ console.log("innerP 冒泡", e.target.nodeName, e.currentTarget.nodeName);
}, false);
textSpan.addEventListener("click", function(e){ console.log("textSpan 冒泡", e.target.nodeName, e.currentTarget.nodeName);
}, false); </script> </body> </html>
<script>
var wrapDiv = document.getElementById("wrapDiv"); var innerP = document.getElementById("innerP"); var textSpan = document.getElementById("textSpan"); // 測試直接綁定的事件到底發生在哪個階段
wrapDiv.onclick = function(){
console.log("wrapDiv onclick 測試直接綁定的事件到底發生在哪個階段")
}; // 捕獲階段綁定事件
window.addEventListener("click", function(e){
console.log("window 捕獲", e.target.nodeName, e.currentTarget.nodeName); }, true); document.addEventListener("click", function(e){
console.log("document 捕獲", e.target.nodeName, e.currentTarget.nodeName); }, true); document.documentElement.addEventListener("click", function(e){
console.log("documentElement 捕獲", e.target.nodeName, e.currentTarget.nodeName); }, true); document.body.addEventListener("click", function(e){
console.log("body 捕獲", e.target.nodeName, e.currentTarget.nodeName); }, true); wrapDiv.addEventListener("click", function(e){
console.log("wrapDiv 捕獲", e.target.nodeName, e.currentTarget.nodeName); }, true); innerP.addEventListener("click", function(e){
console.log("innerP 捕獲", e.target.nodeName, e.currentTarget.nodeName); }, true); textSpan.addEventListener("click", function(){
console.log("textSpan 冒泡 在捕獲之前綁定的")
}, false); textSpan.onclick = function(){
console.log("textSpan onclick")
}; textSpan.addEventListener("click", function(e){
console.log("textSpan 捕獲", e.target.nodeName, e.currentTarget.nodeName); }, true); // 冒泡階段綁定的事件
window.addEventListener("click", function(e){
console.log("window 冒泡", e.target.nodeName, e.currentTarget.nodeName); }, false); document.addEventListener("click", function(e){
console.log("document 冒泡", e.target.nodeName, e.currentTarget.nodeName); }, false); document.documentElement.addEventListener("click", function(e){
console.log("documentElement 冒泡", e.target.nodeName, e.currentTarget.nodeName); }, false); document.body.addEventListener("click", function(e){
console.log("body 冒泡", e.target.nodeName, e.currentTarget.nodeName); }, false); wrapDiv.addEventListener("click", function(e){
console.log("wrapDiv 冒泡", e.target.nodeName, e.currentTarget.nodeName); }, false); innerP.addEventListener("click", function(e){
console.log("innerP 冒泡", e.target.nodeName, e.currentTarget.nodeName); }, false); textSpan.addEventListener("click", function(e){
console.log("textSpan 冒泡", e.target.nodeName, e.currentTarget.nodeName); }, false); </script>
[在目標元素上就不會遵守先發生捕獲后發生冒泡這一規則,而是先綁定的事件先發生。]
3事件綁定
element.onclick = function(e){
// ... };
element.addEventListener('click', function(e){
// ... }, false);
element.attachEvent('onclick', function(){
// ... });
缺點:IE僅支持事件捕獲的冒泡階段;事件監聽函數內的this關鍵字指向了window對象,而不是當前元素(IE的一個巨大缺點);事件對象僅存在與window.event參數中;事件必須以ontype的形式命名,比如,onclick而非click;僅IE可用,你必須在非IE瀏覽器中使用W3C的addEventListener。
4解除事件
element.removeEventListener('click', function(e){
// ... }, false);
element.detachEvent('onclick', function(){
// ... });
5阻止事件傳播
<script>
var wrapDiv = document.getElementById("wrapDiv"); var innerP = document.getElementById("innerP"); var textSpan = document.getElementById("textSpan"); // 測試直接綁定的事件到底發生在哪個階段
wrapDiv.onclick = function(){
console.log("wrapDiv onclick 測試直接綁定的事件到底發生在哪個階段")
}; // 捕獲階段綁定事件
window.addEventListener("click", function(e){
console.log("window 捕獲", e.target.nodeName, e.currentTarget.nodeName); }, true); document.addEventListener("click", function(e){
console.log("document 捕獲", e.target.nodeName, e.currentTarget.nodeName); }, true); document.documentElement.addEventListener("click", function(e){
console.log("documentElement 捕獲", e.target.nodeName, e.currentTarget.nodeName); }, true); document.body.addEventListener("click", function(e){
console.log("body 捕獲", e.target.nodeName, e.currentTarget.nodeName); }, true); wrapDiv.addEventListener("click", function(e){
console.log("wrapDiv 捕獲", e.target.nodeName, e.currentTarget.nodeName); // 在捕獲階段阻止事件的傳播
e.stopPropagation(); }, true); innerP.addEventListener("click", function(e){
console.log("innerP 捕獲", e.target.nodeName, e.currentTarget.nodeName); }, true); textSpan.addEventListener("click", function(){
console.log("textSpan 冒泡 在捕獲之前綁定的")
}, false); textSpan.onclick = function(){
console.log("textSpan onclick")
}; textSpan.addEventListener("click", function(e){
console.log("textSpan 捕獲", e.target.nodeName, e.currentTarget.nodeName); }, true); // 冒泡階段綁定的事件
window.addEventListener("click", function(e){
console.log("window 冒泡", e.target.nodeName, e.currentTarget.nodeName); }, false); document.addEventListener("click", function(e){
console.log("document 冒泡", e.target.nodeName, e.currentTarget.nodeName); }, false); document.documentElement.addEventListener("click", function(e){
console.log("documentElement 冒泡", e.target.nodeName, e.currentTarget.nodeName); }, false); document.body.addEventListener("click", function(e){
console.log("body 冒泡", e.target.nodeName, e.currentTarget.nodeName); }, false); wrapDiv.addEventListener("click", function(e){
console.log("wrapDiv 冒泡", e.target.nodeName, e.currentTarget.nodeName); }, false); innerP.addEventListener("click", function(e){
console.log("innerP 冒泡", e.target.nodeName, e.currentTarget.nodeName); }, false); textSpan.addEventListener("click", function(e){
console.log("textSpan 冒泡", e.target.nodeName, e.currentTarget.nodeName); }, false); </script>
6阻止事件的默認行為
function cancelHandler(event){ var event=event||window.event;//兼容IE //取消事件相關的默認行為 if(event.preventDefault) //標準技術 event.preventDefault(); if(event.returnValue) //兼容IE9之前的IE event.returnValue=false; return false; //用于處理使用對象屬性注冊的處理程序 }
7事件委托
在父級上定義了函數,當點擊目標時,會向上冒泡,到父級執行操作。每一個子元素,都會統一冒泡到父級然后執行。
<ul id="color-list"> <li>red</li> <li>yellow</li> <li>blue</li> <li>green</li> <li>black</li> <li>white</li> </ul>
(function(){
var color_list = document.getElementById('color-list'); var colors = color_list.getElementsByTagName('li'); for(var i=0;i<colors.length;i++){ colors[i].addEventListener('click',showColor,false); }; function showColor(e){
var x = e.target; alert("The color is " + x.innerHTML); }; })();
(function(){
var color_list = document.getElementById('color-list'); color_list.addEventListener('click',showColor,false); function showColor(e){
var x = e.target; if(x.nodeName.toLowerCase() === 'li'){
alert('The color is ' + x.innerHTML); } } })();
<body> <ul id="thl"> <li>001</li> <li>002</li> <li>003</li> </ul> <button onclick="fun()">touch</button> <script> var thl= document.getElementById('thl'); var aLi = thl.getElementsByTagName('li'); for (var i = 0; i < aLi.length; i++) {
aLi[i].onclick = fn;
} function fn (){ console.log(this.innerHTML);
} function fun(){ var node=document.createElement("li"); var textnode=document.createTextNode("maomaoliang");
node.appendChild(textnode);
document.getElementById("thl").appendChild(node);
} </script> </body>
藍藍設計( www.syprn.cn )是一家專注而深入的界面設計公司,為期望卓越的國內外企業提供卓越的UI界面設計、BS界面設計 、 cs界面設計 、 ipad界面設計 、 包裝設計 、 圖標定制 、 用戶體驗 、交互設計、 網站建設 、平面設計服務 <script> var thl= document.getElementById('thl');
thl.onclick = function(ev) { ev = ev || event; //兼容處理 var target = ev.target || ev.srcElement; //找到li元素 if (target.nodeName.toLowerCase() == 'li') {
console.log(target.innerHTML);
}
}; function fun(){ var node=document.createElement("li"); var textnode=document.createTextNode("maomaoliang");
node.appendChild(textnode);
document.getElementById("thl").appendChild(node);
} </script>
如果您想訂閱本博客內容,每天自動發到您的郵箱中, 請點這里
1、cookie的作用:
我們在瀏覽器中,經常涉及到數據的交換,比如你登錄郵箱,登錄一個頁面。我們經常會在此時設置30天內記住我,或者自動登錄選項。那么它們是怎么記錄信息的呢,答案就是今天的主角cookie了,Cookie是由HTTP服務器設置的,保存在瀏覽器中,但HTTP協議是一種無狀態協議,在數據交換完畢后,服務器端和客戶端的鏈接就會關閉,每次交換數據都需要建立新的鏈接。就像我們去超市買東西,沒有積分卡的情況下,我們買完東西之后,超市沒有我們的任何消費信息,但我們辦了積分卡之后,超市就有了我們的消費信息。cookie就像是積分卡,可以保存積分,商品就是我們的信息,超市的系統就像服務器后臺,http協議就是交易的過程。
2、機制的區別:
session機制采用的是在服務器端保持狀態的方案,而cookie機制則是在客戶端保持狀態的方案,cookie又叫會話跟蹤機制。打開一次瀏覽器到關閉瀏覽器算是一次會話。說到這里,講下HTTP協議,前面提到,HTTP協議是一種無狀態協議,在數據交換完畢后,服務器端和客戶端的鏈接就會關閉,每次交換數據都需要建立新的鏈接。此時,服務器無法從鏈接上跟蹤會話。cookie可以跟蹤會話,彌補HTTP無狀態協議的不足。
3、cookie的分類:
cookie分為會話cookie和持久cookie,會話cookie是指在不設定它的生命周期expires時的狀態,前面說了,瀏覽器的開啟到關閉就是一次會話,當關閉瀏覽器時,會話cookie就會跟隨瀏覽器而銷毀。當關閉一個頁面時,不影響會話cookie的銷毀。會話cookie就像我們沒有辦理積分卡時,單一的買賣過程,離開之后,信息則銷毀。
持久cookie則是設定了它的生命周期expires,此時,cookie像商品一樣,有個保質期,關閉瀏覽器之后,它不會銷毀,直到設定的過期時間。對于持久cookie,可以在同一個瀏覽器中傳遞數據,比如,你在打開一個淘寶頁面登陸后,你在點開一個商品頁面,依然是登錄狀態,即便你關閉了瀏覽器,再次開啟瀏覽器,依然會是登錄狀態。這就是因為cookie自動將數據傳送到服務器端,在反饋回來的結果。持久cookie就像是我們辦理了一張積分卡,即便離開,信息一直保留,直到時間到期,信息銷毀。
4、簡單的使用cookie的代碼
cookie的幾種常見屬性:document.cookie="key=value;expires=失效時間;path=路徑;domain=域名;secure;(secure表安全級別),
cookie以字符串的形式保存在瀏覽器中。下面貼段代碼出來,是一個類似購物網站的將商品添加到購物車,再從購物車還原商品信息的過程,是自己用原生JS封裝的函數。
封裝的cookie的存入,讀取以及刪除的函數:(這里是將信息以對象的形式存放到cookie中的,會用到JSON的知識)
下面是商品詳情頁的JS代碼
購物車還原商品信息:
藍藍設計( www.syprn.cn )是一家專注而深入的界面設計公司,為期望卓越的國內外企業提供卓越的UI界面設計、BS界面設計 、 cs界面設計 、 ipad界面設計 、 包裝設計 、 圖標定制 、 用戶體驗 、交互設計、 網站建設 、平面設計服務
如果您想訂閱本博客內容,每天自動發到您的郵箱中, 請點這里
說到前端, 大家第一反應是不是都是vue、react、webpack等這些大大小小的框架或者工具, 但其實這些都是和js相關的, 真正的樣式會被大家忽略。其實真正呈現給大家看到華麗的頁面, 都是樣式才讓他們多了那份色彩。那么大家覺得簡單的css樣式, 真的簡單么? 讓我們一起來看下, 開啟css的入坑之旅, 今天一起跟大家簡單聊聊盒模型的相關問題......
百度知道對此的解釋, 很有意思, 在此引用一下
CSS盒子模型, 內容(CONTENT)就是盒子里裝的東西; 而填充(PADDING)就是怕盒子里裝的東西(貴重的)損壞而添加的泡沫或者其它抗震的輔料; 邊框(BORDER)就是盒子本身了; 至于邊界(MARGIN)則說明盒子擺放的時候的不能全部堆在一起,要留一定空隙保持通風,同時也為了方便取出。 —— 百度知道
這段描述很有趣, 很好的解釋margin、border、padding之間的關系, 不同模式下, 盒模型的width也是不同的, 那么好, 盒模型的第一個坑來了, width的范圍問題。
通常瀏覽器里, 盒模型的分為兩種模式, 兩種模式(怪異模式和標準模式)下width和height的值不同, 怪異模式的width和height包含border、padding和content, 而標準模式下的width和height只包含content, 這就是為啥有些瀏覽器渲染出來的dom標簽排版會亂。解決也很簡單, 在標簽的上面, 加上doctype的設置就好了, 讓瀏覽器統一用同一種標準去解析頁面。 怪異模式(左圖)和標準模式(右圖)的如下:
當然, 還有用來改變盒模型width范圍的一個css3的屬性,
當設置為'border-box'時, width = border + padding + content;
當設置為'content-box'時, width = content。
那么第一個div的實際寬度為100px, 第二個div的實際寬度為120px。
說完盒模型的padding和border, 那么再來吐槽下margin, 盒模型的margin的折疊(margin collapsing)問題, 有些也叫外邊距合并。
通常我們說的折疊, 都是垂直方向上的折疊, 水平方向是不存在的。標準模式下, 上下兩個兄弟的塊級元素, margin是會重疊的, 并且以最大的那個間距為準(都為正數)。
比如下面這段代碼:
上圖灰色為重疊部分, 重疊10px的間距。
既然兄弟盒模型會有margin折疊, 那么父子呢? 答案是一定的, 父子也存在margin折疊的問題, 只不過條件稍微苛刻一點, 我們一起來看下。 父子組件的折疊觸發, 要求不能有間隙, 就是父組件不能設置border或padding值, 不能有空余的內容, 且同時有margin值, 比如下面這段代碼:
當然, 折疊后的空余部分, 也是取較大值, 且折疊觸發, 只存在于垂直方向。
上圖灰色為重疊部分, 重疊10px的間距。
剛才提到一個詞"間隙", 如果有間隙的話是不會觸發折疊的, 比如父級元素設置了padding, 或者子元素都設置了相對定位和top值等等。如下圖:
看到這里, 我想有些同學會問了, 對于這些
Margins between a floated box and any other box do not collapse (not even between a float and its in-flow children).
Margins of elements that establish new block formatting contexts (such as floats and elements with 'overflow' other than 'visible') do not collapse with their in-flow children.
Margins of absolutely positioned boxes do not collapse (not even with their in-flow children).
Margins of inline-block boxes do not collapse (not even with their in-flow children).
The bottom margin of an in-flow block-level element always collapses with the top margin of its next in-flow block-level sibling, unless that sibling has clearance.
The top margin of an in-flow block element collapses with its first in-flow block-level child's top margin if the element has no top border, no top padding, and the child has no clearance.
The bottom margin of an in-flow block box with a 'height' of 'auto' and a 'min-height' of zero collapses with its last in-flow block-level child's bottom margin if the box has no bottom padding and no bottom border and the child's bottom margin does not collapse with a top margin that has clearance.
A box's own margins collapse if the 'min-height' property is zero, and it has neither top or bottom borders nor top or bottom padding, and it has a 'height' of either 0 or 'auto', and it does not contain a line box, and all of its in-flow children's margins (if any) collapse.
這是從W3C里引用的原文, 這8條規則是特殊的不折疊的情況, 簡單翻譯過來(僅供參考):
浮動的盒模型不會margin折疊
創建BFC與子不折疊
設置定位的盒模型不會折疊
行內塊級元素的盒模型不折疊
兄弟元素有間隙不折疊
父子盒模型元素, 孩子元素有border、padding、有浮動就不折疊
height為auto、min-height為0的塊級盒模型, 和它的最后一個沒有border和padding的孩子盒模型底邊距折疊, 且孩子的底部外邊距和被清除浮動上邊距有間隙不折疊。
如果min-height為0, 上下border、上下padding都為0, height為0或auto, 且沒有行內盒模型, 他的孩子節點都會折疊
有點晦澀難懂, 大家不妨消化一下。說到這, 再補充一下, 盒模型margin折疊的計算問題, 總結了以下幾點:
同為正值時, 取較大者為兩者為間距
一正一負時, 正負相加為間距, 若結果為負值, 則兩者部分重合
都為負值時, 兩者重合, 且重合部分為絕對值大者
舉個例子:
兩者都為負值, 兩個div上下重合, 且重合間距為15px。
暫時就想到這么多, css的學習之路任重而道遠, 盒模型又是重中之重。上面有描述不對的地方也歡迎各位同學批評指正, 也歡迎大家來到大轉轉FE做客, 一起討論一起研究前端的技術問題。志同道合的同學, 也歡迎加入我們轉轉FE團隊, 咱們一起打拼。
盒模型
box-sizing
:
<div class="wrapper z1"></div>
<div class="wrapper z2"></div>
.wrapper{
width: 100px;
height: 50px;
padding: 10px;
background-color: #dedede;
}
.z1{
box-sizing: border-box;
}
.z2{
box-sizing: content-box;
}
<div class="wrapper"></div>
<div class="wrapper"></div>
.wrapper{
width: 100px;
height: 50px;
margin: 10px;
background-color: #dedede;
}
<div class="outer">
<div class="inner"></div>
</div>
.outer{
width: 200px;
height: 100px;
margin: 10px;
background-color: #dedede;
}
.inner{
width: 100px;
height: 50px;
margin: 10px;
background-color: #bcbcbc;
}
margin collapsing
, 有沒有一個統一的整理, 對于大轉轉的FEer, 我們當然想到了大家的前面, 請看下面:
<div class="wrapper z-01"></div>
<div class="wrapper z-02"></div>
.wrapper{
width: 100px;
height: 50px;
background-color: #dedede;
}
.z-01{
margin: -10px;
}
.z-02{
margin: -15px;
}
如果您想訂閱本博客內容,每天自動發到您的郵箱中, 請點這里
代理模式是為一個對象提供一個代用品或占位符,以便控制對它的訪問。
(可以想象一下明星與經紀人的關系,明星是請求的本體,經紀人就是代理proxy)
代理對象內部含有對本體對象的引用,因而可以與調用本體的相關方法;同時,代理對象提供與本體對象相同的接口,方便在任何時刻代理本體對象。
代理模式的變體有很多,有:保護代理、虛擬代理、緩存代理、防火墻代理、遠程代理、智能引用代理、寫時復制代理。具體介紹前三種。
(1)保護代理
保護代理主要用于控制不同權限的對象對本體對象的訪問權限。比如很多人想訪問本體A,如果有代理B存在的話,B會首先剔除不滿足A的訪問條件的訪問者,符合條件的才能訪問。
作用:過濾請求
例如:權限的劃分和管理就是使用保護代理proxy來完成的。
注冊普通用戶:code為“001”
論壇管理者 :code為“002”
系統管理者 :code為“003”
游 客 :code為“000”
論壇開放了四個基礎功能
1,發帖
2,帖子審核
3,清除帖子
4,留言
游客不具備任何操作權限,注冊用戶只能發帖,論壇管理者可以審核以及刪帖操作,系統管理者具有所有功能權限。
在該例子中,論壇代理有與user本體相同的接口,可以在滿足條件時,執行與本體相同的代碼,與調用方法的人而言,是不透明的,我實現了調用,但不在乎是通過代理實現的,還是本體實現的。
本案例來源:大熊君大話設計模式JavaScript
(2)虛擬代理
虛擬代理是將調用本體方法的請求進行管理,等到本體適合執行時,再執行。
作用:將開銷很大的對象,延遲到真正需要它的時候再執行。
比如:利用虛擬代理實現圖片預加載功能:
比如:利用虛擬代理合并HTTP請求
在這些例子中,虛擬代理對請求進行擱置處理,等到合適的時機,對本體的接口進行調用,可以有效提升Web性能。
(3)緩存代理
緩存代理可以為開銷大的一些運算結果提供暫時性的存儲,如果再次傳進相同的參數是,直接返回結果,避免大量重復計算。
什么情況下使用代理
當我們需要使用的對象很復雜或者需要很長時間去構造,這時就可以使用代理模式(Proxy)。例如:如果構建一個對象很耗費時間和計算機資源,代理模式(Proxy)允許我們控制這種情況,直到我們需要使用實際的對象。一個代理(Proxy)通常包含和將要使用的對象同樣的方法,一旦開始使用這個對象,這些方法將通過代理(Proxy)傳遞給實際的對象。
比如上面的代碼:需要花很長的時間加載很多圖片,復雜的運算過程,頻繁的多次請求處理等;都可以用到代理模式。
小結
代理模式的一個好處就是對外部提供統一的接口方法,而代理類在接口中實現對真實類的附加操作行為,從而可以在不影響外部調用情況下,進行系統擴展。也就是說,我要修改真實角色的操作的時候,盡量不要修改他,而是在外部在“包”一層進行附加行為,即代理類。
什么是代理模式
如何實現代理模式
例子(上代碼)
藍藍設計的小編 http://www.syprn.cn