js重难点精讲(ES二)|8月更文挑战

291 阅读6分钟

早上岁月静好,炎热的夏天,早上七点的成都还算凉爽,妈妈在厨房煮着早餐,女儿还在床上熟睡,我在床边看着书,一切很美好。

ES6对于对象的扩展

属性简写

  • 可以直接在对象中写入变量
  • key相当于变量名,value相当于变量值,可以省略value,只通过key表示对象的完整属性
const name = 'yangf';
const people = {name,age};
console.log(people); // {name:'yangf',age:''}

属性遍历

  • for...in

    • 包含可枚举的自身属性、继承属性
    • 不包含不可枚举属性、Symbol属性
  • Object.keys(obj)

    • 返回的是一个数组
    • 包含可枚举的自身属性
    • 不包含继承属性、不可枚举属性、Symbol属性
  • Object.getOwnPropertyNames(obj)

    • 返回的是数组
    • 包含所有的自身属性
    • 不包含继承属性、Symbol属性
  • Object.getOwnPropertySymbols(obj)

    • 返回数组
    • 只包含Symbol属性
  • Refect.ownKeys(obj)

    • 返回数组
    • 包含自身所有属性(可枚举、不可枚举、Symbol)
    • 不包含继承属性

根据需要获取对象的key值再获取相应的value值

// 定义一个拥有实例属性、继承属性的对象,其中包含Symbol属性、可枚举属性、不可枚举属性,覆盖全部的场景


// 父类
function People(name,age){
    this.name = name;
    this.age = age;
}


// 子类(成绩和年纪)
function Student(achievement,grade) {
    this.achievement = achievement;
    this.grade = grade;
    this[Symbol('school')] = '成都小学'
}


// 继承
Student.prototype = new People();


// 生成子类的实例
let student = new Student('85','三年级');


// 在实例上增加可枚举属性和不可枚举属性
Object.defineProperty(student,'sex',{
    configurable:true,
    enumerable:true,
    writable:true,
    value:'女'
});
Object.defineProperty(student,'class',{
    configurable:true,
    enumerable:false,
    writable:true,
    value:'二班'
});


/**
*描述属性是否可删除
*以及除value和writable特性外的其他特性是否可以被修改
*例外:可以把writable的状态由true改为false,但是无法由false改为true
*在writable: true的情况下,可以改变value的值
*默认false
*configurable:true  
*描述属性是否可枚举,默认false
*enumerable:true 
*描述属性是否可写,默认false
*writable:true 
*value:'女' 
**/
  • 实例属性:achievement、grade、Symbol('school')、sex
  • 继承属性:name、age
  • 可枚举属性:achievement、grade、sex
  • 不可枚举属性:class
  • Symbol属性:Symbol('school')

题外话Object.defineProperty()

  1. 作用:在一个对象上定义一个新属性或者修改一个已经存在的属性
  2. 语法:Object.defineProperty(obj,prop,desc)
    • obj:需要操作的对象
    • prop:需要修改或者新增的属性名
    • desc:一些描述
  3. desc描述:通过对象属性赋值的情况下,对象的属性可以修改、删除等操作;但是通过Object.defineProperty()定义属性,通过描述符的设置可以进行精准的控制对象属性
  4. 通过Object.defineProperty()定义对象属性有两种形式(数据描述符、存取描述符)
  5. 数据描述符:特有的两个属性:writable、value
  6. 存取描述符:是由一对getter、setter函数功能来描述的属性
for(let key in student){
    console.log(key);
}
// achievement grade sex name age


Object.keys(student);
// ["achievement", "grade", "sex"]


Object.getOwnPropertyNames(student)
// ["achievement", "grade", "sex", "class"]


Object.getOwnPropertySymbols(student)
// [Symbol(school)]


Reflect.ownKeys(student)
// ["achievement", "grade", "sex", "class", Symbol(school)]

Object.assign()函数

  • 特点及作用

    • 用于将一个或者多个对象的可枚举属性赋值给目标对象,然后返回目标对象
    • 当多个源对象具有相同的属性时,后者的属性值会覆盖前面的属性值
    • 无法复制对象的不可枚举属性和继承属性,可以复制可枚举的Symbol属性
let obja = {a:1}; // 目标对象
let objb = {b:2}; // 源对象1
let objc = {c:3}; // 源对象2
let objd = {c:4}; // 源对象3
console.log(Object.assign(obja,objb,objc,objd));
// {a:1,b:2,c:4}
  • 常见用途

    • 对象复制
      • 不是严格意义上的深拷贝
      • 如果属性是基本数据类型,则会复制它的值
      • 如果属性是引用数据类型,则会复制它的引用
const obja = {
    a:1
}
const objb = Object.assign({},obja);
objb.a = 2;
console.log(obja.a);// 1
  • 给对象添加属性
  • 给对象添加函数
  • 合并对象
// 传统写法
function People(name,age,sex){
    this.name = name;
    this.age = age;
    this.sex = sex;
};
People.prototype.getName = function() {
    return this.name;
}
// new
function People(name,age,sex){
    Object.assign(this,name,age,sex);
};    
Object.assign(People.prototype,{
    getName() {
        retun this.name;
    }
});
// 合并对象
let obja = {a:1};
let objb = {b:2};
const merge = (obja, ...objb)=>Object.assign({}, obja, ...objb);
console.log(merge(obja,objb));// {a: 1, b: 2}
  • 题外话:js深拷贝的方法
    • JSON.parse(JSON.stringify())
      • 非安全的JSON值会被丢弃,如undefined、function、symbol
      • set、map这种数据格式的对象,也不会被正确处理,而是处理成一个空对象
    • 递归
      • 安全可靠

Symbol类型

  • ES6之前,对象的属性名都是由字符串构成的

    • 假如一个对象继承了另一个对象的属性,我们又需要定义新的属性时,很容易造成属性名的冲突
      • 为此ES6引入了一种新的基本数据类型Symbol,它表示的是一个独一无二的值
      • 至此JavaScript中就一共存在6种基本数据类型
      • Undefined类型、Null类型、Boolean类型、String类型、Number类型、Symbol类型
  • 特性

    • 唯一性
      • 似于一种唯一标识性的ID,通过Symbol()函数来创建一个Symbol值
        • 任何通过Symbol()函数创建的Symbol值都是不相同的
      • 是一个新增的基本数据类型,所以通过typeof运算符得到的结果是“symbol”
      • 函数中可以传递一个字符串参数,表示对Symbol值的描述,主要是方便对不同Symbol值的区分
let a = Symbol();
let b = Symbol();
let c = Symbol('one');
let d = Symbol('one');
console.log(type of a); // symbol
console.log(a === b); // false
console.log(c === d); // false
  • 不能使用new操作符
    • Symbol函数并不是一个构造函数
  • 不能参与类型运算
    • 可以通过toString()函数显示地转换为字符串
    • 本身不能参与其他类型的运算
  • 可以创建同一个Symbol值
    • 使用Symbol.for()函数,函数接收一个字符串作为参数
    • 功能:
      • 先搜索有没有以该参数作为名称的Symbol值
      • 如果有,就返回这个Symbol值
      • 否则就新建并返回一个以该字符串为名称的Symbol值
    • 特点:
      • 使用Symbol.for()函数创建的变量会被登记在全家作用域中以便搜索
      • 函数调用不会立即返回一个新的值,而是先搜索该值是否存在
let symbol = Symbol('string');
symbol.toString();// Symbol(string)
symbol + '';
// Uncaught TypeError: Cannot convert a Symbol value to a string


let s1 = Symbol.for('string');
let s2 = Symbol.for('string');
s1 === s2; // true
  • 常见用途

    • 在对象中不需要对外访问的变量可以使用symbol
      • 因为Object.keys()函数或者for...in遍历不出来symbol属性
let people = {
    name:'yangf',
    age:18,
    [Symbol('card')]:'XXXX'
};
console.log(Object.keys(people));  // ['name', 'age']

因为Symbol属性不会出现在属性遍历的过程中,所以在使用JSON.stringify()函数将对象转换为JSON字符串时,Symbol值也不会出现在结果中