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)