Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 婷婷99精品国产97久久综合,亚洲欧美在线观看播放,国产资源网站

          整合營銷服務商

          電腦端+手機端+微信端=數據同步管理

          免費咨詢熱線:

          HTML+CSS+JS,20行代碼的貪吃蛇

          csdn上看到一位大神用20行代碼就寫出了一個貪吃蛇的小游戲,鏈接請點這里,感覺被驚艷到了,就試著讀了一下這段代碼,閱讀過程中不斷為作者寫法的巧妙而叫絕,其中我發現自己對運算符優先級和一些js的技巧不是很清楚,所以看完之后決定把思路分享出來,方便和我一樣的小白學習。

          ??我對代碼稍稍做了些修改,并添加了一些注釋,方便理解。

          <!DOCTYPE html>
          <html lang="en">
          <head>
             <meta charset="UTF-8">
             <title>貪吃蛇重構</title>
             <style>
                 body {
                     display: flex;
                     height: 100vh;
                     margin: 0;
                     padding: 0;
                     justify-content: center;
                     align-items: center;
                 }
             </style>
          </head>
          <body>
             <canvas id="can" width="400" height="400" style="background-color: black">對不起,您的瀏覽器不支持canvas</canvas>
             <script>
                 var snake = [41, 40],       //snake隊列表示蛇身,初始節點存在但不顯示
                     direction = 1,          //1表示向右,-1表示向左,20表示向下,-20表示向上
                     food = 43,              //食物的位置
                     n,                      //與下次移動的位置有關
                     box = document.getElementById('can').getContext('2d');
                                             //從0到399表示box里[0~19]*[0~19]的所有節點,每20px一個節點
          
                 function draw(seat, color) {
                     box.fillStyle = color;
                     box.fillRect(seat % 20 *20 + 1, ~~(seat / 20) * 20 + 1, 18, 18);
                                             //用color填充一個矩形,以前兩個參數為x,y坐標,后兩個參數為寬和高。
                 }
          
                 document.onkeydown = function(evt) {    
                                             //當鍵盤上下左右鍵摁下的時候改變direction
                     direction = snake[1] - snake[0] == (n = [-1, -20, 1, 20][(evt || event).keyCode - 37] || direction) ? direction : n;
                 };
          
                 !function() {
                     snake.unshift(n = snake[0] + direction);    
                                             //此時的n為下次蛇頭出現的位置,n進入隊列
                     if(snake.indexOf(n, 1) > 0 || n < 0 || n > 399 || direction == 1 && n % 20 == 0 || direction == -1 && n % 20 == 19) {
                                             //if語句判斷貪吃蛇是否撞到自己或者墻壁,碰到時返回,結束程序
                         return alert("GAME OVER!");
                     }
                     draw(n, "lime");        //畫出蛇頭下次出現的位置
                     if(n == food) {         //如果吃到食物時,產生一個蛇身以外的隨機的點,不會去掉蛇尾
                         while (snake.indexOf(food = ~~(Math.random() * 400)) > 0);
                         draw(food, "yellow");
                     } else {                //沒有吃到食物時正常移動,蛇尾出隊列
                         draw(snake.pop(),"black");
                     }
                     setTimeout(arguments.callee, 150);      
                                             //每隔0.15秒執行函數一次,可以調節蛇的速度
                 }();
             </script>
          </body>
          </html>

          ??首先,我們要知道做一個貪吃蛇最主要的是什么,是做出蛇活動的場所和如何使蛇動起來。??我們先看蛇活動的場所:

          <!-- html -->
             <canvas id="can" width="400" height="400" style="background-color: black">
                 對不起,您的瀏覽器不支持canvas
             </canvas>
             <!-- js -->
             box = document.getElementById('can').getContext('2d');

          ??這是一個 400px*400px的 canvas,思路是以 20px*20px為一個方格,組成 20行 20列的方陣,總共 400格,然后綠色填充的格子表示蛇身,用黃色表示食物。這 400個格子和數字 0~399一一對應,對應的方式就是以 20作為基數, n/20再取整表示第幾行, n%20表示第幾列。行數和列數都用 0~19表示。??蛇用一個一維數組表示,每個值都是這 400個數中的一個,用 varsnake=[41,40];初始化這條蛇,索引 0為蛇頭。food表示食物的位置, direction表示蛇頭下一次運動的轉向。蛇的運動就用添加和刪除數組元素來實現,每次執行繪制蛇頭,去掉蛇尾,循環執行使蛇運動。??下邊從函數運行的起始處( 39行)開始看:

          !function() {}();

          ??什么鬼?這其實是立即執行函數 IIFE的另一種寫法。關于 IIFE,這篇文章講的挺不錯的。繼續往下看,給蛇頭添加一個節點 n,其值為當前蛇頭的值加 direction的值,如此一來就能理解為什么要用 20表示向下, -20表示向上了。再下一行是一個 if語句,其中值得提醒的是 &&的優先級高于 ||,這個語句就是判斷即將出現的蛇頭是不是屬于蛇身,或者跑到box外邊去了。如果沒有死亡,就把這個蛇頭繪制出來,下邊就看看繪制的代碼:

          function draw(seat, color) {
             box.fillStyle = color;
             box.fillRect(seat % 20 *20 + 1, ~~(seat / 20) * 20 + 1, 18, 18);
          }

          ??填充時填充 18*18的像素,留 1px邊框。.fillRect()中第一個參數就是要繪制的矩形的 x坐標 seat%20*20+1,即先得到所要繪制的矩形塊在方陣中的位置:第 ~~(seat/20)行,第 seat%20列,再 *20+1具體到像素點。可能這個 ~~有點難理解,我感覺在這里的用處應該和 Math.floor()差不多,對一個浮點型的數取反再取反,得到的數就是去掉小數位的整數了。



          ??回到 47行,又是一個判斷語句,判斷下次蛇頭出現的位置是不是和當前的食物的位置相同,如果相同,生成下一個食物,食物的位置為一個隨機數,但是要判斷這個點不是出現在當前的蛇身上,繪制食物。如果沒有吃到食物,即蛇在正常運動時,每向前一次,將蛇尾彈出,并利用其返回值將這個點重新繪制為黑色。??最后的 setTimeout,循環執行當前函數,設置執行周期來調蛇的移動速度。??到了這里,我們發現這條蛇已經可以動了,加上鍵盤的操作就完成了:

          document.onkeydown = function(evt) {    
             direction = snake[1] - snake[0] == (n = [-1, -20, 1, 20][(evt || event).keyCode - 37] || direction) ? direction : n;
          };

          ??將這個函數綁定到鍵盤事件上, evt||event用法的原因這里有詳細的解釋,是為了兼容 ie。??三目運算符 ?前邊的判斷語句又可分為兩部分:

          1. snake[1]-snake[0]的值應該就是 -direction,按理說此處寫成 -direction應該和原來是一個效果,那為什么沒有這么做呢,因為如果這樣寫,玩家可能在一個函數周期中多次改變 direction的值,最后使得 direction和當前真正的運動方向不一致,導致游戲崩潰。
          2. 在 ==后邊, [-1,-20,1,20][(evt||event).keyCode-37]中前邊的 []是一個數組,后邊的 []是取索引,左上右下四個鍵的 keyCode分別為 37,38,39,40,計算后的索引為 0,1,2,3,使方向鍵與 direction的取值對應起來。這里的巧妙之處在于如果按下的按鍵不是方向鍵,在數組中將得不到對應的值,返回 undefine。此時,由于之后的 ||運算符, n會取到 direction原來的值。

          ??再用三目運算符來判斷,如果按鍵方向不是反方向,就更新 direction的值。

          以上就是本篇的全部內容啦,雖然都是一些基礎的東西,但是感覺還是挺好玩的。要是哪里理解的不對還希望指證出來,共同進步。

          源自:https://segmentfault.com/a/1190000009770460

          聲明:文章著作權歸作者所有,如有侵權,請聯系小編刪除。

          端程序員,每天接觸的都是瀏覽器。作為一個合格的前端工程師,瀏覽器相關的工作原理是我們對性能優化的基石,今天就來考考自己對瀏覽器了解有多少?

          一、從輸入 URL 到頁面呈現發生了什么?

          在瀏覽器中輸入一個網址,如:https://www.baidu.com 。從輸入地址到我們看到百度首頁,這一過程到底發生了什么?

          1.1、構建網絡請求

          1.2、查找緩存

          檢查如果有緩存,則直接使用緩存,如果沒有緩存,則會向服務器發送網絡請求。

          1.3、DNS解析

          我們訪問網站的時候,輸入的是域名,比如上邊截圖內

          域名:https://www.baidu.com

          IP地址:36.152.44.95:443

          真正的數據包是通過 IP 地址傳過來的,域名和 IP 是 一 一 映射關系。我們根據域名獲取到具體的 IP 這個過程就叫做 DNS 解析。

          IP 地址后的數字指定的端口號,如果沒有,默認是 80 。

          1.4、建立 TCP 連接

          服務器要是想把數據包傳給瀏覽器之前,首先要建立連接。建立 TCP 連接,就是保證服務器與瀏覽器之間能夠進行安全連接通信,數據傳輸完畢之后再斷開連接。

          TCP (Transmission Control Protocol),傳輸控制協議,是一種面向連接的,可靠的,基于字節流的傳輸層通信協議。

          同一個域名下,最多能夠建立 6 個 TCP 連接,超過 6 個的話,剩余的會排隊等待。TCP 連接分為三個階段:

          • 通過三次握手建立瀏覽器與服務器之間的連接。
          • 進行數據傳輸,服務器向瀏覽器發送數據包。
          • 斷開連接的階段,數據傳輸完畢之后,通過四次揮手來斷開連接。

          1.5、發送 HTTP 請求

          TCP 建立連接完畢后,瀏覽器和服務器可以開始通信了,即開始發送 HTTP 請求。

          http 請求,前端程序員就很熟悉嘍!有請求和響應。

          網絡請求流程圖:

          二、頁面是如何渲染的?

          第一個問題講的瀏覽內輸入 url 之后做了做了些啥,最后到發送網絡請求。服務器根據 url 提供的地址查找文件,然后加載 html、css、js、img等資源文件。接收到文件之后瀏覽器是如何渲染的呢?

          瀏覽器渲染的過程為:

          1. 瀏覽器將獲取的 html 文檔解析成 DOM 樹。
          2. 處理 CSS 標記,構成層疊樣式表模型CSSOM。
          3. 將 DOM 和 CSSOM 合并,創建渲染樹(rendering tree),代表一系列將被渲染的對象。
          4. 渲染樹的每個元素包含的內容都是計算過的,它被稱為布局 layout 。瀏覽器使用流式布局的方式,只需一次繪制操作布局所有的元素。
          5. 將渲染樹的各個節點繪制到屏幕上,這一步被稱之為 painting。

          圖示:

          三、瀏覽器緩存是怎么回事?

          3.1、強緩存

          檢查強緩存的時候,不會發送 http 請求。

          如何來檢查呢?通過相應的字段來進行檢查的,在 hTTP/1.0 中使用的是 Expires /,在 HTTP/1.1 使用的是 Cache-Control 。

          Expires

          Expires 即過期時間,存在于服務端返回的響應頭,告訴瀏覽器在過期時間之前可以直接從緩存內獲取數據,無需再次發送網絡請求。

          expires: Wed, 29 Dec 2021 07:19:28 GMT
          
          我是在2021-12-22 12:30左右 請求的 https://www.baidu.com/ ,
          返回的 expires 內容如上。
          表示資源在 2012-12-29 07:12:28 過期,在這之前不會向服務器發送請求

          這個方式你看有毛病嗎?潛藏了一個大坑,如果電腦的本地時間與服務器時間不一致時,那么服務器返回的這個過期時間可能就是不準確的,因此這種方式在 HTTP 1.1 中被拋棄了。

          Cache-Control

          在 HTTP1.1 中,采用了一個非常關鍵的字段:Cache-Control 。這個字段也存在于響應頭中。如:

          cache-control: max-age=2592000

          代表的是這個響應返回后,在 (2592/3600=720小時)直接可以直接使用緩存。

          它和 Expires 本質的不同在于它并沒有采用具體的時間點,而是采用的時長來控制強緩存。如果 Expires 和 Cache-Control 同時存在的時候,Cache-Control 會優先考慮。

          強緩存有沒有可能失效呢?如果資源緩存時間超時,也就是強緩存失效了,接下來該怎么辦呢?此時就會進入到第二級屏障 -- 協商緩存。

          3.2、協商緩存

          強緩存失效之后,瀏覽器在請求頭中攜帶相應的 緩存tag 向服務器發送請求,服務器根據這個 緩存tag 決定到底是否使用緩存,這就是協商緩存

          緩存 tag 有兩種:ETag 和 Last-Modified 。

          ETag 是服務器根據當前文件內容生成的唯一標識,如果內容發生更新,唯一標識也會更新。瀏覽器接收到的 ETag 會作為 if-None-Match 字段的內容,并放到請求頭中,發送給服務器之后,服務器會與服務器上的 值進行對比,如果兩者一樣,瀏覽器直接返回304,使用緩存。不一樣時發送 http 請求。

          Last-Modified ,最后修改時間。瀏覽器第一次發送網絡請求后,服務器會在響應頭上加上該字段。瀏覽器再發請求時,會把該值作為 last-Modified-Since 的值,放入請求頭,然后服務器會與服務器上的最后修改時間進行對比,如果兩者一樣,瀏覽器直接返回304,使用緩存。不一樣時發送 http 請求。

          兩者對比:

          精準度上 ETag 更好一點。因為 ETag 能夠更準確的判斷資源是否有更新,保證拉取到的都是最新內容。

          性能上 Last-Modified 剛好一點,只需要記錄一個時間點就好了。

          如果兩者都存在的話,優先考慮 ETag。

          3.3、緩存位置

          前邊講述,瀏覽器請求地址時,服務器返回 304 表示使用瀏覽器緩存,這些資源究竟緩存到哪了呢?

          緩存位置一共有四種,按照優先級由高到低排列分別為:

          • Service Worker
          • Memory Cache
          • Disk Cache
          • Push Cache

          四、瀏覽器的本地存儲有哪些?

          所謂本地存儲,就是把一些信息,存儲到客戶端本地,存儲的信息不會因為頁面的跳轉或關閉而消失。瀏覽器本地存儲主要分為:cookie、webStorage 和 indexDB。

          4.1、cookie

          cookie 主要為了辨別用戶身份。彌補 http 在狀態管理上的不足。

          http 是一個無狀態協議,瀏覽器向服務器發送請求之后,服務器返回響應,下次再請求的時候,服務器已經不認識瀏覽器了,如果瀏覽器下次再發送請求時,能夠把 cookie 帶上,服務器進行解析,便能夠辨別瀏覽器的身份。

          cookie 就是用來存儲狀態的,它的特點分別有:

          • 能夠兼容所有瀏覽器,它和服務器之間有一定的關聯。
          • 存儲大小限制:一般瀏覽器規定同源下最多只能存儲 4KB 大小
          • cookie 存在過期時間,過期時間可以自己設置。
          • cookie 不穩定,清除瀏覽器緩存或三方清理垃圾時容易把 cookie 移除掉。
          • 用戶可以根據句自己的需求開啟 cookie 緩存,如果開啟無痕瀏覽器或隱身模式時,將關閉 cookie。

          4.2、webStorage

          webStorag 可分為 localStorage 和 sessionStorage ,是本地持久化存儲,本地持久化存儲用來保存一些不需要發送給服務器的信息,用來補充 cookie 存儲方式不足。

          localStorage 特點:

          • 不兼容低版本瀏覽器 IE6-8 。
          • 生命周期是永久的,除非用戶主動清除,否則一直存在。
          • 存儲的數據大小一般為 5M,各瀏覽器之間有差異。
          • 不受瀏覽器無痕模式或隱身模式影響。
          • 嚴格的本地存儲,與服務器之間沒有關系。

          sessionStorage 特點:

            • 不兼容低版本瀏覽器 IE6-8 。
            • 僅在當前會話下有效,關閉當前頁面或關閉瀏覽器,就會被清除。
            • 存儲的數據大小一般為 5M,各瀏覽器之間有差異。
            • 嚴格的本地存儲,與服務器之間沒有關系。

          localStorage 和 sessionStorage 有一個本質區別,localStorage 生命周期是永久化的,而 sessionStorage 只存在于當前會話。

          4.3、indexedDB

          indexedDB 是 html5 提供的一種本地存儲,一般保存大量用戶數據并要求數據之間有搜索需要的場景,當網絡斷開,做一些離線應用,數據格式為 json 。本質上是一個 非關系型數據庫。它的容量是沒有上限的。

          特點:

          • 存儲空間較大,默認250M 。
          • 鍵值對操作,可以進行數據庫讀取和遍歷,也可以用索引進行高效的檢索。
          • 受同源策略限制,無法跨域訪問數據庫。

          總結:瀏覽器本地存儲每種方式都有各自的特點,cookie 比較小適合存儲與服務器之間通信的較小狀態信息,webStorage 存儲不參與服務器通信的數據,indexedDB 存儲大型的非關系型數據庫。

          五、什么是 XSS 攻擊?

          XSS ( Cross Site Scripting ) 跨站腳本,為了與 CSS 區分,故意叫做 XSS 。主要是由于網站程序員對用戶輸入過濾不足,導致攻擊者利用輸入可以在頁面進行顯示或盜取用戶信息,利用身份信息進行惡意操作的一種攻擊方式。

          講直白點,就是惡意攻擊者通過在輸入框處添加惡意 script 代碼,用戶瀏覽網頁的時候執行 script 代碼,從而達到惡意攻擊用戶的目的。

          5.1、XSS 攻擊類型

          XSS 攻擊實現有三種方式:存儲型、反射型 和 文檔寫。

          存儲型

          表面意思理解,就是將惡意腳本存儲起來。將腳本存儲到服務器的數據庫,然后在客戶端執行這些惡意腳本,從而達到攻擊效果。

          比如,在評論區提交一段 script 代碼,如果前后端不做任何轉義工作,直接把腳本存儲到數據庫,頁面加載數據的時候,渲染時發現它是 js 代碼,就會直接執行,相當于執行了一段未知邏輯的 js 。

          反射型

          反射型 XSS 指的是惡意腳本作為網絡請求的一部分。

          瀏覽器請求接口如:

          http://www.xxx.com?q=<script>alert("惡意腳本")</script>

          會將參數 q=<script>alert("惡意腳本")</script> 傳遞給服務器,服務器將內容返回給瀏覽器,瀏覽器渲染時,發現它是 js 腳本,就會直接執行。所以頁面一加載的時候,就會有一個彈框。

          之所以稱為反射型,是因為它是從瀏覽器通過網絡請求經過服務器,然后又返回瀏覽器,執行解析。

          文檔型

          文檔型的 XSS 攻擊不會經過服務器,作為中間人的角色,在數據傳輸過程中劫持到網絡數據包,然后修改里面的 html 文檔。

          常見的 wifi 劫持 或者本地惡意軟件。

          XSS 攻擊危害包括:

          • 盜取用戶各類賬號,如機器登錄賬號,用戶網銀,各類管理員賬號。
          • 控制企業數據,包括讀取,篡改、添加、刪除敏感數據。
          • 盜竊具有商業價值的資料。
          • 控制受害者機器向其他網站發起攻擊。
          • 劫持別人的廣告,點擊廣告之后跳轉到自己的廣告頁

          5.2、XSS防范措施

          措施1:XSS 攻擊原理就是惡意執行 js 腳本,我們要防范它,只需要在用戶輸入的地方,對輸入的內容進行轉碼或過濾。

          如:
          <script>
            alert('惡意腳本')
          </script>
          
          //轉碼后
          <script>alert('惡意腳本')</script>

          這樣在代碼 html 中解析時,不會當做 js 腳本執行。

          措施2:CSP ,瀏覽器中的內容安全策略,就是決策瀏覽器加載哪些資源。具體的有:

          • 同源策略,限制其他域下的資源加載。
          • 禁止在當前頁面向其他域下提交數據。
          • 提供上報機制,能夠及時發現 XSS 攻擊。

          措施3:HttpOnly,如果 cookie 設置了 httponly,那么通過 js 腳本無法獲取到 cookie 信息。這樣能夠有效防止 XSS 攻擊,竊取用戶信息。

          六、http 和 https

          瀏覽器訪問 http 的網站的時候,域名前面會提示“不安全”,訪問 https//xxx.com 的時候瀏覽器提示 “安全”,這是為什么呢?

          http 協議,超文本傳輸協議,被用于在服務器和瀏覽器之間傳遞信息,http協議以明文方式發送內容,不提供任何方式的數據加密,如果攻擊者直接截取瀏覽器和服務器之間傳輸報文,就可以直接讀懂其中的信息。

          為了解決 http 協議的缺陷,使用 https 安全套接字層超文本傳輸協議,為了保證數據的安全性,在 http 協議的基礎上,新增了 SSL 協議,SSL依靠證書來驗證服務器的身份器,并未瀏覽器和服務器之間的通信加密。

          https 并不是一個新協議,而是一個加強版的 http 。簡單講 https 協議由 SSL+http 協議構建成可進行加密傳輸、身份認證的網絡協議,要比 http 協議安全。

          https 和 http 的區別:

          • https 協議需要申請安全證書,一般免費較少,需要費用,而 http 不需要。
          • https 具有 SSL 加密傳輸,更加安全,而 http 是明文傳輸,不安全。
          • https 和 http 使用的不同連接方式,用的默認端口不一樣,http 是 80,https是443。
          • http 的連接簡單,沒有狀態,而 https 是需要通過 SSL 校驗身份信息的,相對更加安全。

          https 工作原理圖:

          加解密過程

          接著我們來談談瀏覽器和服務器進行協商加解密的過程。

          首先,瀏覽器會給服務器發送一個隨機數client_random和一個加密的方法列表。

          服務器接收后給瀏覽器返回另一個隨機數server_random和加密方法。

          現在,兩者擁有三樣相同的憑證: client_random、server_random和加密方法。

          接著用這個加密方法將兩個隨機數混合起來生成密鑰,這個密鑰就是瀏覽器和服務端通信的暗號。


          主站蜘蛛池模板: 99精品国产一区二区三区| 国产成人精品久久一区二区三区| 日本免费一区二区久久人人澡| 日韩AV无码一区二区三区不卡毛片| 成人区人妻精品一区二区不卡视频| 69久久精品无码一区二区| 色视频综合无码一区二区三区| 精品免费国产一区二区| 激情内射亚洲一区二区三区爱妻| 日本一区二区三区精品中文字幕| 国产主播一区二区三区| 无码人妻AⅤ一区二区三区水密桃 无码欧精品亚洲日韩一区夜夜嗨 无码毛片一区二区三区中文字幕 无码毛片一区二区三区视频免费播放 | 精品成人av一区二区三区| 日韩视频在线观看一区二区| 一区二区三区观看免费中文视频在线播放 | 寂寞一区在线观看| 91视频一区二区| 免费无码AV一区二区| 中文字幕精品无码一区二区三区| 国产乱人伦精品一区二区| 福利在线一区二区| 亚洲一区二区三区高清不卡 | 伊人色综合一区二区三区| 亚洲一区二区三区丝袜| 无码精品视频一区二区三区| 四虎一区二区成人免费影院网址 | 国产99精品一区二区三区免费| 精品国产乱子伦一区二区三区| 视频一区二区在线观看| 国产精品综合一区二区| 影音先锋中文无码一区| 无码人妻久久一区二区三区免费丨| 97精品国产福利一区二区三区| 国产精品亚洲产品一区二区三区 | 精品国产一区二区三区www| 无码丰满熟妇一区二区| 极品尤物一区二区三区| 亚洲AV成人一区二区三区观看| 日韩精品区一区二区三VR| 久久se精品一区二区| 少妇无码一区二区二三区|