js相關

1、Object.defineProperty()方法

vue的雙向數據綁定就是經過Object.defineProperty()方法實現的,俗稱屬性攔截器。html

方法會直接在一個對象上定義一個新屬性,或者修改一個已經存在的屬性, 並返回這個對象。vue

// 語法:
/*
 * @param: obj:須要定義屬性的對象; 
 *         prop:須要定義或修改的屬性;
 *         descriptor:將被定義或修改屬性的描述符
*/
Object.defineProperty(obj,prop,descriptor)

實例:es6

var a = {};
Object.defineProperty(a, 'b', {
    set: function(newValue) {
        console.log('賦值操做, 賦值' + newValue);
    },
    get: function() {
        console.log('取值操做');
        return 2;
    }
});
a.b = 1;    // 賦值操做,賦值1
a.b;       // 取值操做2

 下面咱們來寫個實例看看,這裏咱們以Vue爲參照去實現怎麼寫MVVM數組

// index.html
<body>
    <div id="app">
        <h1>{{song}}</h1>
        <p>《{{album.name}}》是{{singer}}2005年11月發行的專輯</p>
        <p>主打歌爲{{album.theme}}</p>
        <p>做詞人爲{{singer}}等人。</p>
        爲你彈奏肖邦的{{album.theme}}
    </div>
    <!--實現的mvvm-->
    <script src="mvvm.js"></script>
    <script>
        // 寫法和Vue同樣
        let mvvm = new Mvvm({
            el: '#app',
            data: {     // Object.defineProperty(obj, 'song', '發如雪');
                song: '發如雪',
                album: {
                    name: '十一月的蕭邦',
                    theme: '夜曲'
                },
                singer: '周杰倫'
            }
        });
    </script>
</body>

上面是html裏的寫法,相信用過Vue的同窗並不陌生app

那麼如今就開始實現一個本身的MVVM吧async

打造MVVM

// 建立一個Mvvm構造函數
// 這裏用es6方法將options賦一個初始值,防止沒傳,等同於options || {}
function Mvvm(options = {}) {   
    // vm.$options Vue上是將全部屬性掛載到上面
    // 因此咱們也一樣實現,將全部屬性掛載到了$options
    this.$options = options;
    // this._data 這裏也和Vue同樣
    let data = this._data = this.$options.data;

    // 數據劫持
    observe(data);
}

數據劫持

爲何要作數據劫持?mvvm

  • 觀察對象,給對象增長Object.defineProperty函數

  • vue特色是不能新增不存在的屬性 不存在的屬性沒有get和setthis

  • 深度響應 由於每次賦予一個新對象時會給這個新對象增長defineProperty(數據劫持)spa

多說無益,一塊兒看代碼

// 建立一個Observe構造函數
// 寫數據劫持的主要邏輯
function Observe(data) {
    // 所謂數據劫持就是給對象增長get,set
    // 先遍歷一遍對象再說
    for (let key in data) {     // 把data屬性經過defineProperty的方式定義屬性
        let val = data[key];
        observe(val);   // 遞歸繼續向下找,實現深度的數據劫持
        Object.defineProperty(data, key, {
            configurable: true,
            get() {
                return val;
            },
            set(newVal) {   // 更改值的時候
                if (val === newVal) {   // 設置的值和之前值同樣就不理它
                    return;
                }
                val = newVal;   // 若是之後再獲取值(get)的時候,將剛纔設置的值再返回去
                observe(newVal);    // 當設置爲新值後,也須要把新值再去定義成屬性
            }
        });
    }
}

// 外面再寫一個函數
// 不用每次調用都寫個new
// 也方便遞歸調用
function observe(data) {
    // 若是不是對象的話就直接return掉
    // 防止遞歸溢出
    if (!data || typeof data !== 'object') return;
    return new Observe(data);
}


以上代碼就實現了數據劫持

 

 

2、巧用JSON.stringify()生成漂亮格式的JSON字符串

就是經過  函數的第三個參數來指定縮進的空格數:
JSON.stringify()
// 此處爲了示例, 採用字面量的形式構造了一個對象
// 實際使用中, 通常是某個POJO,或者VO之類的值對象
var myObject =  {
        "myProp": "myValue", "subObj": { "prop": "value" } }; // 格式化 var formattedStr = JSON.stringify(myObject, null, 2);
生成的字符串以下所示:
{
  "myProp": "myValue",
  "subObj": {
    "prop": "value"
  }
}

 

3、實現一個 sleep 函數

好比 sleep(1000) 意味着等待1000毫秒,可從 Promise、Generator、Async/Await 等角度實現。

1.

//Promise
const sleepp = time => {
  return new Promise(resolve => setTimeout(resolve,time))
}
sleepp(1000).then(()=>{
  console.log(1)
})

2.

//Generator
function* sleepGenerator(time) {
  yield new Promise(function(resolve,reject){
    setTimeout(resolve,time);
  })
}
sleepGenerator(1000).next().value.then(()=>{console.log(1)})

3.

//async
function sleep(time) {
  return new Promise(resolve => setTimeout(resolve,time))
}
async function output() {
  let out = await sleep(1000);
  console.log(1);
  return out;
}
output();

4.

//ES5
function sleep(callback,time) {
  if(typeof callback === 'function')
    setTimeout(callback,time)
}

function output(){
  console.log(1);
}
sleep(output,1000);

 

4、數組去重並獲取重複元素次數

    const AA = [1,2,3,4,2,1,2,2,4,6,4]

    function filter (arr) {
      var newArr = []
      var obj={}
      for(var i = 0; i < arr.length; i++){
        if(obj[arr[i]]){
          obj[arr[i]]++
        }else{
          newArr.push(arr[i])
          obj[arr[i]]=1
        }
      }
      var res = []
      for (var n in obj) {
        if(obj[n] > 1) {
          res.push(`重複元素:${n},重複了${obj[n]}次`)
        }
      }
      return res
    }
    console.log(filter(AA))

5、合併數組並去重

  // 數組合並並去重
    let arr1 = [1, 1, 2, 3, 't', 9, 5, 5, 4]
    let arr2 = [1, 2, 5, 4, 9, 7, 7, 't', 8]
function uniqueArr(arr1,arr2) { //合併兩個數組 arr1.push(...arr2)//或者arr1 = [...arr1,...arr2] //去重 let arr3 = Array.from(new Set(arr1))//let arr3 = [...new Set(arr1)] return arr3 } console.log(uniqueArr(arr1, arr2))

 

6、js實現漢字中文排序的方法 例如:省市列表的排序

1.數組內的元素是中文字符串的簡單排序

 

var arr = ['南京', '北京', '上海', '杭州', '深圳'];
  function sortChinese (arr) { // 參數: 排序的數組
    arr.sort(function (item1, item2) {
      return item1.localeCompare(item2, 'zh-CN');
    })
  }
  sortChinese(arr)
  console.log(arr); //  ["北京", "杭州", "南京", "上海", "深圳"]

 

2.數組內的元素是對象,以對象某一個屬性進行排序

var arr = [
    {name: '南京', code: '09', info: {province: '江蘇'}},
    {name: '北京', code: '01', info: {province: '北京'}},
    {name: '上海', code: '02', info: {province: '上海'}},
    {name: '深圳', code: '05', info: {province: '廣東'}}
  ];
  function sortChinese (arr, dataLeven) { // 參數:arr 排序的數組; dataLeven 數組內的須要比較的元素屬性
    /* 獲取數組元素內須要比較的值 */
    function getValue (option) { // 參數: option 數組元素
      if (!dataLeven) return option
      var data = option
      dataLeven.split('.').filter(function (item) {
        data = data[item]
      })
      return data + ''
    }
    return arr.sort(function (item1, item2) {
      return getValue(item1).localeCompare(getValue(item2), 'zh-CN');
    })
  }
  console.log(sortChinese(arr, 'name') // 例如:比較的是name,傳入的就是 'name'
); /*[{name: '北京', code: '01', info: {province: '北京'}}, {name: '南京', code: '09', info: {province: '江蘇'}}, {name: '上海', code: '02', info: {province: '上海'}}, {name: '深圳', code: '05', info: {province: '廣東'}}]*/ sortChinese(arr, 'info.province') // 例如:比較的是數組元素屬性info內的province屬性,傳入的就是 'info.province'  console.log(arr); /* [{name: '北京', code: '01', info: {province: '北京'}}, {name: '深圳', code: '05', info: {province: '廣東'}}, {name: '南京', code: '09', info: {province: '江蘇'}}, {name: '上海', code: '02', info: {province: '上海'}}]*/

3.對國內的全部省份進行排序,而且首字母相同的第一個添加首字母

function chineseLetter (arr, dataLeven) {
    var letter = 'abcdefghjklmnopqrstwxyz'.split('')
    var zh = "阿八嚓噠妸發旮哈譏咔垃痳拏噢妑七呥扨它穵夕丫帀".split('')
    /* 獲取數組元素比較的值 */
    function getValue (option) {
      if (!dataLeven) return option
      var data = option
      dataLeven.split('.').filter(function (item) {
        data = data[item]
      })
      return data + ''
    }
    /* 進行排序 */
    arr.sort(function (item1, item2) {
      return getValue(item1).localeCompare(getValue(item2), 'zh-Hans-CN')
    })
    /* 判斷須要排序的字符串是否含有中文字符 */
    if (/[\u4e00-\u9fff]/.test(getValue(arr[0])) && typeof arr[0] === 'object') pySegSort(0, 0)
    /* 給省列表中添加首字符 */
    function pySegSort (letterIndex, zhIndex) {
      var first = true // 首次是否加 字母標識
      for (var i = zhIndex; i < arr.length; i++) {
        var item = arr[i]
        //      是否有值 && 當前值大於等於本次字母的最小值 && (最後一位 || 當前值小於下次字母的最小值)
        var state = zh[letterIndex] && getValue(item).localeCompare(zh[letterIndex], 'zh') >= 0 && (letterIndex === letter.length - 1 || getValue(item).localeCompare(zh[letterIndex+1], 'zh') < 0)
        if (state) { // 知足條件,同一個首字母下的:例如 A 下的全部省份
          if (first) { //是不是第一次出現
            item.letter = letter[letterIndex].toUpperCase()
            first = false
          } else {
            item.letter = ''
          }
        } else { // 遞歸調用 函數,進行下次字母下的排列
          letterIndex++
          if (letterIndex < letter.length) {
            pySegSort(letterIndex, i)
            break
          }
        }
      }
    }
  }
  chineseLetter(provinceList, 'value')
  console.log(provinceList)
相關文章
相關標籤/搜索