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构造函数
// 这里用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); }
以上代码就实现了数据劫持
就是经过 函数的第三个参数来指定缩进的空格数:
JSON.stringify()
// 此处为了示例, 采用字面量的形式构造了一个对象
// 实际使用中, 通常是某个POJO,或者VO之类的值对象
var myObject = {
"myProp": "myValue", "subObj": { "prop": "value" } }; // 格式化 var formattedStr = JSON.stringify(myObject, null, 2);
生成的字符串以下所示:
{ "myProp": "myValue", "subObj": { "prop": "value" } }
好比 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);
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))
// 数组合并并去重 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))
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)