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)
相关文章
相关标签/搜索