js对象学习

对象添加删除检测

let Object ={}
//添加
Object.name=8
Object['age']=3
//删除
delete Object.name
//检测本身
console.log(Object.hasOwnProperty('name'));  //布尔值
//数组对象检测本身加原型
console.log('constructor' in Object); //布尔值

计算属性给对象定义键名

const lessons = [
    {
      title:'任1务',
      cons:'cs1s'
    },
    {
      title:'任2务',
      cons:'css2',
    },
    {
      title:'任3务',
      cons:'cs4s'
    }
  ]
  let obj = {}
  let res = lessons.map((a,b)=>obj[`${a.cons}-${b}`]=a)
  console.log(obj);

image-20220130004418600

利用系统API获取对象属性与值

const hd = {
  name: "后盾人",
  age: 10
};
console.log(Object.keys(hd)); //["name", "age"]
console.log(Object.values(hd)); //["后盾人", 10]
console.table(Object.entries(hd)); //[["name","后盾人"],["age",10]]

遍历对象

for/in 用于遍历对象属性

const hd = {
  name: "后盾人",
  age: 10
};
for (let key in hd) {
  console.log(key, hd[key]);
}   // 后盾人   10

for/of 用于遍历迭代对象,不能直接操作对象。但Object对象的keys/方法返回的是迭代对象。通常用作遍历数组

const hd = {
  name: "后盾人",
  age: 10
};
for (const [key, value] of Object.entries(hd)) {
  console.log(key, value);       //name 后盾人
}                                //age 10

拷贝

对象拷贝:对象赋值时复制的内存地址,所以一个对象的改变直接影响另一个

let obj = {
  name: '后盾人',
  user: {
  	name: 'hdcms'
  }
}
let a = obj;
let b = obj;
a.name = 'lisi';
console.log(b.name); //lisi

浅拷贝:改变新数据,不改变原数据,个人理解为只是针对一层数据的拷贝有效,多层嵌套结构的数据则无效。

  1. 使用for/in执行对象拷贝
let obj = {name: "后盾人"};

let hd = {};
for (const key in obj) {
  hd[key] = obj[key];
}

hd.name = "hdcms";
console.log(hd);
console.log(obj);
  1. Object.assign 函数可简单的实现浅拷贝,它是将两个对象的属性叠加后面对象属性会覆盖前面对象同名属性。
  2. 使用es6扩展符也可以实现浅拷贝

**深拷贝:**改变新数据,不改变原数据

  1. 使用for/in执行深拷贝
let obj = {
    name: '后盾人',
    user: {
        name: 'hdcms'
    },
    use:[4]
}
function ob(obj){
  let res = ob instanceof Array ?[]:{}
  for(const [k,v] of Object.entries(obj)){
    typeof( res[k] =  v) ==='Object'?ob(v):res[k] =  v
  }
  return res
}
console.log(ob(obj));
  1. JSON.parse(JSON.stringify())函数可实现深拷贝

属性特征

JS中可以对属性的访问特性进行控制

查看特征:使用 Object.getOwnPropertyDescriptor查看对象属性的描述

const user = {
  name: "向军",
  age: 18
};
// 查看所有属性特征
let desc = Object.getOwnPropertyDescriptors(user);
//查看一个属性特征
let desc = Object.getOwnPropertyDescriptor(user, "name"`)

属性包括以下四种特性

特性说明默认值
configurable能否使用delete、能否需改属性特性、或能否修改访问器属性true
enumerable对象属性是否可通过for-in循环,或Object.keys() 读取true
writable对象属性是否可修改true
value对象属性的默认值undefined

**设置特征:**使用Object.defineProperty 方法修改属性特性,通过下面的设置属性name将不能被遍历、删除、修改。

"use strict";
const user = {
  name: "向军"
};
Object.defineProperty(user, "name", {
  value: "后盾人",
  writable: false,
  enumerable: false,
  configurable: false
});

禁止添加:Object.preventExtensions 禁止向对象添加属性

const user = {
  name: "向军"
};
Object.preventExtensions(user);
user.age = 18; //Error

Object.isExtensible 判断是否能向对象中添加属性

const user = {
  name: "向军"
};
Object.preventExtensions(user);
console.log(Object.isExtensible(user)); //false

封闭对象Object.seal()方法封闭一个对象,阻止添加删除新属性并将所有现有属性标记为 `configurable: false,可以修改属性

const user = {
  name: "后盾人",
  age: 18
};

Object.seal(user);

delete user.name; //Error

Object.isSealed 如果对象是密封的则返回 true,属性都具有 configurable: false

"use strict";
const user = {
  name: "向军"
};
Object.seal(user);
console.log(Object.isSealed(user)); //true

**冻结对象:**Object.freeze冻结对象后不允许添加、删除、修改属性,writable、configurable都标记为false

const user = {
  name: "向军"
};
Object.freeze(user);
user.name = "后盾人"; //Error

Object.isFrozen()方法判断一个对象是否被冻结

const user = {
  name: "向军"
};
Object.freeze(user);
console.log(Object.isFrozen(user)); //true

注意:封闭对象可以修改对象值,冻结不可修改

访问器

**gerter/setter:**getter方法用于获得属性值,setter方法用于设置属性,这是JS提供的存取器特性即使用函数来管理属性。

const user = {
  data: { name: '后盾人', age: null },
    //给属性赋值
  set age(value) { 
    if (typeof value != "number" || value > 100 || value < 10) {
      throw new Error("年龄格式错误");
    }
    this.data.age = value;
  },
    //获取值
  get age() {
    return `年龄是: ${this.data.age}`;
  }
};
user.age = 99; //走set age
console.log(user.age); //走get age

下面通过设置站网站名称与网址体验getter/setter批量设置属性的使用

const web = {
  name: "后盾人", //后盾
  url: "houdunren.com",  //hdcms
  get site() {
    return `${this.name} ${this.url}`;
  },
  set site(value) {
    [this.name, this.url] = value.split(",");
  }
};
web.site = "后盾,hdcms";
console.log(web.site); //后盾hdcms

访问器描述符:使用 defineProperty 可以模拟定义私有属性,从而使用面向对象的抽象特性。

function User(name, age) {
  let data = { name, age };
  Object.defineProperties(this, {
    name: {
      get() {
        return data.name;
      },
      set(value) {
        if (value.trim() == "") throw new Error("无效的用户名");
        data.name = value;
      }
    },
    age: {
      get() {
        return data.name;
      },
      set(value) {
        if (value.trim() == "") throw new Error("无效的用户名");
        data.name = value;
      }
    }
  });
}
let hd = new User("后盾人", 33);
console.log(hd.name);
hd.name = "向军1";
console.log(hd.name);

上面的代码也可以使用语法糖 class定义

const DATA = Symbol();
class User {
  constructor(name, age) {
    this[DATA] = { name, age };
  }
  get name() {
    return this[DATA].name;
  }
  set name(value) {
    if (value.trim() == "") throw new Error("无效的用户名");
    this[DATA].name = value;
  }
  get age() {
    return this[DATA].name;
  }
  set age(value) {
    if (value.trim() == "") throw new Error("无效的用户名");
    this[DATA].name = value;
  }
}
let hd = new User("后盾人", 33);
console.log(hd.name);
hd.name = "向军1";
console.log(hd.name);
console.log(hd);

代理拦截

**代理对象:**代理(拦截器)是对象的访问控制,setter/getter 是对单个对象属性的控制,而代理是对整个对象的控制。严格模式set必须返回布尔值

"use strict";
const hd = { name: "后盾人" };
const proxy = new Proxy(hd, {
  get(obj, property) {   //obj是hd对象,property随proxy.age = 10;属性名age改变而改变
    return obj[property];
  },
  set(obj, property, value) { //value随proxy.age = 10;值改变而改变
    obj[property] = value;
    return true;
  }
});
proxy.age = 10;
console.log(hd);

**代理函数:**如果代理以函数方式执行时,会执行代理中定义 apply 方法。

下面使用 apply 计算函数执行时间

function factorial(num) {
  return num == 1 ? 1 : num * factorial(num - 1);
}
let proxy = new Proxy(factorial, {
  apply(func, obj, args) {  //参数说明:函数,上下文对象,参数
    console.time("run");
    func.apply(obj, args);
    console.timeEnd("run");
  }
});
proxy.apply(this, [1000]);

**截取字符串:**下例中对数组进行代理,用于截取标题操作

const lessons = [
  {
    title: "媒体查询响应式布局",
    category: "css"
  },
  {
    title: "FLEX 弹性盒模型",
    category: "css"
  },
  {
    title: "MYSQL多表查询随意操作",
    category: "mysql"
  }
];
let proxy = new Proxy(lessons,{
  get(array,key){
    const title= array[key].title
    array[key].title= title.length>5?title.substr(0,5):title //改变原数组
    return array[key]
  }
})
console.log(proxy[0]);

数据双向绑定

下面通过代理实现vue 等前端框架的数据绑定特性特性。

<body>
<input type="text" v-model="title" />
<input type="text" v-model="title" />
<div v-bind="title"></div>
</body>
<script>
    //构造函数
function View() {
	//设置代理拦截
  let proxy = new Proxy(
    {},
    {
      get(obj, property) {},
      set(obj, property, value) {
        obj[property] = value;
        document
          .querySelectorAll(
            `[v-model="${property}"],[v-bind="${property}"]`
          )
          .forEach(el => {
            el.innerHTML = value;
            el.value = value;
          });
      }
    }
  );
  //初始化绑定元素事件
  this.run = function() {
    const els = document.querySelectorAll("[v-model]");
    els.forEach(item => {
      item.addEventListener("keyup", function() {
        proxy[this.getAttribute("v-model")] = this.value;
      });  //getAttribute("v-model")通过class名获取class值
    });
  };
}
let view = new View().run();

表单验证

<style>
  body {
    padding: 50px;
    background: #34495e;
  }
  input {
    border: solid 10px #ddd;
    height: 30px;
  }
  .error {
    border: solid 10px red;
  }
</style>
<body>
  <input type="text" validate rule="max:12,min:3" />
  <input type="text" validate rule="max:3,isNumber" />
</body>
<script>
  "use strict";
  //验证处理类
  class Validate {
    max(value, len) {
      return value.length <= len;
    }
    min(value, len) {
      return value.length >= len;
    }
    isNumber(value) {
      return /^\d+$/.test(value);
    }
  }

  //代理工厂
  function makeProxy(target) {
    return new Proxy(target, {
      get(target, key) {
        return target[key];
      },
      set(target, key, el) {
        const rule = el.getAttribute("rule");  //获取class值
        const validate = new Validate(); //创建构造函数
        let state = rule.split(",").every(rule => {  //max:12,min:3
          const info = rule.split(":"); ['max','12 ']'
          return validate[info[0]](el.value, info[1]); //max(输入框值,12)
        });
        el.classList[state ? "remove":"add"]("error"); //给标签添加class
        return true;
      }
    });
  }

  const nodes = makeProxy(document.querySelectorAll("[validate]"));//把需要验证的元素传给函数
//给元素添加事件
  nodes.forEach((item, i) => {
    item.addEventListener("keyup", function() {
        //主要触发set
      nodes[i] = this;
    });
  });
</script>

json

序列化是将 json 转换为字符串,一般用来向其他语言传输使用。

根据第二个参数指定保存的属性

第三个是参数用来控制TAB数量,如果字符串则为前导字符。

let hd = {
  title: "后盾人",
  url: "houdunren.com",
  teacher: {
  	name: "向军大叔",
  }
}
console.log(JSON.stringify(hd, null, 4));//全部转换保存
console.log(JSON.stringify(hd, ['title', 'url'])); //只保存title,url

为数据添加 toJSON 方法来自定义返回格式

let hd = {
    "title": "后盾人",
    "url": "houdunren.com",
    "teacher": {
        "name": "向军大叔",
    },
    "toJSON": function () {
        return {
            "title": this.url,
            "name": this.teacher.name
        };
    }
}
console.log(JSON.stringify(hd)); //{"title":"houdunren.com","name":"向军大叔"}

反序列化

使用 JSON.parse 将字符串 json 解析成对象,使用第二个参数函数来对返回的数据二次处理

let hd = {
  title: "后盾人", //[推荐]后盾人
  url: "houdunren.com",
  teacher: {
    name: "向军大叔"
  }
};
let jsonStr = JSON.stringify(hd);
console.log(
  JSON.parse(jsonStr, (key, value) => {  //keys
    if (key == "title") {
      return `[推荐] ${value}`;
    }
    return value;
  })
);

turn {
“title”: this.url,
“name”: this.teacher.name
};
}
}
console.log(JSON.stringify(hd)); //{“title”:“houdunren.com”,“name”:“向军大叔”}


## 反序列化

使用 `JSON.parse` 将字符串 `json` 解析成对象,使用第二个参数函数来对返回的数据二次处理

```js
let hd = {
  title: "后盾人", //[推荐]后盾人
  url: "houdunren.com",
  teacher: {
    name: "向军大叔"
  }
};
let jsonStr = JSON.stringify(hd);
console.log(
  JSON.parse(jsonStr, (key, value) => {  //keys
    if (key == "title") {
      return `[推荐] ${value}`;
    }
    return value;
  })
);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

25氪

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值