沐鳴註冊網站_CSS浮動標準修復top塌陷和清除浮動及IE兼容標準格式

1、浮動的特性

1、浮動元素有左浮動(float:left)和右浮動(float:right)兩種
2、浮動的元素會向左或向右浮動,碰到父元素邊界、其他元素才停下來
3、相鄰浮動的塊元素可以並在一行,超出父級寬度就換行
4、浮動讓行內元素或塊元素自動轉化為行內塊元素(此時不會有行內塊元素間隙問題)
5、浮動元素後面沒有浮動的元素會佔據浮動元素的位置,沒有浮動的元素內的文字會避開浮動的元素,形成文字饒圖的效果
6、父元素如果沒有設置尺寸(一般是高度不設置),父元素內整體浮動的元素無法撐開父元素,父元素需要清除浮動
7、浮動元素之間沒有垂直margin的合併

2、浮動的缺點及坑

1、top塌陷
2、li子元素浮動屬性無法對ul的
3、IE對:after或者:befroe兼容

3、clearfix修復代碼標準格式


  
   
    /*top塌陷*/ .clearfix:after,.clearfix:before{ content: ""; display: table; } /*清除浮動*/ .clearfix:after{ clear: both; } /*IE兼容*/ .clearfix{ zoom: 1; }
   
  

__EOF__

本文作者:
胸毛君
本文鏈接:https://www.cnblogs.com/lzq70112/p/13130246.html

站長推薦

1.雲服務推薦: 國內主流雲服務商,各類雲產品的最新活動,優惠券領取。地址:阿里雲騰訊雲華為雲

2.廣告聯盟: 整理了目前主流的廣告聯盟平台,如果你有流量,可以作為參考選擇適合你的平台點擊進入

鏈接: http://www.fly63.com/article/detial/9317

沐鳴測速註冊_你真的了解ES6的Set,WeakSet,Map和WeakMap嗎?

之前在學習 ES6 的時候,看到 Set 和 Map,不知道其應用場景有哪些,只覺得很多時候會用在數組去重和數據存儲,後來慢慢才領悟到 Set 是一種叫做集合的數據結構,Map 是一種叫做字典的數據結構。

本文在gitthub做了收錄:https://github.com/Michael-lzg/my–article/blob/master/javascript/

Set

Set 本身是一個構造函數,用來生成 Set 數據結構。Set 函數可以接受一個數組(或者具有 iterable 接口的其他數據結構)作為參數,用來初始化。Set 對象允許你存儲任何類型的值,無論是原始值或者是對象引用。它類似於數組,但是成員的值都是唯一的,沒有重複的值。

const s = new Set()
[2, 3, 5, 4, 5, 2, 2].forEach((x) => s.add(x))
for (let i of s) {
  console.log(i)
}
// 2 3 5 4

Set 中的特殊值

Set 對象存儲的值總是唯一的,所以需要判斷兩個值是否恆等。有幾個特殊值需要特殊對待:

  • +0 與 -0 在存儲判斷唯一性的時候是恆等的,所以不重複
  • undefined 與 undefined 是恆等的,所以不重複
  • NaN 與 NaN 是不恆等的,但是在 Set 中認為 NaN 與 NaN 相等,所有隻能存在一個,不重複。

Set 的屬性:

  • size:返回集合所包含元素的數量
const items = new Set([1, 2, 3, 4, 5, 5, 5, 5])
items.size // 5

Set 實例對象的方法

  • add(value):添加某個值,返回 Set 結構本身(可以鏈式調用)。
  • delete(value):刪除某個值,刪除成功返回 true,否則返回 false。
  • has(value):返回一個布爾值,表示該值是否為 Set 的成員。
  • clear():清除所有成員,沒有返回值。
s.add(1).add(2).add(2)
// 注意2被加入了兩次

s.size // 2

s.has(1) // true
s.has(2) // true
s.has(3) // false

s.delete(2)
s.has(2) // false

遍歷方法

  • keys():返回鍵名的遍歷器。
  • values():返回鍵值的遍歷器。
  • entries():返回鍵值對的遍歷器。
  • forEach():使用回調函數遍歷每個成員。

由於 Set 結構沒有鍵名,只有鍵值(或者說鍵名和鍵值是同一個值),所以 keys 方法和 values 方法的行為完全一致。

let set = new Set(['red', 'green', 'blue'])

for (let item of set.keys()) {
  console.log(item)
}
// red
// green
// blue

for (let item of set.values()) {
  console.log(item)
}
// red
// green
// blue

for (let item of set.entries()) {
  console.log(item)
}
// ["red", "red"]
// ["green", "green"]
// ["blue", "blue"]

Array 和 Set 對比

  • Array 的 indexOf 方法比 Set 的 has 方法效率低下
  • Set 不含有重複值(可以利用這個特性實現對一個數組的去重)
  • Set 通過 delete 方法刪除某個值,而 Array 只能通過 splice。兩者的使用方便程度前者更優
  • Array 的很多新方法 map、filter、some、every 等是 Set 沒有的(但是通過兩者可以互相轉換來使用)

Set 的應用

1、Array.from 方法可以將 Set 結構轉為數組。

const items = new Set([1, 2, 3, 4, 5])
const array = Array.from(items)

2、數組去重

// 去除數組的重複成員
;[...new Set(array)]

Array.from(new Set(array))

3、數組的 map 和 filter 方法也可以間接用於 Set

let set = new Set([1, 2, 3])
set = new Set([...set].map((x) => x * 2))
// 返回Set結構:{2, 4, 6}

let set = new Set([1, 2, 3, 4, 5])
set = new Set([...set].filter((x) => x % 2 == 0))
// 返回Set結構:{2, 4}

4、實現並集 (Union)、交集 (Intersect) 和差集

let a = new Set([1, 2, 3])
let b = new Set([4, 3, 2])

// 並集
let union = new Set([...a, ...b])
// Set {1, 2, 3, 4}

// 交集
let intersect = new Set([...a].filter((x) => b.has(x)))
// set {2, 3}

// 差集
let difference = new Set([...a].filter((x) => !b.has(x)))
// Set {1}

weakSet

WeakSet 結構與 Set 類似,也是不重複的值的集合。

  • 成員都是數組和類似數組的對象,若調用 add() 方法時傳入了非數組和類似數組的對象的參數,就會拋出錯誤。
const b = [1, 2, [1, 2]]
new WeakSet(b) // Uncaught TypeError: Invalid value used in weak set
  • 成員都是弱引用,可以被垃圾回收機制回收,可以用來保存 DOM 節點,不容易造成內存泄漏。
  • WeakSet 不可迭代,因此不能被用在 for-of 等循環中。
  • WeakSet 沒有 size 屬性。

Map

Map 中存儲的是 key-value 形式的鍵值對, 其中的 key 和 value 可以是任何類型的, 即對象也可以作為 key。 Map 的出現,就是讓各種類型的值都可以當作鍵。Map 提供的是 “值-值”的對應。

Map 和 Object 的區別

  1. Object 對象有原型, 也就是說他有默認的 key 值在對象上面, 除非我們使用 Object.create(null)創建一個沒有原型的對象;
  2. 在 Object 對象中, 只能把 String 和 Symbol 作為 key 值, 但是在 Map 中,key 值可以是任何基本類型(String, Number, Boolean, undefined, NaN….),或者對象(Map, Set, Object, Function , Symbol , null….);
  3. 通過 Map 中的 size 屬性, 可以很方便地獲取到 Map 長度, 要獲取 Object 的長度, 你只能手動計算

Map 的屬性

  • size: 返回集合所包含元素的數量
const map = new Map()
map.set('foo', ture)
map.set('bar', false)
map.size // 2

Map 對象的方法

  • set(key, val): 向 Map 中添加新元素
  • get(key): 通過鍵值查找特定的數值並返回
  • has(key): 判斷 Map 對象中是否有 Key 所對應的值,有返回 true,否則返回 false
  • delete(key): 通過鍵值從 Map 中移除對應的數據
  • clear(): 將這個 Map 中的所有元素刪除
const m = new Map()
const o = { p: 'Hello World' }

m.set(o, 'content')
m.get(o) // "content"

m.has(o) // true
m.delete(o) // true
m.has(o) // false

遍歷方法

  • keys():返回鍵名的遍歷器
  • values():返回鍵值的遍歷器
  • entries():返回鍵值對的遍歷器
  • forEach():使用回調函數遍歷每個成員
const map = new Map([
  ['a', 1],
  ['b', 2],
])

for (let key of map.keys()) {
  console.log(key)
}
// "a"
// "b"

for (let value of map.values()) {
  console.log(value)
}
// 1
// 2

for (let item of map.entries()) {
  console.log(item)
}
// ["a", 1]
// ["b", 2]

// 或者
for (let [key, value] of map.entries()) {
  console.log(key, value)
}
// "a" 1
// "b" 2

// for...of...遍歷map等同於使用map.entries()

for (let [key, value] of map) {
  console.log(key, value)
}
// "a" 1
// "b" 2

數據類型轉化

Map 轉為數組

let map = new Map()
let arr = [...map]

數組轉為 Map

Map: map = new Map(arr)

Map 轉為對象

let obj = {}
for (let [k, v] of map) {
  obj[k] = v
}

對象轉為 Map

for( let k of Object.keys(obj)){
  map.set(k,obj[k])
}

Map的應用

在一些 Admin 項目中我們通常都對個人信息進行展示,比如將如下信息展示到頁面上。傳統方法如下。

<div class="info-item">
  <span>姓名</span>
  <span>{{info.name}}</span>
</div>
<div class="info-item">
  <span>年齡</span>
  <span>{{info.age}}</span>
</div>
<div class="info-item">
  <span>性別</span>
  <span>{{info.sex}}</span>
</div>
<div class="info-item">
  <span>手機號</span>
  <span>{{info.phone}}</span>
</div>
<div class="info-item">
  <span>家庭住址</span>
  <span>{{info.address}}</span>
</div>
<div class="info-item">
  <span>家庭住址</span>
  <span>{{info.duty}}</span>
</div>

js 代碼

mounted() {
  this.info = {
    name: 'jack',
    sex: '男',
    age: '28',
    phone: '13888888888',
    address: '廣東省廣州市',
    duty: '總經理'
  }
}

我們通過 Map 來改造,將我們需要显示的 label 和 value 存到我們的 Map 后渲染到頁面,這樣減少了大量的html代碼

<template>
  <div id="app">
    <div class="info-item" v-for="[label, value] in infoMap" :key="value">
      <span>{{label}}</span>
      <span>{{value}}</span>
    </div>
  </div>
</template>

js 代碼

data: () => ({
  info: {},
  infoMap: {}
}),
mounted () {
  this.info = {
    name: 'jack',
    sex: '男',
    age: '28',
    phone: '13888888888',
    address: '廣東省廣州市',
    duty: '總經理'
  }
  const mapKeys = ['姓名', '性別', '年齡', '電話', '家庭地址', '身份']
  const result = new Map()
  let i = 0
  for (const key in this.info) {
    result.set(mapKeys[i], this.info[key])
    i++
  }
  this.infoMap = result
}

WeakMap

WeakMap 結構與 Map 結構類似,也是用於生成鍵值對的集合。

  • 只接受對象作為鍵名(null 除外),不接受其他類型的值作為鍵名
  • 鍵名是弱引用,鍵值可以是任意的,鍵名所指向的對象可以被垃圾回收,此時鍵名是無效的
  • 不能遍歷,方法有 get、set、has、delete

總結

Set

  • 是一種叫做集合的數據結構(ES6新增的)
  • 成員唯一、無序且不重複
  • [value, value],鍵值與鍵名是一致的(或者說只有鍵值,沒有鍵名)
  • 允許儲存任何類型的唯一值,無論是原始值或者是對象引用
  • 可以遍歷,方法有:add、delete、has、clear

WeakSet

  • 成員都是對象
  • 成員都是弱引用,可以被垃圾回收機制回收,可以用來保存 DOM 節點,不容易造成內存泄漏
  • 不能遍歷,方法有 add、delete、has

Map

  • 是一種類似於字典的數據結構,本質上是鍵值對的集合
  • 可以遍歷,可以跟各種數據格式轉換
  • 操作方法有:set、get、has、delete、clear

WeakMap

  • 只接受對象作為鍵名(null 除外),不接受其他類型的值作為鍵名
  • 鍵名是弱引用,鍵值可以是任意的,鍵名所指向的對象可以被垃圾回收,此時鍵名是無效的
  • 不能遍歷,方法有 get、set、has、delete

站長推薦

1.雲服務推薦: 國內主流雲服務商,各類雲產品的最新活動,優惠券領取。地址:阿里雲騰訊雲華為雲

2.廣告聯盟: 整理了目前主流的廣告聯盟平台,如果你有流量,可以作為參考選擇適合你的平台點擊進入

鏈接: http://www.fly63.com/article/detial/9313

沐鳴註冊網站_轉行web前端,需要哪些工具和需要學習什麼?

今天我們來談談Web和前端開發過程中需要學習什麼?前端開發需要使用什麼開發工具?也簡單介紹前端開發前景和薪水。

前端工程師的主要職責:

前端工程師在不同的公司有不同的功能,但性質相似。

1、網站設計與網頁界面開發

2、做網站界面開發

3、Web界面開發,前端數據綁定,前台邏輯

4、設計、開發、數據

web前端開發中需要掌握的技術:

1、學習html,這是最簡單,最基本的是要掌握div,formtable、Ulli、P、跨度、字體這些標籤,這些都是最前端的學習都是需要不斷的學習,學一天停一停相當於白學。

2、學習css,css這裏說的不包括css3 Web前端開發工程師裏面我們看到的,一個可以使用html或css + css+div的界面布局,所以css是用來協助html布局和显示,我們稱之為“css樣式”,為什麼說div+css?因為我說div是html主要用於布局的,所以div是這個東西的核心!css必須配合部。css必須掌握浮、位置、寬度和高度,以及最大值和最小值,以100%,溢出,邊緣、填充等。這些都是與布局相關的樣式。

3、js。你覺得還過的去,看看js是可怕的,事實上,js入門很簡單,不需要很多東西,只要根據ID或名稱DOM或”風格,或價值,然後以一個ID或名稱元標籤,或額外的數據,在html,這是對數據的操作有關係,那麼數據邏輯的影響,無非是一個跳躍,彈框,隱藏什麼,這一切都是結合其他應用,代碼一點都不難,將這些基本的js。百度其他好。然後多看一些,不是什麼問題。

4、學習jQuery,相當於封裝一組js插件的js。其目的是操作更方便,編寫更少的代碼,jQuery條目也非常簡單。這些都是切入點,要學會像js,只是改變了JQ代碼。剩下的就跟百度一樣。

5、最好是指出背景語言,如java,php,為什麼?因為我們是前台接口數據,從後台到點,如果後台代碼,你知道如何與後台數據交互是最好的,它節省了時間,也可以使前端代碼更加規範。否則,可能是因為你回來了,無法忍受的數據,然後前端代碼再次重寫,這將是可怕的。

6、研究CSS3 + html5

以上6點,基本上是一個web前端開發工程師掌握的技術,我也試着講述一下自己的經驗,但是我們不認為上面的6點只是我說的那麼簡單,沒有,他們正在使用,這是在這樣的一個火中,因為堅強!我說的就是這麼簡單,你覺得原因很難祛除,萬事開頭難,我說的是方法和技巧的入門,需要了解的東西。除了告訴你一個秘密,不要以為代碼很難敲,現在什麼語言都有自動提示代碼功能,只需要輸入一個字符,兩個字符,後面的代碼就會彈出,讓你選擇!你害怕什麼?所以不要害怕你糟糕的英語。

web前端開發中需要用到的工具:

有一個ediplus,這是這是一個字體顏色的記事本等,我用這個,因為我覺得DW佔用太多的內存,使電腦卡,所以我用寫ediplus代碼,代碼有沒有自動提示,我不知道,你可以百度是否有插件。Eclipse可以寫java,php和上面的各種代碼!zendstudio是專寫php,但上述2個工具是比較專業的,這是由我們的專業開發人員使用,所以你可以看到,PS圖像處理軟件是沒有必要的。

web前端開發展望:

web前端開發的前景是非常好的。我們不在乎我們做什麼網站或者我們在做什麼項目。現在我們都在關注用戶體驗。人們說,如果你的網站界面看起來不錯,你的網站和項目將成功3/4。所以現在很多人說Web前端的開發前景略好於後端開發。但我做一個比較,前端開發技術的學習上,後端開發技術開發技術還了解到,前、後端開發薪酬肯定是遠遠高於前面,但後面的開發技術在一定程度上會有一個很大的瓶頸,因此早期的中級程序員,前端開發後端開發更好,那麼高級程序員。

前端開發工資薪酬:

這是一個敏感的話題,在上海,0~1年Web前端開發工作經驗的工資是8k ~ 12K,工資取決於你的情況.我們從事這個行業的技術,你的技術有多少薪水,在這條線上的技術無法相比,因為主要還是取決於你的個人技術能力。

站長推薦

1.雲服務推薦: 國內主流雲服務商,各類雲產品的最新活動,優惠券領取。地址:阿里雲騰訊雲華為雲

2.廣告聯盟: 整理了目前主流的廣告聯盟平台,如果你有流量,可以作為參考選擇適合你的平台點擊進入

鏈接: http://www.fly63.com/article/detial/9311

沐鳴娛樂怎麼樣?_原生JS利用transform實現banner的無限滾動

功能

  • 默認情況無限循環向右移動
  • 點擊数字切換到對應圖片
  • 點擊左右切換可切換圖片

原理

首先說下原理。

  1. 在布局上所有的圖片都是重疊的,即只要保證Y方向對齊即可,當前可見的圖z-index層級最高。
  2. 每隔3s中更換一張圖片,使用setTimeout定時。
  3. 使用gIndex記錄當前可視區域的展示的是哪張圖片下標,每次更換,計算下一張圖片的下標。
  4. 通過requestAnimationFrame實現一次圖片切換的動畫。

這種方法也可以做到整個頁面始終只有2個img標籤,而不必把所有的img節點全部創建出來,要點是每次更換不可見img的src。

動畫的實現

  1. 首先定義一個timestap,這個值記錄每個幀移動多少距離。定義初始step=0,記錄移動的步數。
  2. 每次移動的距離moveWidth是timestamp*step,圖片1向右移動增加moveWidth,圖片2從左側進入moveWidth。因此,圖片1的transform是translate(moveWidth), 而圖片2的transform則是translate(moveWidth-圖片寬度)。
  3. step+1
  4. 如果moveWidth>圖片寬度,步驟5,否則requestAnimationFrame請求下一次執行,繼續2-4.
  5. 圖片1和2都將位置放置在起始位置,圖片2的z-index設置為最高。

這樣就完成了一次移動的動畫。

html代碼

<header>
    <div class="box">
        <img src="imgs/banner1.jpg">
        <img src="imgs/banner2.jpg">
        <img src="imgs/banner3.jpg">
        <img src="imgs/banner4.jpg">
    </div>
    <div class="buttons">
        <div class="active">1</div>
        <div>2</div>
        <div>3</div>
        <div>4</div>
    </div>
    <div class="left">
        <div class="arrow"></div>
    </div>
    <div class="right">
        <div class="arrow"></div>
    </div>
</header>

js代碼

var timeout = null;
window.onload = function () {
    var oLeft = document.querySelector('.left');
    var oRight = document.querySelector('.right');
    var oButton = document.querySelector('.buttons');
    var oButtons = document.querySelectorAll('.buttons div');
    var oImgs = document.querySelectorAll('.box img');
    var imgWidth = oImgs[0].width;
    var gIndex = 0;
    begainAnimate();

    // 綁定左右點擊事件
    oLeft.onclick = function () {
        clearTimeout(timeout);
        leftMove();
        begainAnimate();
    };
    oRight.onclick = function () {
        clearTimeout(timeout);
        rightMove();
        begainAnimate();
    };
    // 綁定数字序號事件
    oButton.onclick = function (event) {
        clearTimeout(timeout);
        var targetEl = event.target;
        var nextIndex = (+targetEl.innerText) - 1;
        console.log(nextIndex);
        rightMove(nextIndex);
        begainAnimate();
    }
    // 默認初始動畫朝右邊
    function begainAnimate() {
        clearTimeout(timeout);
        timeout = setTimeout(function () {
            rightMove();
            begainAnimate();
        }, 3000);
    }
    // 向左移動動畫
    function leftMove() {
        var nextIndex = (gIndex - 1 < 0) ? oImgs.length - 1 : gIndex - 1;
        animateSteps(nextIndex, -50);
    }
    // 向右移動動畫
    function rightMove(nextIndex) {
        if (nextIndex == undefined) {
            nextIndex = (gIndex + 1 >= oImgs.length) ? 0 : gIndex + 1;
        }
        animateSteps(nextIndex, 50);
    }
    // 一次動畫
    function animateSteps(nextIndex, timestamp) {
        var currentImg = oImgs[gIndex];
        var nextImg = oImgs[nextIndex];
        nextImg.style.zIndex = 10;
        var step = 0;
        requestAnimationFrame(goStep);
        // 走一幀的動畫,移動timestamp
        function goStep() {
            var moveWidth = timestamp * step++;
            if (Math.abs(moveWidth) < imgWidth) {
                currentImg.style.transform = `translate(${moveWidth}px)`;
                nextImg.style.transform = `translate(${moveWidth > 0 ? (moveWidth - imgWidth) : (imgWidth + moveWidth)}px)`;
                requestAnimationFrame(goStep);
            } else {
                currentImg.style.zIndex = 1;
                currentImg.style.transform = `translate(0px)`;
                nextImg.style.transform = `translate(0px)`;
                oButtons[gIndex].setAttribute('class', '');
                oButtons[nextIndex].setAttribute('class', 'active');
                gIndex = nextIndex;
            }
        }
    }
}
window.onclose = function () {
    clearTimeout(timeout);
}

css布局樣式


<style>
    /* 首先設置圖片box的區域,將圖片重疊在一起  */
    header {
        width: 100%;
        position: relative;
        overflow: hidden;
    }
    .box {
        width: 100%;
        height: 300px;
    }
    .box img {
        width: 100%;
        height: 100%;
        position: absolute;
        transform: translateX(0);
        z-index: 1;
    }
    .box img:first-child {
        z-index: 10;
    }
    
    /* 数字序列按鈕 */
    .buttons {
        position: absolute;
        right: 10%;
        bottom: 5%;
        display: flex;
        z-index: 100;
    }

    .buttons div {
        width: 30px;
        height: 30px;
        background-color: #aaa;
        border: 1px solid #aaa;
        text-align: center;
        margin: 10px;
        cursor: pointer;
        opacity: .7;
        border-radius: 15px;
        line-height: 30px;
    }

    .buttons div.active {
        background-color: white;
    }

    /* 左右切換按鈕 */
    .left,
    .right {
        position: absolute;
        width: 80px;
        height: 80px;
        background-color: #ccc;
        z-index: 100;
        top: 110px;
        border-radius: 40px;
        opacity: .5;
        cursor: pointer;
    }

    .left {
        left: 2%;
    }

    .right {
        right: 2%;
    }

    .left .arrow {
        width: 30px;
        height: 30px;
        border-left: solid 5px #666;
        border-top: solid 5px #666;
        transform: translate(-5px, 25px) rotate(-45deg) translate(25px, 25px);
    }

    .right .arrow {
        width: 30px;
        height: 30px;
        border-left: solid 5px #666;
        border-top: solid 5px #666;
        transform: translate(50px, 25px) rotate(135deg) translate(25px, 25px);
    }
</style>

來自:https://segmentfault.com/a/1190000022929832

站長推薦

1.雲服務推薦: 國內主流雲服務商,各類雲產品的最新活動,優惠券領取。地址:阿里雲騰訊雲華為雲

2.廣告聯盟: 整理了目前主流的廣告聯盟平台,如果你有流量,可以作為參考選擇適合你的平台點擊進入

鏈接: http://www.fly63.com/article/detial/9307

沐鳴登錄_客戶端與服務端長連接的幾種方式

一、ajax 輪詢

實現原理:ajax 輪詢指客戶端每間隔一段時間向服務端發起請求,保持數據的同步。

優點:可實現基礎(指間隔時間較短)的數據更新。

缺點:這種方法也只是盡量的模擬即時傳輸,但並非真正意義上的即時通訊,很有可能出現客戶端請求時,服務端數據並未更新。或者服務端數據已更新,但客戶端未發起請求。導致多次請求資源浪費,效率低下。

二、long poll 長輪詢

實現原理:

long poll 指的是客戶端發送請求之後,如果沒有數據返回,服務端會將請求掛起放入隊列(不斷開連接)處理其他請求,直到有數據返回給客戶端。然後客戶端再次發起請求,以此輪詢。在 HTTP1.0 中客戶端可以設置請求頭 Connection:keep-alive,服務端收到該請求頭之後知道這是一個長連接,在響應報文頭中也添加 Connection:keep-alive。客戶端收到之後表示長連接建立完成,可以繼續發送其他的請求。在 HTTP1.1 中默認使用了 Connection:keep-alive 長連接。

優點:減少客戶端的請求,降低無效的網絡傳輸,保證每次請求都有數據返回,不會一直佔用線程。

缺點:無法處理高併發,當客戶端請求量大,請求頻繁時對服務器的處理能力要求較高。服務器一直保持連接會消耗資源,需要同時維護多個線程,服務器所能承載的 TCP 連接數是有上限的,這種輪詢很容易把連接數頂滿。每次通訊都需要客戶端發起,服務端不能主動推送。

三、iframe 長連接

實現原理:
在網頁上嵌入一個 iframe 標籤,該標籤的 src 屬性指向一個長連接請求。這樣服務端就可以源源不斷地給客戶端傳輸信息。保障信息實時更新。

優點:消息及時傳輸。

缺點:消耗服務器資源。

四、WebSocket

實現原理:

Websocket 實現了客戶端與服務端的雙向通信,只需要連接一次,就可以相互傳輸數據,很適合實時通訊、數據實時更新等場景。

Websocket 協議與 HTTP 協議沒有關係,它是一個建立在 TCP 協議上的全新協議,為了兼容 HTTP 握手規範,在握手階段依然使用 HTTP 協議,握手完成之後,數據通過 TCP 通道進行傳輸。

Websoket 數據傳輸是通過 frame 形式,一個消息可以分成幾個片段傳輸。這樣大數據可以分成一些小片段進行傳輸,不用考慮由於數據量大導致標誌位不夠的情況。也可以邊生成數據邊傳遞消息,提高傳輸效率。

與 HTTP 的區別:
以下是一個 WebSoket 協議的請求響應報文頭,與 HTTP 協議的區別是:

URL是以 ws: 開頭,如果是對應的 HTTPS,則以 wss: 開頭。WebSocket 使用 ws 或 wss 為統一資源標誌符,其中 wss 表示在 TLS 之上的 Websocket。

Status Code:101。該狀態碼錶示協議切換。服務器返回了 101 ,表示沒有釋放 TCP 連接。WebSoket 協議握手階段還是依賴於 HTTP 協議,到數據傳輸階段便切換協議。

Conection:upgrade,表示協議升級。在 HTTP 協議中,該請求頭有兩個值,一個是 close , HTTP/1.0 默認值,表示客戶端或服務端想要關閉連接。另一個是 keep-alive,HTTP/1.1 默認值,表示長連接。

以下頭部字段是只有 WebSocket 協議才有的字段。
請求頭:
Sec-WebSocket-Extension:表示客戶端協商的拓展特性。
Sec-WebSocket-Key:是一個 Base64 encode 的密文,由瀏覽器隨機生成,用來驗證是否是 WebSocket 協議。
Sec-WebSocket-Version:表示 WebSocket 協議版本。

響應頭:
Sec-WebSocket-Extension:表示服務端支持的拓展特性。
Sec-WebSocket-Accept:與客戶端的 Sec-WebSocket-Key 相對應,是經過服務器確認,加密過後的 Sec-WebSocket-Key。

優點:

雙向通信。客戶端和服務端雙方都可以主動發起通訊。
沒有同源限制。客戶端可以與任意服務端通信,不存在跨域問題。
數據量輕。第一次連接時需要攜帶請求頭,後面數據通信都不需要帶請求頭,減少了請求頭的負荷。
傳輸效率高。因為只需要一次連接,所以數據傳輸效率高。
缺點:

長連接需要後端處理業務的代碼更穩定,推送消息相對複雜;
長連接受網絡限制比較大,需要處理好重連。
兼容性,WebSocket 只支持 IE10 及其以上版本。
服務器長期維護長連接需要一定的成本,各個瀏覽器支持程度不一;
成熟的 HTTP 生態下有大量的組件可以復用,WebSocket 則沒有,遇到異常問題難以快速定位快速解決。

站長推薦

1.雲服務推薦: 國內主流雲服務商,各類雲產品的最新活動,優惠券領取。地址:阿里雲騰訊雲華為雲

2.廣告聯盟: 整理了目前主流的廣告聯盟平台,如果你有流量,可以作為參考選擇適合你的平台點擊進入

鏈接: http://www.fly63.com/article/detial/9074

沐鳴登錄_有了 Promise 和 then,為什麼還要使用 async?

最近代碼寫着寫着,我突然意識到一個問題——我們既然已經有了 Promise 和 then,為啥還需要 async 和 await?這不是脫褲子放屁嗎?

比如說我們需要一段請求服務器的代碼:

new Promise((resolve, reject) => {
  setTimeout(() => {
    const res = '明月幾時有'
    if (1 > 2) {
      resolve(res)
    } else {
      reject('我不知道,把酒問青天吧')
    }
  }, 1500)
}).then(
  (res) => {
    console.log(`成功啦!結果是${res}`)
  },
  (err) => {
    console.log(`失敗了。。。錯誤是${err}`)
  }
)

這段代碼,簡潔漂亮,但是如果用上了 async 和 await,就需要寫成下面這樣:

function ask() {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      const res = '明月幾時有'
      if (1 > 2) {
        resolve(res)
      } else {
        reject('我不知道,把酒問青天吧')
      }
    }, 1500)
  })
}

async function test() {
  try {
    const res = await ask()
  } catch (err) {
    console.log(err)
  }
}

test()

竟然還需要一個 try catch 來捕捉錯誤!越寫越像 Java 呀。

MDN 給我們了一些解釋:

如果你在代碼中使用了異步函數,就會發現它的語法和結構會更像是標準的同步函數。

說白了,這種寫法的一部分原因,就是為了“討好” Java 和其他的一些程序員。

另一方面呢,也是增強可讀性,雖然說 async await 的寫法比較丑,但是毫無疑問,可讀性遠遠高於 Promise then。

最為重要的呢,是 Promise 可以無限嵌套,而 async await 只能處理一個 Promise,無法繼續嵌套。

所以一旦需要使用多次連續回調,async await 就乏力了。

其實也可以,通過 await 一個Promise.all()來實現。

作者:幾乎一米八的徐某某

出處:Aero Blog (https://www.cnblogs.com/xhyccc/)


站長推薦

1.雲服務推薦: 國內主流雲服務商,各類雲產品的最新活動,優惠券領取。地址:阿里雲騰訊雲華為雲

2.廣告聯盟: 整理了目前主流的廣告聯盟平台,如果你有流量,可以作為參考選擇適合你的平台點擊進入

鏈接: http://www.fly63.com/article/detial/9049

沐鳴開戶_學會享受孤獨是通往成功的第一步

我們生活在一個社交異常活躍的世界,在這個世界里,人們漸漸地忽視獨處的重要性。辦公室的設計都正在拋棄以往的那種小隔板間,而採用那種開放的辦公區域;學校的學生也不再坐在自己獨立擁有的桌椅前,而是成組地呆在一起。持續不斷的消息提示音是我們現代文明裡的噪音,不斷地提醒我們每一條短信、每一條微博和每一條各種通知。即使是平淡無奇的燒菜做飯,人們也樂於在朋友圈裡發圖分享。

所有這些社交活動有一個直接的後果就是,我們基本不再擁有獨處的時間。是的,人們都在說,融入社交圈是好事,與其他人交往可以豐富我們的生活,但是任何好的事情都應該有個度,不是嗎?

人類所有的不幸都來源於害怕和厭惡孤獨。

–拉布呂耶爾(Jean de la Bruyere)

一項涉及92個公司總共600名程序員的調查表明,每個公司內部的效率水平大致是穩定的,但是不同的公司效率卻有高有低。效率較高的公司在這一點上是一致的:他們都不使用時尚的開放辦公區,而使用能免於被打擾的私人辦公區。效率最高的公司中,有62%聲稱自己在工作時擁有足夠的個人空間,而反過來,效率比較低的公司中只有19%的人持相同觀點。並且,在最低效的那些公司中,有76%的人說自己經常被人打擾,以致工作中斷。

能夠享受孤獨並不僅僅可以帶來工作質量的提升,對於維護精神和心情的良好狀態也是有用的。為了讓生活更加充實,你必須學會享受獨處的時光。孤獨可以帶來太多太多的好處,這裏舉一些最明顯的:

1、有助恢復精力

我們任何人都需要時間去恢復精力,即使是那些無可救藥的性格外向的人也是一樣。除了靜靜一個人獃著,沒有其他辦法有這種效果。當你自己獨處的時候,通過慢慢品嘗精神上的安靜和孤獨可以幫你從一天的壓力中獲得解脫。

2、可以做任何你想做的事情

和其他人呆在一起是很有趣,但是同時,我們也更傾向於隱藏真實的自我。你總是需要不斷地調整自己的想法,以此來適應其他人的喜好。但是當你自己獨處的時候,你可以做你自己真正想做的事情。你可以毫不猶豫穿上自己愛穿的衣服,吃想吃的東西,把時間花在自己認為值得的事情上。

3、學會相信自己

自由並不僅僅是做自己想做的事情,更是相信自己的直覺、了解自己直覺的能力,並且不考慮任何外界的影響或者壓力。獨處可以幫助你對自己建立一個更真實的了解,教會你相信自己:了解自己是誰,自己知道些什麼,什麼樣的事情是適合自己的。當和其他人在一起的時候,你總是不斷地去觀察其他人的反應,並且以此來調整自己的感想和行為,更好地融入大家。有時,甚至你自己也對此沒有察覺。當你自己獨處的時候,這一切都由你來做主。你可以培養自己的思想和喜好,並且不用擔心被別人左右。一旦你習慣於享受孤獨,那麼你就會發現自己真正有能力做到什麼,不再在意別人對你的限定。

4、提高自己的情商

情商是指發現並且理解自己和他人的心情的能力,並且憑藉這種了解來指導自己的行動、與他人建立適當的聯繫。TalentSmart公司曾經對100萬人做過一次調查,發現90%最優秀的人的情商都非常高。學會了解自我是具備高情商的必備基礎,如果做不到了解自我,那麼情商不可能提高。因為了解自我需要理解自己的情緒以及如何來應對不同的人和處境,這就需要你能夠多多反思,而在自己獨處的時候可以更好地反思。

5、可以提升自信

學會享受獨處可以極大地提升自信。當你獨處的時候如果發生煩躁不安的情緒,那麼這時你會很容易地去考慮自己為什麼在煩躁,或者是因為有別人在場所以才強言歡笑。學會享受獨處可以足夠地了解自己,因此提升自信。

6、可以更會欣賞別人

獨處讓人的心變得更柔軟。讓你更容易用全新的眼光去看待他人,幫助你培養感恩的情懷,對他人他事也有了更好的認識。

7、提升效率

俗話說人多力量大,這話如果對於掃樹恭弘=叶 恭弘的活兒可能是真的,但是對於創造性的工作來說,可完全不是這麼回事。即使對於頭腦風暴這樣的會議,所帶來的效果也經常是願望大於現實。德克薩斯州工農大學(Texas A&M)的研究人員發現,頭腦風暴會因為“認知固化”的原因而阻礙提高生產率。認知固化指的是人們一起工作的時候經常被別人的想法所牽絆,以致於沒法想出真正創新的點子。並且越多的人一起參与,這種固化的壞處越明顯。讓自己靜靜一個人工作不僅可以減少不必要的紛擾,也不會因為“廚子太多”而陷入麻煩。

總結一下:

獨處對每個人都大有裨益,趁着周末讓自己一個人獃獃吧。

附記:通過獨處自己有了什麼樣的收穫呢?請把您的心得通過評論區分享給我吧,因為我通過你也能學到我所不了解的。

作者:Travis Bradberry博士與人合著了暢銷書《情商2.0》,創辦的TalentSmart公司,是世界領先的提供情商培訓和測試的服務機構,客戶涵蓋世界500強中的75%。他的書被翻譯成25種語言在超過150個國家發售。博士為《新聞周刊》、《泰晤士報》、《時代周刊》、《商業周刊》、《財富》、《福布斯》等媒體撰寫文章或者被選為封面人物。

站長推薦

1.雲服務推薦: 國內主流雲服務商,各類雲產品的最新活動,優惠券領取。地址:阿里雲騰訊雲華為雲

2.廣告聯盟: 整理了目前主流的廣告聯盟平台,如果你有流量,可以作為參考選擇適合你的平台點擊進入

鏈接: http://www.fly63.com/article/detial/9593

沐鳴平台_你真的懂遞歸嗎?

因為很多算法思想都基於遞歸,無論是DFS、樹的遍歷、分治算法、動態規劃等都是遞歸思想的應用。學會了用遞歸來解決問題的這種思維方式,再去學習其他的算法思想,無疑是事半功倍的。

遞歸的本質

無可奈何花落去,似曾相識燕歸來。

遞歸,去的過程叫“遞” ,回來的過程叫“歸”。

探究遞歸的本質要從計算機語言的本質說起。

計算機語言的本質是彙編語言,彙編語言的特點就是沒有循環嵌套。
我們平時使用高級語言來寫的 if..else.. 也好, for/while 也好,在實際的機器指令層面來看,就是一個簡單的地址跳轉,跳轉到特定的指令位置,類似於 goto 語句。

機器嘛,總是沒有溫度的。我們再來看一個生活中的例子,大家小的時候一定用新華字典查過字。如果要查的字的解釋中,也有不認識的字。那就要接着查第二個字,不幸第二個字的解釋中,也有不認識的字,就要接着查第三個字。直到有一個字的解釋我們完全可以看懂,那麼遞歸就到了盡頭。接下來我們開始後退,逐個清楚了之前查過的每一個字,最終,我們明白了我們要查的第一個字。

我們再從一段代碼中,體會一下遞歸。

const factorial = function(n) {
    if (n <= 1) {
        return 1;
    }
    return n * factorial(n - 1);
}

factorial 是一個實現階乘的函數。我們以階乘 f(6) 來看下它的遞歸。

f(6) = n * f(5),所以 f(6) 需要拆解成 f(5) 子問題進行求解,以此類推 f(5) = n * f(4) ,也需要進一步拆分 … 直到 f(1),這是遞的過程。 f(1) 解決后,依次可以解決f(2)…. f(n)最後也被解決,這是歸的過程。

從上面兩個例子可以看出,遞歸無非就是把問題拆解成具有相同解決思路的子問題,直到最後被拆解的子問題不能夠拆分,這個過程是“遞”。當解決了最小粒度可求解的子問題后,在“歸”的過程中順其自然的解決了最開始的問題。

搞清楚了遞歸的本質,在利用遞歸思想解題之前,我們還要記住滿足遞歸的三個條件:

1.問題可以被分解成幾個子問題

2.問題和子問題的求解方法完全相同

3.遞歸終止條件

敲黑板,記筆記!


LeetCode 真題

我們拿一道 LeetCode 真題練練手。

求解斐波那契數列,該數列由 0 和 1 開始,後面的每一項数字都是前面兩項数字的和,也就是:

F(0) = 0,   F(1) = 1
F(N) = F(N - 1) + F(N - 2), 其中 N > 1.

給定 N,計算 F(N)。

遞歸樹如上圖所示,要計算 f(5),就要先計算子問題 f(4) 和 f(3),要計算 f(4),就要先計算齣子問題 f(3)和 f(2)…
以此類推,當最後計算到 f(0) 或者 f(1) 的時候,結果已知,然後層層返回結果。

經過如上分析可知,滿足遞歸的三個條件,開始擼代碼。

遞歸解法

const fib = function(n) {
    if (n == 0 || n == 1) {
        return n;
    }
    return fib(n - 1) + fib(n - 2);
}

或者可以這樣炫技:

const fib = n => n <= 0 ? 0 : n == 1 ? 1: fib(n - 2) + fib(n - 1);

還沒完事,記住要養成習慣,一定要對自己寫出的算法進行複雜度分析。這部分在專欄JavaScript算法時間、空間複雜度分析已經講解過,沒看過的同學請點擊鏈接移步。

複雜度分析

  • 空間複雜度為 O(n)
  • 時間複雜度 O(2^n)

總時間 = 子問題個數 * 解決一個子問題需要的時間

  • 子問題個數即遞歸樹中的節點總數 2^n
  • 解決一個子問題需要的時間,因為只有一個加法操作 fib(n-1) + fib(n-2) ,所以解決一個子問題的時間為 O(1)

二者相乘,得出算法的時間複雜度為 O(2^n),指數級別,裂開了呀。

面試的時候如果只寫這樣一種解法就 GG 了。

其實這道題我們可以利用動態規劃或是黃金分割比通項公式來求解,動態規劃想要講清楚的話篇幅較長,後續開個專欄會詳細介紹,這裏看不懂的同學們不要着急。

(選擇這道題的初衷是為了讓大家理解遞歸。)

動態規劃解法

遞歸是自頂向下(看上文遞歸樹),動態規劃是自底向上,將遞歸改成迭代。為了減少空間消耗,只存儲兩個值,這種解法是動態規劃的最優解。

  • 時間複雜度 O(n)
  • 空間複雜度 O(1)
const fib = function(n) {
    if (n == 0) {
        return 0;
    }
    let a1 = 0;
    let a2 = 1;
    for (let i = 1; i < n; i++) {
        [a1, a2] = [a2, a1 + a2];
    }
    return a2;
}

黃金分割比通項公式解法

  • 時間複雜度 O(logn)
  • 空間複雜度 O(1)
const fib = function(n) {
    return (Math.pow((1 + Math.sqrt(5))/2, n) - Math.pow((1 - Math.sqrt(5))/2, n)) / Math.sqrt(5);
}

除此之外,還可以利用矩陣方程來解題,這裏不再展開。

回到遞歸,在學習遞歸的過程中,最大的陷阱就是人肉遞歸。人腦是很難把整個“遞”“歸”過程毫無差錯的想清楚的。但是計算機恰好擅長做重複的事情,那我們便無須跳入細節,利用數學歸納法的思想,將其抽象成一個遞推公式。相信它可以完成這個任務,其他的交給計算機就好了。

如果你非要探究裏面的細節,挑戰人腦壓棧,那麼你只可能會陷入其中,甚至懷疑人生。南牆不好撞,該回頭就回頭。

你凝望深淵的時候,深淵也在凝望你。

原文:https://segmentfault.com/a/1190000022677431

站長推薦

1.雲服務推薦: 國內主流雲服務商,各類雲產品的最新活動,優惠券領取。地址:阿里雲騰訊雲華為雲

2.廣告聯盟: 整理了目前主流的廣告聯盟平台,如果你有流量,可以作為參考選擇適合你的平台點擊進入

鏈接: http://www.fly63.com/article/detial/9061

沐鳴測速登錄地址_在JavaScript 中 14 個拷貝數組的技巧

數組拷貝經常被誤解,但這並不是因為拷貝過程本身,而是因為缺乏對 js 如何處理數組及其元素的理解。js 中的數組是可變的,這說明在創建數組之後還可以修改數組的內容。

這意味着要拷貝一個數組,咱們不能簡單地將舊數組分配給一個新變量,它也是一個數組。如果這樣做,它們將共享相同的引用,並且在更改一個變量之後,另一個變量也將受到更改的影響。這就是我們需要克隆這個數組的原因。

接着來看看一些關於拷貝何克隆數組的有趣方法和技巧。

技巧 1 – 使用Array.slice方法

const numbers = [1, 2, 3, 4, 5]

const copy = numbers.slice()
copy.push(6) // 添加新項以證明不會修改原始數組

console.log(copy)
console.log(numbers)

// 輸出
// [1, 2, 3, 4, 5, 6]
// [1, 2, 3, 4, 5]

技巧 2 – 使用Array.map方法

const numbers = [1, 2, 3, 4, 5]

const copy = numbers.map( num => num )
copy.push(6) // 添加新項以證明不會修改原始數組

console.log(copy);
console.log(numbers);

// 輸出
// [1, 2, 3, 4, 5, 6]
// [1, 2, 3, 4, 5]

技巧 3 – 使用Array.from 方法

const numbers = [1, 2, 3, 4, 5];

const copy = Array.from(new Set(numbers));
copy.push(6); // 添加新項以證明不會修改原始數組

console.log(copy);
console.log(numbers);

// 輸出
// [1, 2, 3, 4, 5, 6]
// [1, 2, 3, 4, 5]

技巧 4 – 使用展開操作符

const numbers = [1, 2, 3, 4, 5];

const copy = [...numbers];
copy.push(6); // 添加新項以證明不會修改原始數組

console.log(copy);
console.log(numbers);

// 輸出 
// [1, 2, 3, 4, 5, 6]
// [1, 2, 3, 4, 5]

技巧 5 – 使用 Array.of 方法和展開操作符

const numbers = [1, 2, 3, 4, 5];

const copy = Array.of(...numbers);
copy.push(6); // 添加新項以證明不會修改原始數組

console.log(copy);
console.log(numbers);

// 輸出 
// [1, 2, 3, 4, 5, 6]
// [1, 2, 3, 4, 5]

Array.of() 方法創建一個具有可變數量參數的新數組實例,而不考慮參數的數量或類型。Array.of() 和 Array 構造函數之間的區別在於處理整數參數:Array.of(7) 創建一個具有單個元素 7 的數組,而 Array(7) 創建一個長度為7的空數組(注意:這是指一個有7個空位(empty)的數組,而不是由7個undefined組成的數組)。

Array.of(7);       // [7] 
Array.of(1, 2, 3); // [1, 2, 3]

Array(7);          // [ , , , , , , ]
Array(1, 2, 3);    // [1, 2, 3]

技巧 6 – 使用 Array 構造函數和展開操作符

const numbers = [1, 2, 3, 4, 5];

const copy = new Array(...numbers);
copy.push(6); // 添加新項以證明不會修改原始數組

console.log(copy);
console.log(numbers);

// 輸出 
// [1, 2, 3, 4, 5, 6]
// [1, 2, 3, 4, 5]

技巧 7 – 使用解構

const numbers = [1, 2, 3, 4, 5];

const [...copy] = numbers;
copy.push(6); // 添加新項以證明不會修改原始數組

console.log(copy);
console.log(numbers);

// 輸出
// [1, 2, 3, 4, 5, 6]
// [1, 2, 3, 4, 5]

技巧 8 – 使用 Array.concat 方法

const numbers = [1, 2, 3, 4, 5];

const copy = numbers.concat();
copy.push(6); // 添加新項以證明不會修改原始數組

console.log(copy);
console.log(numbers);

// 輸出
// [1, 2, 3, 4, 5, 6]
// [1, 2, 3, 4, 5]

技巧 9 – 使用 Array.push 方法和展開操作符

const numbers = [1, 2, 3, 4, 5];

let copy = [];
copy.push(...numbers);
copy.push(6); // 添加新項以證明不會修改原始數組

console.log(copy);
console.log(numbers);

// 輸出
// [1, 2, 3, 4, 5, 6]
// [1, 2, 3, 4, 5]

技巧 10 – 使用 Array.unshift 方法和展開操作符

const numbers = [1, 2, 3, 4, 5];

let copy = [];
copy.unshift(...numbers);
copy.push(6); // 添加新項以證明不會修改原始數組

console.log(copy);
console.log(numbers);

// 輸出
// [1, 2, 3, 4, 5, 6]
// [1, 2, 3, 4, 5]

技巧 11 – 使用 Array.forEach 方法和展開操作符

const numbers = [1, 2, 3, 4, 5];

let copy = [];
numbers.forEach((value) => copy.push(value));
copy.push(6); // 添加新項以證明不會修改原始數組

console.log(copy);
console.log(numbers);

// 輸出
// [1, 2, 3, 4, 5, 6]
// [1, 2, 3, 4, 5]

技巧 12 – 使用 for 循環

const numbers = [1, 2, 3, 4, 5];

let copy = [];
for (let i = 0; i < numbers.length; i++) {
    copy.push(numbers[i]);
}
copy.push(6); // 添加新項以證明不會修改原始數組

console.log(copy);
console.log(numbers);

// 輸出
// [1, 2, 3, 4, 5, 6]
// [1, 2, 3, 4, 5]

技巧 13 – 使用 Array.reduce 方法

這個做法是可行,但比較多餘,少用

const numbers = [1, 2, 3, 4, 5];

const copy = numbers.reduce((acc, x) => { acc.push(x); return acc; }, []);
copy.push(6); // 添加新項以證明不會修改原始數組

console.log(copy);
console.log(numbers);

// 輸出
// [1, 2, 3, 4, 5, 6]
// [1, 2, 3, 4, 5]

技巧 14 – 使用古老的 apply 方法

const numbers = [1, 2, 3, 4, 5];

let copy = [];
Array.prototype.push.apply(copy, numbers);
copy.push(6); // 添加新項以證明不會修改原始數組

console.log(copy);
console.log(numbers);

// 輸出
// [1, 2, 3, 4, 5, 6]
// [1, 2, 3, 4, 5]

總結

請注意,上面這些方法執行的是淺拷貝,就是數組是元素是對象的時候,咱們更改對象的值,另一個也會跟着變,就能技巧4來說,如果咱們的數組元素是對象,如下所示:

const authors = [
  { name: '前端小智', age: 25 }, 
  { name: '王大冶', age: 30 }, 
]

const copy = [...authors ]
copy[0].name = '被更改過的前端小智'

console.log(copy)
console.log(authors)

所以上面的技巧適合簡單的數據結構,複雜的結構要使用深拷貝。數組拷貝經常被誤解,但這並不是因為拷貝過程本身,而是因為缺乏對 js 如何處理數組及其元素的理解。

原文:https://medium.com/

來源:twitter

譯者:前端小智  

站長推薦

1.雲服務推薦: 國內主流雲服務商,各類雲產品的最新活動,優惠券領取。地址:阿里雲騰訊雲華為雲

2.廣告聯盟: 整理了目前主流的廣告聯盟平台,如果你有流量,可以作為參考選擇適合你的平台點擊進入

鏈接: http://www.fly63.com/article/detial/9057

沐鳴平台註冊登錄_JSON和HTML之間互轉實現

主要實現功能html轉json,再由json恢復html

可去除 style 和 script 標籤

將行內樣式轉換為 js object

將 class 轉換為數組形式

主要依賴於 htmlparser2 ; 這是一個性能優越、功能強大的 html 解析庫

直接上代碼

import { Parser } from "htmlparser2"

const numberValueRegexp = /^\d+$/
const zeroValueRegexp = /^0[^0\s].*$/
const scriptRegexp = /^script$/i
const styleRegexp = /^style$/i
const selfCloseTagRegexp = /^(meta|base|br|img|input|col|frame|link|area|param|embed|keygen|source)$/i

const TAG = 'tag'
const TEXT = 'text'
const COMMENT = 'comment'

/**
 * 去除前後空格
 */
export const trim = val => {
    return (val || '').replace(/^\s+/, '').replace(/\s+$/, '')
}
/**
 * 首字母大寫
 */
export const capitalize = word => {
    return (word || '').replace(/( |^)[a-z]/, c => c.toUpperCase())
}
/**
 * 駝峰命名法/小駝峰命名法, 首字母小寫
 */
export const camelCase = key => {
    return (key || '').split(/[_-]/).map((item, i) => i === 0 ? item : capitalize(item)).join('')
}
/**
 * 大駝峰命名法,首字母大寫
 */
export const pascalCase = key => {
    return (key || '').split(/[_-]/).map(capitalize).join('')
}
export const isPlainObject = obj => {
    return Object.prototype.toString.call(obj) === '[object Object]'
}
/**
 * 行內樣式轉Object
 */
export const style2Object = (style) => {
    if (!style || typeof style !== 'string') {
        return {}
    }
    const styleObject = {}
    const styles = style.split(/;/)
    styles.forEach(item => {
        const [prop, value] = item.split(/:/)
        if (prop && value && trim(value)) {
            const val = trim(value)
            styleObject[camelCase(trim(prop))] = zeroValueRegexp.test(val) ? 0 : numberValueRegexp.test(val) ? Number(val) : val
        }
    })
    return styleObject
}

export const tojsON = (html, options) => {
    options = Object.assign({ skipStyle: false, skipScript: false, pureClass: false, pureComment: false }, options)
    const json = []
    let levelNodes = []
    const parser = new Parser({
        onopentag: (name, { style, class: classNames, ...attrs } = {}) => {
            let node = {}
            if ((scriptRegexp.test(name) && options.skipScript === true) ||
                (styleRegexp.test(name) && options.skipStyle === true)) {
                node = false
            } else {
                if (options.pureClass === true) {
                    classNames = ''
                }
                node = {
                    type: TAG,
                    tagName: name,
                    style: style2Object(style),
                    inlineStyle: style || '',
                    attrs: { ...attrs },
                    classNames: classNames || '',
                    classList: options.pureClass ? [] : (classNames || '').split(/\s+/).map(trim).filter(Boolean),
                    children: []

                }
            }
            if (levelNodes[0]) {
                if (node !== false) {
                    const parent = levelNodes[0]
                    parent.children.push(node)
                }
                levelNodes.unshift(node)
            } else {
                if (node !== false) {
                    json.push(node)
                }
                levelNodes.push(node)
            }
        },
        ontext(text) {
            const parent = levelNodes[0]
            if (parent === false) {
                return
            }
            const node = {
                type: TEXT,
                content: text
            }
            if (!parent) {
                json.push(node)
            } else {
                if (!parent.children) {
                    parent.children = []
                }
                parent.children.push(node)
            }
        },
        oncomment(comments) {
            if (options.pureComment) {
                return
            }
            const parent = levelNodes[0]
            if (parent === false) {
                return
            }
            const node = {
                type: COMMENT,
                content: comments
            }
            if (!parent) {
                json.push(node)
            } else {
                if (!parent.children) {
                    parent.children = []
                }
                parent.children.push(node)
            }
        },
        onclosetag() {
            levelNodes.shift()
        },
        onend() {
            levelNodes = null
        }
    })
    parser.done(html)
    return json
}
const setAttrs = (attrs, results) => {
    Object.keys(attrs || {}).forEach(k => {
        if (!attrs[k]) {
            results.push(k)
        } else {
            results.push(' ', k, '=', '"', attrs[k], '"')
        }
    })
}
const toElement = (elementInfo, results) => {

    switch (elementInfo.type) {
        case TAG:
            const tagName = elementInfo.tagName
            results.push('<', tagName)
            if (elementInfo.inlineStyle) {
                results.push(', elementInfo.inlineStyle, '"')
            }
            if (elementInfo.classNames) {
                results.push(', elementInfo.classNames, '"')
            }
            setAttrs(elementInfo.attrs, results)
            if (selfCloseTagRegexp.test(tagName)) {
                results.push(' />')
            } else {
                results.push('>')
                if (Array.isArray(elementInfo.children)) {
                    elementInfo.children.forEach(item => toElement(item, results))
                }
                results.push('</', tagName, '>')
            }
            break;
        case TEXT:
            results.push(elementInfo.content)
            break;
        case COMMENT:
            results.push("<!-- ", elementInfo.content, " -->")
            break;
        default:
        // ignore
    }
}
export const tohtml = json => {
    json = json || []
    if (isPlainObject(json)) {
        json = [json]
    }
    const results = []
    json.forEach(item => toElement(item, results))
    return results.join('')
}


示例

const source = '<div>測試1</div> <div>測試2</div>'
const htmljson = toJSON(source, { skipScript: true, skipStyle: true, pureClass: true, pureComment: true })
const jsonhtml = toHTML(htmljson)
console.log(htmljson)
console.log(jsonhtml)


參數說明

skipScript 過濾 script 標籤,默認 false

skipStyle 過濾 style 標籤,默認 false

pureClass 去掉 class 屬性,默認 false

pureComment 去掉註釋,默認 false

備註

htmlparser2 通過 npm i htmlparser2 –save 進行安裝即可  

原文鏈接 IT浪子の博客 > JSON和HTML之間互轉實現

站長推薦

1.雲服務推薦: 國內主流雲服務商,各類雲產品的最新活動,優惠券領取。地址:阿里雲騰訊雲華為雲

2.廣告聯盟: 整理了目前主流的廣告聯盟平台,如果你有流量,可以作為參考選擇適合你的平台點擊進入

鏈接: http://www.fly63.com/article/detial/9055