前端基础(三十四):你不知道的JavaScript - 对象

语法

// 文字形式
var obj1 = {
    
     name: 'Lee' };
// 构造形式
var obj2 = new Object();
obj2.name = 'Lee';

类型

  • 六种主要类型
    • string number boolean null undefined object
  • 注意:
    • 其中 string number boolean null undefined 是基本类型,其本身并不是对象
    • null 有时会被当做一种对象类型,但这其实是语言的一个bug,即对 null 执行 typeof null 时返回字符串 "object",但实际上 null 是基本类型。
    • 错误说法 "JavaScript中万物皆对象"
  • 对象子类型
    • 函数 Function(即可调用的对象,本质上和对象一样,只是可以调用)
    • 数组 Array

内置对象

内置对象:

对象的子类型,有的子类型名字看起来和基本类型一样,不过实际上他们的关系更为复杂。

实际上是一些内置函数,可以当作构造函数来使用,用来构造一个对象子类型的心对象。

  • 如:String Number Boolean Object Function Array Date RegExp Error
    var str = "ProsperLee";
    console.log(typeof str);                // "string"  
    console.log(str instanceof String);     // false
    console.log(Object.prototype.toString.call(str));       // "[object String]"
    
    var strObj = new String("ProsperLee");
    console.log(typeof strObj);             // "object"
    console.log(strObj instanceof String);  // true
    console.log(Object.prototype.toString.call(strObj));    // "[object String]"
    
    // 语言自动把字面量str转换成了String对象,所以才可以访问的属性和方法
    console.log(str.length); // 10
    console.log(new String(str).length); // 10
    console.log(42.359.toFixed(2)); // "42.36"
    console.log(new Number(42.359).toFixed(2)); // "42.36"
    
  • null undefined 没有对应的构造形式,只有文字形式。
    // new null // error  null is not a constructor
    // new undefined // error  undefined is not a constructor
    
  • Date 只有构造形式,没有文字形式。
  • Object Array Function RegExp 无论使用文字形式还是构造形式,都是对象,不是字面量。
  • Error 一般是在抛出异常时被自动创建,也可以使用 new Error(...) 这种构造形式创建。

内容

内容:对象内部存储的属性。

这些属性名称存储在对象容器内,而属性的值其实不是存在对象容器内,属性名称就像指针(引用)一样指向真正值存储的位置。

var obj = {
    
    name: 'Lee', 'abc-def': 123};
// 属性访问(必须满足标识符规范进行使用)
obj.name; 
// 键访问(可以接受任意UTF-8/Unicode字符串作为属性名)
obj['name']; 
obj['abc-def'];
  • 在对象中,属性名永远都是字符串,即使使用除字符串以外的其他值作为属性,也会被转换为字符串。
  • 数组下标是数字。
    var obj = {
          
           1: 'abc', true: '真', [this]: 'Hello' };
    var list = ['abc'];
    
    console.log(obj['1'], obj[1]);                                  // abc abc
    console.log(obj['true'], obj[true]);                            // 真 真
    console.log(obj['this'], obj[this], obj['[object Window]']);    // undefined Hello Hello 
    console.log(list[0], list['0']);                                // abc abc
    

可计算属性

// Symbol基础数据类型,包含一个不透明且无法预测的值(从技术层面就是一个字符串)
var obj = {
    
    
    ['a' + 'b']: 'Hello',
    [Symbol()]: 'Hello'
}
console.log(obj.ab); // Hello
console.log(obj[Symbol()]); // undefined
console.log(obj['Symbol()']); // undefined

属性与方法

叫法:

从技术角度说函数永远不会“属于”一个对象,所以把对象内部引用的函数称为“方法”不妥。

即使在对象的文字形式中声明一个函数表达式,这个函数也不“属于”这个对象,只能算作是对于相同函数对象的多个引用。

var obj = {
    
    
    foo: function (){
    
    
        console.log('foo');
    }
}

数组

  • 数组的下标是数字
  • 数组也是对象
  • 数组也可以 添加、访问 属性
  • 如果添加的属性“看起来像”一个数字,那么会自动处理成下标
var list = [1, 2, 3, 4];
console.log(list[2]);       // 3
console.log(list.length);   // 4
list.name = 'Lee';
console.log(list.name);     // 'Lee'
list['1'] = 'abc';
console.log(list);          // [1, 'abc', 3, 4, name: 'Lee']

复制对象

深拷贝 & 浅拷贝

参考地址: https://blog.csdn.net/weixin_43526371/article/details/107361037

属性描述符

  • Object.getOwnPropertyDescriptor
    var obj = {
          
           name: 'Lee' };
    /**
     * 返回指定对象上一个自有属性对应的属性描述符
     * {
     *   value: 'Lee',          // 数据值
     *   writable: true,        // 可写
     *   enumerable: true,      // 可枚举
     *   configurable: true     // 可配置
     * }
     */ 
    console.log(Object.getOwnPropertyDescriptor(obj, 'name')); 
    
  • Object.defineProperty(value,writable,configurable,enumerable)
    var obj = {
          
          };
    Object.defineProperty(obj, 'name', {
          
          
        value: 'Lee',
        writable: false,
        configurable: false,
        enumerable: false
    });
    console.log(obj);       // {name: 'Lee'}
    
    // 【writable】
    obj.name = 'Tom';
    console.log(obj);       // {name: 'Lee'}
    
    // 【configurable】
    /**
     * Error: Cannot redefine property: name
     *      Object.defineProperty(obj, 'name', {
     *          value: 'Tom',
     *          writable: false, // true false
     *          configurable: false, // true false
     *          enumerable: false // true false
     *      });
     */
    delete obj.name;
    console.log(obj); // {name: 'Lee'}
    
    // 【enumerable】
    for (const key in obj) {
          
           // 执行不到遍历,因为只有一个key并且不可枚举
        console.log(key);
    }
    

不变性

  • 定义常量 defineProperty
    var obj = {
          
          };
    Object.defineProperty(obj, 'name', {
          
          
        value: 'Lee',
        writable: false,
        configurable: false,
    });
    
  • 禁止扩展 preventExtensions
    var obj = {
          
           name: 'Lee' };
    Object.preventExtensions(obj);
    obj.age = 25; // 严格模式下报错
    console.log(obj);
    
  • 密封 seal
    • Object.seal(..) 会创建一个“密封”的对象,这个方法实际上会在一个现有对象上调用 Object.preventExtensions(..) 并把所有现有属性标记为 configurable:false
    • 密封之后不仅不能添加新属性,也不能重新配置或者删除任何现有属性(虽然可以 修改属性的值)。
    var obj = {
          
           name: 'Lee', list: [1, 2, {
          
           age: 25 }], obj: {
          
           name: 'Tom' } };
    Object.seal(obj);
    // { value: 'Lee',       writable: true, enumerable: true, configurable: false }
    console.log(Object.getOwnPropertyDescriptor(obj, 'name'));
    // { value: Array(3),    writable: true, enumerable: true, configurable: false }
    console.log(Object.getOwnPropertyDescriptor(obj, 'list'));
    // { value: {…},         writable: true, enumerable: true, configurable: false }
    console.log(Object.getOwnPropertyDescriptor(obj, 'obj'));
    // { value: 'Tom',       writable: true, enumerable: true, configurable: true }
    console.log(Object.getOwnPropertyDescriptor(obj.obj, 'name'));
    // { value: 25,          writable: true, enumerable: true, configurable: true }
    console.log(Object.getOwnPropertyDescriptor(obj.list[2], 'age')); 
    
  • 冻结 freeze
    • Object.freeze(..) 会创建一个冻结对象,这个方法实际上会在一个现有对象上调用 Object.seal(..) 并把所有“数据访问”属性标记为 writable:false,这样就无法修改它们的值。
    var obj = {
          
           name: 'Lee', list: [1, 2, {
          
           age: 25 }], obj: {
          
           name: 'Tom' } };
    Object.freeze(obj);
    // { value: 'Lee',       writable: false,   enumerable: true, configurable: false }
    console.log(Object.getOwnPropertyDescriptor(obj, 'name'));
    // { value: Array(3),    writable: false,   enumerable: true, configurable: false }
    console.log(Object.getOwnPropertyDescriptor(obj, 'list'));
    // { value: {…},         writable: false,   enumerable: true, configurable: false }
    console.log(Object.getOwnPropertyDescriptor(obj, 'obj'));
    // { value: 'Tom',       writable: true,    enumerable: true, configurable: true }
    console.log(Object.getOwnPropertyDescriptor(obj.obj, 'name'));
    // { value: 25,          writable: true,    enumerable: true, configurable: true }
    console.log(Object.getOwnPropertyDescriptor(obj.list[2], 'age')); 
    

[[Get]][[Put]] & GetterSetter

var obj = {
    
     name: 'Lee' };

var name = 'Lee';
Object.defineProperty(obj, 'name', {
    
    
    // [[Get]] Getter
    get(){
    
    
        console.log(`[[Get]] Getter ---> ${
      
      name}`);
        return name;
    },
    // [[Put]] Setter
    set(value){
    
    
        console.log(`[[Put]] Setter ---> ${
      
      value}`);
        name = value;
    }
})
console.log(obj);           // { name: (...) }
console.log(obj.name);      // [[Get]] Getter ---> Lee Lee
obj.name = 'Tom';           // [[Put]] Setter ---> Tom

存在性

  • in & hasOwnProperty
    function Person() {
          
          
        this.name = 'Lee';
    }
    Person.prototype.desc = "Hello World";
    
    var person = new Person();
    
    console.log('name' in person); // true
    console.log('desc' in person); // true
    console.log('age' in person);  // false
    
    console.log(person.hasOwnProperty('name'));    // true
    console.log(person.hasOwnProperty('desc'));    // false
    console.log(person.hasOwnProperty('age'));     // false
    
  • 判断是否可枚举
    var obj = {
          
           name: 'Lee', age: 25 };
    Object.defineProperty(obj, 'name', {
          
          
        enumerable: false
    })
    Object.defineProperty(obj, 'age', {
          
          
        enumerable: true
    })
    console.log(obj.propertyIsEnumerable('name'));  // false
    console.log(obj.propertyIsEnumerable('age'));   // true
    
  • Object.keys 包含所有可枚举属性的数组
    var obj = {
          
           name: 'Lee', age: 25 };
    Object.defineProperty(obj, 'name', {
          
          
        enumerable: false
    })
    Object.defineProperty(obj, 'age', {
          
          
        enumerable: true
    })
    console.log(Object.keys(obj)); // ['age']
    
  • Object.getOwnPropertyNames 包含所有属性的数组
    var obj = {
          
           name: 'Lee', age: 25 };
    Object.defineProperty(obj, 'name', {
          
          
        enumerable: false
    })
    Object.defineProperty(obj, 'age', {
          
          
        enumerable: true
    })
    console.log(Object.getOwnPropertyNames(obj)); // ['name', 'age']
    

遍历

  • for ... in ... 遍历可枚举属性(遍历的是属性,并非遍历值)
    • 同数组的for循环,实际遍历的是下标
    
    var obj = {
          
           name: 'Lee', age: 25 };
    Object.defineProperty(obj, 'name', {
          
          
        enumerable: false
    })
    Object.defineProperty(obj, 'age', {
          
          
        enumerable: true
    })
    
    for (const key in obj) {
          
          
        console.log(key); // age
    }
    
  • 遍历数组的辅助迭代器
  • for ... of ... 数组遍历值
    /**
     * // obj is not iterable
     * var obj = { name: 'Lee', age: 25, desc: '独行者' };
     * for (const item of obj) { console.log(item); }
     */
    
    var list = ['Lee', 'Tom', 'Lucy'];
    for (const item of list) {
          
          
        console.log(item); // Lee Tom Lucy
    }
    
    • 原理:for..of 循环首先会向被访问对象请求一个迭代器对象,然后通过调用迭代器对象的 next() 方法来遍历所有返回值
      var list = ['Lee', 'Tom', 'Lucy'];
      
      var item = list[Symbol.iterator]();
      
      console.log(list); // ['Lee', 'Tom', 'Lucy']
      
      console.log(item); // Array Iterator {}
      
      console.log(item.next()); // {value: 'Lee', done: false}
      console.log(item.next()); // {value: 'Tom', done: false}
      console.log(item.next()); // {value: 'Lucy', done: false}
      console.log(item.next()); // {value: undefined, done: true}
      
  • for ... of ... 对象遍历值
    var obj = {
          
           name: 'Lee', age: 25, desc: '独行者' };
    
    Object.defineProperty(obj, Symbol.iterator, {
          
          
        enumerable: false, 
        writable: false, 
        configurable: true,
        value: function () {
          
          
            var o = this;
            var index = 0;
            var keys = Object.keys(o);
            return {
          
          
                next: function () {
          
          
                    return {
          
          
                        value: o[keys[index++]],
                        done: index > keys.length
                    }
                }
            }
        }
    })
    
    console.log(obj); // {name: 'Lee', age: 25, desc: '独行者', Symbol(Symbol.iterator): ƒ}
    
    for (const item of obj) {
          
          
        console.log(item); // Lee 25 独行者
    }
    
    var item = obj[Symbol.iterator]();
    
    console.log(item); // {next: ƒ}
    
    console.log(item.next()); // {value: 'Lee', done: false}
    console.log(item.next()); // {value: 25, done: false}
    console.log(item.next()); // {value: '独行者', done: false}
    console.log(item.next()); // {value: undefined, done: true}
    
  • 迭代器生成‘无限个’随机数的遍历
    // 生成无限个随机数
    var randoms = {
          
          
        [Symbol.iterator]: function () {
          
          
            return {
          
          
                next: function () {
          
          
                    return {
          
           value: Math.random() };
                }
            };
        }
    };
    
    // for of 会自动调用执行函数,并返回value
    for (const iterator of randoms) {
          
          
        console.log(iterator); // 0.4844446296389606  0.7078310386150104
        // 当生成的值大于0.5跳出遍历
        if(iterator > 0.5) break; 
    }
    
    var item = randoms[Symbol.iterator]();
    console.log(item.next()); // {value: 0.713562025169989}
    

猜你喜欢

转载自blog.csdn.net/weixin_43526371/article/details/125102377