最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

JS使用鏈?zhǔn)綄傩员磉_(dá)式取值和賦值的實(shí)現(xiàn)方法

 更新時(shí)間:2023年08月09日 11:57:31   作者:CoderLiu  
這篇文章主要給大家詳細(xì)介紹了JS如何使用鏈?zhǔn)綄傩员磉_(dá)式取值和賦值,文章通過代碼示例介紹的非常詳細(xì),對(duì)我們的學(xué)習(xí)或工作有一定的幫助,感興趣的同學(xué)可以參考一下

什么是鏈?zhǔn)綄傩员磉_(dá)式?

例如,有這樣一個(gè)對(duì)象:

const obj = {a: {b: {c: 3} } };

我們要取到其中c的值,正常情況下我們有很多種方法可以取到值,例如直接點(diǎn)或者使用解構(gòu)等:

const c = obj.a.b.c;
const {a: {b: {c} } } = obj;

但是有一些情況不是我們主動(dòng)去取值的,而是由某個(gè)方法或某個(gè)類在其執(zhí)行時(shí)去取值。舉個(gè)例子:Vue2的響應(yīng)式原理是劫持對(duì)象的 getter 和 setter ,在 getter 中收集依賴,在 setter 中觸發(fā)依賴,那如何確定哪些屬性是被依賴的呢,Watcher這個(gè)類就接受表達(dá)式為參數(shù),它來獲取屬性值,屬性被訪問后觸發(fā)getter,該屬性的依賴就被收集了,在被更新時(shí)就會(huì)執(zhí)行回調(diào)。

const viewModel = {a: {n: { m } } };
new Watcher(viewModel, "a.n.m", (newVal, oldVal) => {
  console.log("新的值--》", newVal);
  console.log("老的值--》", oldVa1l);
});

那么上例中的 a.n.m 就是鏈?zhǔn)綄傩员磉_(dá)式了,通過鏈?zhǔn)綄傩员磉_(dá)式來告訴方法要獲取對(duì)象的哪個(gè)屬性。

還有微信小程序的observer監(jiān)聽器,setData方法等都應(yīng)用到了鏈?zhǔn)綄傩员磉_(dá)式,道理都一樣,通過鏈?zhǔn)綄傩员磉_(dá)式去取值或賦值。

鏈?zhǔn)饺≈?/h2>

先看一下要支持的數(shù)據(jù)類型:

// 對(duì)象,使用 . 訪問
obj.a.b.c
// 數(shù)組,使用下標(biāo)訪問,要支持連續(xù)訪問
arr[0][1][2]
// 對(duì)象數(shù)組嵌套混合
obj.a[0].b

先把鏈?zhǔn)綄傩员磉_(dá)式(以下簡稱路徑)解析為字段數(shù)組,便于后續(xù)操作,例如:把 路徑obj.arr[0].a.b 解析成 ['obj', 'arr', 0, 'a', 'b']

// 解析路徑為字段數(shù)組
function parsePath(path: string) {
  const segments: string[] = path.split('.'); // 分割字段片段
  let fileds: Array<number | string> = []; // 保存字段名
  if (path.includes('[')) { // 如果包含數(shù)組下標(biāo),收集數(shù)組索引 類似arr[0]這樣的格式
    for (const segment of segments) {
      if (/^(\w+)(\[(\w+)\])+/.test(segment)) { // 匹配 類似 arr[0][1] 這種格式
        const arrIndexs: number[] = [];
        for (const item of segment.matchAll(/(\w*)\[(\w+)\]/g)) {
          if (item[1]) fileds.push(item[1]); // 第一個(gè)匹配的括號(hào),即數(shù)組字段名
          arrIndexs.push(~~item[2]); // 第二個(gè)匹配的括號(hào),即數(shù)組索引
        }
        fileds.push(...arrIndexs);
      } else { // 如果是被'.'分割完的字段直接push
        fileds.push(segment);
      }
    }
  } else { // 無數(shù)組值時(shí)無需遍歷,提高性能
    fileds = segments;
  }
  return fileds;
}

注意一個(gè)細(xì)節(jié),數(shù)組合并的方法有性能差異,在寫工具、框架等對(duì)性能要求高的情況下,更推薦使用push, Array.prototype.push.apply(array1, array2)array1.push(…array2) 都行,這倆差距很微小。

  • 數(shù)組元素量級(jí)大而合并次數(shù)少時(shí),性能對(duì)比:
    concat() > push() > […array1,…array2]

  • 數(shù)組元素少但合并次數(shù)多時(shí),性能對(duì)比:
    push() > concat() > […array1,…array2]

  • push()方法適合10萬級(jí)以下元素的數(shù)組合并,次數(shù)越多越有優(yōu)勢,但push()怕數(shù)組元素多,超過12萬左右就會(huì)報(bào)錯(cuò),導(dǎo)致無法合并數(shù)組

  • concat()方法適合數(shù)組元素量級(jí)大,但是合并次數(shù)少的情況,當(dāng)數(shù)組合并頻繁的時(shí)候性能表現(xiàn)略差;

  • […array1, …array2]方法無論是大量級(jí)數(shù)組合并還是數(shù)組頻繁合并,都不占優(yōu)勢,單從性能方面來說,是最差的一種,莫非是因?yàn)樗獎(jiǎng)?chuàng)建數(shù)組產(chǎn)生了較大開銷。

綜合對(duì)比來說: push() > concat() > […array1,…array2]

一般情況下,用push()方法合并數(shù)組是最快的方法,concat()方法可以支撐大量級(jí)數(shù)組合并,而[…array1,…array2]擴(kuò)展運(yùn)算符可讀性較好,不考慮性能時(shí)可以用;

插播一下 String.prototype.matchAll()方法,大家可能有不理解的地方:

matchAll()  方法返回一個(gè)包含所有匹配正則表達(dá)式的結(jié)果及分組捕獲組的迭代器。

const arr = [...'arr[0][1]'.matchAll(/(\w*)\[(\w+)\]/g)];
//  arr[0]:??["arr[0]",?"arr",?"0",?index:?0,?input:?"arr[0][1]",?groups:?undefined]
//  arr[1]:??["[1]",?"",?"1",?index:?6,?input:?"arr[0][1]",?groups:?undefined]

把路徑解析為字段數(shù)組之后,就可以用 reduce 方法來鏈?zhǔn)饺≈盗耍?/p>

// 鏈?zhǔn)饺≈?
function getValByPath(target: object, path: string): any {
  if (!(/[\\.\\[]/.test(path))) return target[path]; // 如果沒有 . 或 [ 符號(hào)說明非鏈?zhǔn)剑苯臃祷貙傩灾?
  const fileds = getPathFileds(path);
  const val = fileds.reduce((pre, cur) => pre?.[cur], target); // 取不到的時(shí)候返回undefined
  return val;
}

上面方法沒有做類型檢查以及默認(rèn)值等,根據(jù)你自己的需要來就行。

到這里,我們就可以用getValByPath方法根據(jù)鏈?zhǔn)綄傩员磉_(dá)式來獲取對(duì)象的屬性值了。

鏈?zhǔn)劫x值

賦值相對(duì)來說更麻煩一些

// 鏈?zhǔn)劫x值
function updateValByPath(target: object, path: string, value): void {
  if (!(/[\\.\\[]/.test(path))) return target[path] = value; // 如果沒有 . 或 [ 符號(hào)說明非鏈?zhǔn)剑苯淤x值
  const fileds = getPathFileds(path);
  // cosnt obj = {a: {b: {c: 6}}};
  // 獲取值引用 ,例如更新obj對(duì)象的c值,需要獲取{c: 6}對(duì)象的引用,即obj.a.d = {c: 6},拿到引用后 ref.c = 8,就 {c: 6} 更新成 {c: 8} 了
  const ref = fileds.slice(0, -1).reduce((pre, cur) => pre[cur], target); // 只遍歷到倒數(shù)第二個(gè)字段,因?yàn)檫@個(gè)字段就是被修改對(duì)象的引用
  if (ref) return ref[`${fileds.at(-1)}`] = value; // 拿到引用后,更新最后一個(gè)字段
  // 如果引用對(duì)象不存在,提醒開發(fā)者不要更新不存在的屬性
  console.warn(`updated property "${path}" is not registered in data, you will not be able to get the value synchronously through "this.data"`);
}

大家已經(jīng)發(fā)現(xiàn)了,上面的方法只能更新引用存在的情況,即被更新數(shù)據(jù)的父級(jí)對(duì)象存在,如果要支持更復(fù)雜的情況,需要在被更新屬性沒有父級(jí)屬性時(shí)幫它創(chuàng)建父級(jí)對(duì)象,可能是一個(gè)對(duì)象類型也可能是一個(gè)數(shù)組類型,這將額外消耗很多內(nèi)存和性能,而且本身隨意操作一個(gè)對(duì)象沒有的屬性就不符合嚴(yán)謹(jǐn)?shù)拇a規(guī)范,不利于維護(hù),大家感興趣的話可以自己在此基礎(chǔ)上擴(kuò)展,支持設(shè)置不存在的屬性。

以上就是詳解JS如何使用鏈?zhǔn)綄傩员磉_(dá)式取值和賦值的詳細(xì)內(nèi)容,更多關(guān)于JS鏈?zhǔn)饺≈岛唾x值的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • js實(shí)現(xiàn)掃雷源代碼

    js實(shí)現(xiàn)掃雷源代碼

    這篇文章主要為大家詳細(xì)介紹了js實(shí)現(xiàn)掃雷源代碼,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2020-11-11
  • html的DOM中Event對(duì)象onabort事件用法實(shí)例

    html的DOM中Event對(duì)象onabort事件用法實(shí)例

    這篇文章主要介紹了html的DOM中Event對(duì)象onabort事件用法,實(shí)例分析了onabort事件的適用范圍與對(duì)應(yīng)的javascript使用技巧,需要的朋友可以參考下
    2015-01-01
  • TypeScript 變量聲明的實(shí)現(xiàn)示例

    TypeScript 變量聲明的實(shí)現(xiàn)示例

    本文詳細(xì)介紹了TypeScript中變量的聲明、命名規(guī)則、聲明方式以及類型斷言的使用,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2025-12-12
  • Bootstrap modal 多彈窗之疊加關(guān)閉陰影遮罩問題的解決方法

    Bootstrap modal 多彈窗之疊加關(guān)閉陰影遮罩問題的解決方法

    這里也會(huì)遇到一次性關(guān)閉所有modal引起陰影遮罩的問題,也就是所有modal都關(guān)閉了,但是主頁面仍然被陰影遮罩。下面通過本文給大家分享解決方案,需要的朋友參考下吧
    2017-02-02
  • JavaScript函數(shù)擴(kuò)展與箭頭函數(shù)超詳細(xì)講解

    JavaScript函數(shù)擴(kuò)展與箭頭函數(shù)超詳細(xì)講解

    這篇文章主要介紹了JavaScript函數(shù)擴(kuò)展與箭頭函數(shù)的使用,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)吧
    2022-11-11
  • ES6基礎(chǔ)之?dāng)?shù)組和對(duì)象的拓展實(shí)例詳解

    ES6基礎(chǔ)之?dāng)?shù)組和對(duì)象的拓展實(shí)例詳解

    這篇文章主要介紹了ES6基礎(chǔ)之?dāng)?shù)組和對(duì)象的拓展,結(jié)合實(shí)例形式詳細(xì)分析了ES6數(shù)組和對(duì)象拓展運(yùn)算符、拓展方法的使用及相關(guān)操作技巧,需要的朋友可以參考下
    2019-08-08
  • js實(shí)現(xiàn)五星評(píng)價(jià)功能

    js實(shí)現(xiàn)五星評(píng)價(jià)功能

    本文主要介紹了js實(shí)現(xiàn)五星評(píng)價(jià)功能和印象評(píng)價(jià)功能的實(shí)例,具有很好的參考價(jià)值。下面跟著小編一起來看下吧
    2017-03-03
  • 微信小程序動(dòng)態(tài)生成二維碼的實(shí)現(xiàn)代碼

    微信小程序動(dòng)態(tài)生成二維碼的實(shí)現(xiàn)代碼

    這篇文章主要介紹了微信小程序動(dòng)態(tài)生成二維碼的實(shí)現(xiàn)代碼,需要的朋友可以參考下
    2018-07-07
  • javascript之bind使用介紹

    javascript之bind使用介紹

    首先apply和call是老生常談的東西,但是對(duì)于bind,我愣了下,因?yàn)檫@個(gè)詞是jquery中使用頻率很高的一個(gè)方法,用來給DOM元素綁定事件用的
    2011-10-10
  • javascript實(shí)現(xiàn)仿騰訊游戲選擇

    javascript實(shí)現(xiàn)仿騰訊游戲選擇

    這篇文章主要介紹了javascript實(shí)現(xiàn)仿騰訊游戲選擇,簡單實(shí)現(xiàn)的下拉菜單二級(jí)聯(lián)動(dòng)效果,十分不錯(cuò),有需要的小伙伴可以參考下。
    2015-05-05

最新評(píng)論

政和县| 绿春县| 石泉县| 柳林县| 孝感市| 龙岩市| 定南县| 莲花县| 潮州市| 津南区| 伊川县| 大姚县| 长寿区| 临汾市| 巩留县| 朝阳县| 团风县| 诏安县| 双鸭山市| 开江县| 永新县| 乐山市| 舞阳县| 安新县| 汉源县| 青海省| 仲巴县| 临桂县| 商城县| 曲阳县| 奉化市| 揭阳市| 洪雅县| 胶南市| 黄大仙区| 长海县| 丹江口市| 瑞丽市| 阜新市| 华宁县| 平遥县|