JavaScript读书笔记(对象的总结)

JavaScript读书笔记(对象的总结)

一、创建对象的方式

  • 1、直接创建(常用)

    let obj = {
      name: '哈哈',
      gender: '男'
    }
    复制代码
  • 2、使用实例化对象的方式创建(比较少用)

    function Foo() {
      //
    }
    let foo = new Foo()
    复制代码
  • 3、内置对象的实例

    let x1 = new Object();    // A new Object object
    let x2 = new String();    // A new String object
    let x3 = new Number();    // A new Number object
    let x4 = new Boolean();   // A new Boolean object
    let x5 = new Array();     // A new Array object
    let x6 = new RegExp();    // A new RegExp object
    let x7 = new Function();  // A new Function object
    let x8 = new Date();      // A new Date object
    复制代码
  • 4、使用工厂方式创建(很少用)

    function CreatePerson(name, age, sex) {
      var obj = new Object();
      obj.name = name;
      obj.age = age;
      obj.sex = sex;
      obj.sayName = function () {
        return this.name;
      }
      return obj;
    }
    
    let p1 = new CreatePerson('哈哈', 20, '男');
    复制代码

二、一些基本的属性或者方法

  • 1、每一个对象都有链接着原型对象的隐藏属性__proto__

    var obj = {};
    obj.__proto__ === Object.prototype; //true
    复制代码
  • 2、判断一个对象是否包含一个属性

    const obj2 = {gender: '男'};
    
    console.log('gender' in obj2);
    console.log('name' in obj2);
    // 也可以使用hasOwnProperty
    console.log(obj2.hasOwnProperty('gender'));
    复制代码
  • 3、判断一个对象是否为空

    const obj2 = {gender: '男'};
    
    console.log(Object.keys(obj2));
    console.log(Object.values(obj2));
    复制代码
  • 4、删除一个属性

    const obj2 = {gender: '男', age: 20, name: '张三'};
    delete obj2.gender;
    console.log(obj2);
    // 也可以使用解析赋值的方式
    const {name, ...obj1} = obj2;
    console.log(obj1);
    复制代码
  • 4、Object.assign()的使用

    • 1.对象的合并
    • 2.对象的浅拷贝
    • 3.给对象新增属性/方法
    • 4.克隆对象(非深拷贝)
  • 5、判断是否为对象

    Object.prototype.toString.call(data).slice(8, -1)
    复制代码

三、关于对象中几个重要词的理解

  • 1、constructor查找该对象是由什么创建出来的

    let obj = {};
    let reg = new RegExp();
    let arry = new Array();
    let str = new String();
    let date = new Date();
    
    
    console.log(obj.constructor);
    console.log(reg.constructor);
    console.log(arry.constructor);
    console.log(str.constructor);
    console.log(date.constructor);
    // 继续往上面找
    console.log(Date.constructor);
    console.log(Function.constructor);
    复制代码
  • 2、instanceof判断构造函数是否在对象实例的原型链上

    Person.prototype.dance = function () {
      return 'dance function';
    }
    
    // 定义一个子类
    function Foo() {
    }
    
    Foo.prototype = new Person();
    let foo = new Foo();
    
    /**
     * 修改Foo原型的constructor
     * 关于defineProperty几个参数的介绍
     * 第一个参数:属性所在的对象,第二个参数:属性的名字,一个描素符对象 
     */
    Object.defineProperty(Foo.prototype, 'constructor', {
      writable: false,
      enumerable: false,
      value: Foo,
    });
    
    let foo1 = new Foo();
    console.log(foo1 instanceof Foo);
    console.log(foo1 instanceof Person);
    console.log(foo1 instanceof Object);
    复制代码
  • 3、hasOwnProperty()判断一个对象是否拥有该属性

    var obj = {name: '哈哈', gender: '男'};
    obj.hasOwnProperty('name');
    复制代码
  • 4、setPrototypeOf()修改对象的原型

    function Foo() {
    };
    const foo = new Foo();
    // 每一个对象都有constructor
    let bar = {};
    console.log(bar.constructor);
    // 修改bar的原型
    Object.setPrototypeOf(bar, foo);
    console.log(bar.constructor); // [Function: Foo]
    复制代码

四、配置对象的属性

  • 1、configurable: 如果为true表示可以修改与删除属性,如果为false就不能修改与删除

  • 2、enumerable: 如果为true表示为可枚举的可以使用for..in

  • 3、value:指定属性的值

  • 4、writable:如果为true表示可以通过赋值语句修改对象属性

  • 5、get定义gettter函数

  • 6、set定义setter函数

  • 7、测试案例

    let obj1 = {};
    obj1.name = '哈哈';
    obj1.gender = '男';
    
    // 定义第三个属性
    Object.defineProperty(obj1, 'address', {
      configurable: false,
      enumerable: true,
      value: '深圳',
      writable: false,
    });
    
    console.log(JSON.stringify(obj1));
    
    for (let key in obj1) {
      console.log(`${key}===${obj1[key]}`);
    }
    复制代码

五、对象的一些扩展

  • 1、对象的私有属性

    function Foo() {
      let name;
      // 定义一个set方法赋值
      this.setName = (newVal) => name = newVal;
      // 定义一个get方法取值
      this.getName = () => name;
    }
    let foo = new Foo();
    foo.setName('哈哈');
    console.log(foo.getName());
    复制代码
  • 2、对象的setget方法

    // 在对象中get与set只是在属性前面加上了一个关键词,但是依然是属性的方式调用
    const obj1 = {
      name: '哈哈',
    
      get getName() {
        console.log('get方法');
        return this.name;
      },
    
      set setName(newVal) {
        this.name = newVal;
      }
    };
    
    console.log(obj1.getName);
    // obj1.setName = '张三';
    // console.log(obj1.getName);
    console.log(obj1.name);
    复制代码
  • 3、使用defineProperty定义私有属性

    function Foo() {
      let _age = 0;
      // 扩展一个属性
      Object.defineProperty(this, 'age', {
        get() {
          return _age;
        },
        set(newVal) {
          _age = newVal;
        }
      })
    }
    
    let foo = new Foo();
    console.log(foo.age);
    foo.age = 10;
    console.log(foo.age);
    复制代码
  • 4、使用setget进行数据的校验

    function Foo() {
      let _age = 0;
    
      Object.defineProperty(this, 'age', {
        get() {
          return _age;
        },
        set(newVal) {
          if (/\d+/.test(newVal)) {
            _age = newVal;
          } else {
            throw new TypeError('必须是数字');
          }
        }
      })
    }
    
    try {
      let foo = new Foo();
      console.log(foo.age);
      foo.age = 10;
      console.log(foo.age);
      foo.age = '哈哈';
    } catch (e) {
      console.log(e);
    }
    复制代码

六、关于原型的理解

  • 1、关于使用new关键词创建对象所发生的事情

    • 创建一个新对象
    • 将构造函数的作用域赋值给新对象(this指向新对象)
    • 执行构造函数的代码
    • 返回新的对象
  • 2、为什么要使用构造函数的原型

    在使用构造函数创建对象的时候,每new一次就会创建一个对象,不同的实例的同名函数是不相等的,因此创建很多重复的代码(每次new一个构造函数,上面的构造函数就会执行一次,就会在内存中开辟一块空间,指向新的堆对象,这样内存消耗比较大),我们希望代码尽可能的复用,就需要原型

    // 普通的创建一个构造函数
    function Animal(name, age) {
      this.name = name;
      this.age = age;
      this.print = function() {
        console.log(`${this.name}====${this.age}`);
      }
    }
    // 使用原型
    function Animal(name, age) {
      this.name = name;
      this.age = age;
    }
    Animal.prototype.print = function() {
      console.log(`${this.name}====${this.age}`);
    }
    复制代码
  • 3、所有的对象都有一个constructor指向原型

  • 4、构造函数都有prototype指向原型

七、深入理解类的继承(ES6前的版本)

在面向对象开发中继承的概念是,新对象复用旧对象上的属性和方法(有点类似拷贝Object.assign),类似生活中子继承父的财产及工具的概念

  • 1、一个构造函数的原型指定另外一个构造函数

    function Person() {
    }
    
    // 定义原型
    Person.prototype.dance = function () {
      return 'dance function';
    };
    
    // 定义一个子类
    function Foo() {
    }
    Foo.prototype = Person.prototype;
    
    // 总结:采用这种方式来创建类的继承,只是地址指向(一个修改了,另外一个也会随之修改)
    复制代码
  • 2、一个构造函数的原型指定另外一个函数的实例对象

    function Person() {
    }
    
    // 定义原型
    Person.prototype.dance = function () {
      return 'dance function';
    };
    
    // 定义一个子类
    function Foo() {
    }
    
    // Foo构造函数的原型指向Person的实例对象
    Foo.prototype = new Person();
    let foo = new Foo();
    console.log(foo.dance());
    // 这样继承的方式会造成Foo的原型丢失,直接指定了Person
    console.log(foo.constructor);
    console.log(foo instanceof Foo);
    
    // 总结:采用这种方式实现继承:造成Foo的原型丢失,直接指定了Person
    复制代码
  • 3、修正方式二中constructor的指向

    function Person() {
    }
    Person.prototype.dance = function () {
      return 'dance function';
    }
    // 定义一个子类
    function Foo() {
    }
    Foo.prototype = new Person();
    let foo = new Foo();
    console.log(foo.constructor);
    // 修改Foo原型的constructor
    Object.defineProperty(Foo.prototype, 'constructor', {
      writable: false,
      enumerable: false,
      value: Foo,
    });
    let foo1 = new Foo();
    console.log(foo1.constructor);
    
    // 总结:修正`constructor`的指向
    复制代码

八、采用class的方式创建类

  • 1、创建一个类

    class Person {
      constructor(name, age) {
        this.name = name;
        this.age = age;
      }
    
      // 普通方法
      say() {
        return 'say...';
      }
    
      // 静态方法
      static talk() {
        console.log(this);
        return '我是静态方法';
      }
    }
    
    let p = new Person('哈哈', 20);
    console.log(Person.talk());
    复制代码
  • 2、实现类的继承

    class Animal {
      constructor(name) {
        this.name = name;
      }
    
      call() {
        return '在叫';
      }
    }
    
    class Dog extends Animal {
      constructor(name, age) {
        super(name);
        this.age = age;
      }
    
      // 重写父类的方法
      call() {
        return `${this.name}在叫`;
      }
    }
    
    let dog = new Dog('大黄狗', 3);
    
    console.log(dog.call());
    复制代码
  • 3、使用setget方法

    class Person {
      constructor() {
        this.name = '哈哈';
      }
    
      set setName(newVal) {
        this.name = newVal;
      }
    
      get getName() {
        return this.name;
      }
    }
    
    let p = new Person();
    console.log(p.getName);
    p.setName = '张三';
    console.log(p.getName);
    复制代码

九、Proxy的使用


ProxyES6中新增的对象,使用方式Proxy(目标对象,代理的对象)

主要有如下属性

  • get(target, propKey, receiver):拦截对象属性的读取,比如√proxy.foo和proxy['foo']√。

  • set(target, propKey, value, receiver):拦截对象属性的设置,比如proxy.foo = vproxy['foo'] = v,返回一个布尔值。

  • has(target, propKey):拦截propKey in proxy的操作,返回一个布尔值。

  • deleteProperty(target, propKey):拦截delete proxy[propKey]的操作,返回一个布尔值。

  • ownKeys(target):拦截Object.getOwnPropertyNames(proxy)、Object.getOwnPropertySymbols(proxy)、Object.keys(proxy)、for...in循环,返回一个数组。该方法返回目标对象所有自身的属性的属性名,而Object.keys()的返回结果仅包括目标对象自身的可遍历属性。

  • getOwnPropertyDescriptor(target, propKey):拦截Object.getOwnPropertyDescriptor(proxy, propKey),返回属性的描述对象。

  • defineProperty(target, propKey, propDesc):拦截Object.defineProperty(proxy, propKey, propDesc)、Object.defineProperties(proxy, propDescs),返回一个布尔值。

  • preventExtensions(target):拦截Object.preventExtensions(proxy)`,返回一个布尔值。

  • getPrototypeOf(target):拦截Object.getPrototypeOf(proxy)`,返回一个对象。

  • isExtensible(target):拦截Object.isExtensible(proxy),返回一个布尔值。

  • setPrototypeOf(target, proto):拦截Object.setPrototypeOf(proxy, proto),返回一个布尔值。如果目标对象是函数,那么还有两种额外操作可以拦截。

  • apply(target, object, args):拦截 Proxy 实例作为函数调用的操作,比如proxy(...args)、proxy.call(object, ...args)、proxy.apply(...)

  • construct(target, args):拦截 Proxy 实例作为构造函数调用的操作,比如new proxy(...args)

  • 1、使用案例

    let targetObj = {name: '哈哈'};
    
    const proxy = new Proxy(targetObj, {
      set(target, key, val) {
        console.log(target);
        console.log(key);
        console.log(val);
        target[key] = val;
      },
      get(target, key) {
        console.log(target);
        console.log(key);
        return key in target ? target[key] : '不存在这个key';
      },
      // 使用in的时候调用
      has(target, key) {
        console.log(target, key)
        if (target.hasOwnProperty(key)) {
          return true;
        } else {
          return false;
        }
      },
      deleteProperty(target, key) {
        if (target.hasOwnProperty(key)) {
          return true;
        } else {
          return false;
        }
      }
    });
    复制代码
  • 2、代理方法

    let targetObj = function () {
      return '目标函数';
    };
    
    let proxy = new Proxy(targetObj, {
      apply(target, ctx, args) {
        console.log(target());
        console.log(ctx);
        console.log(args);
        return 'apply 函数';
      }
    });
    
    proxy(12, 20);
    复制代码
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值