JavaScript讀書筆記(對象的總結)

JavaScript讀書筆記(對象的總結)

1、建立對象的方式

  • 一、直接建立(經常使用)數組

    let obj = {
      name: '哈哈',
      gender: '男'
    }
    複製代碼
  • 二、使用實例化對象的方式建立(比較少用)app

    function Foo() {
      //
    }
    let foo = new Foo()
    複製代碼
  • 三、內置對象的實例函數

    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
    複製代碼
  • 四、使用工廠方式建立(不多用)工具

    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, '男');
    複製代碼

2、一些基本的屬性或者方法

  • 一、每個對象都有連接着原型對象的隱藏屬性__proto__測試

    var obj = {};
    obj.__proto__ === Object.prototype; //true
    複製代碼
  • 二、判斷一個對象是否包含一個屬性ui

    const obj2 = {gender: '男'};
    
    console.log('gender' in obj2);
    console.log('name' in obj2);
    // 也可使用hasOwnProperty
    console.log(obj2.hasOwnProperty('gender'));
    複製代碼
  • 三、判斷一個對象是否爲空this

    const obj2 = {gender: '男'};
    
    console.log(Object.keys(obj2));
    console.log(Object.values(obj2));
    複製代碼
  • 四、刪除一個屬性spa

    const obj2 = {gender: '男', age: 20, name: '張三'};
    delete obj2.gender;
    console.log(obj2);
    // 也可使用解析賦值的方式
    const {name, ...obj1} = obj2;
    console.log(obj1);
    複製代碼
  • 四、Object.assign()的使用prototype

    • 1.對象的合併
    • 2.對象的淺拷貝
    • 3.給對象新增屬性/方法
    • 4.克隆對象(非深拷貝)
  • 五、判斷是否爲對象代理

    Object.prototype.toString.call(data).slice(8, -1)
    複製代碼

3、關於對象中幾個重要詞的理解

  • 一、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);
    複製代碼
  • 二、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);
    複製代碼
  • 三、hasOwnProperty()判斷一個對象是否擁有該屬性

    var obj = {name: '哈哈', gender: '男'};
    obj.hasOwnProperty('name');
    複製代碼
  • 四、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]
    複製代碼

4、配置對象的屬性

  • 一、configurable: 若是爲true表示能夠修改與刪除屬性,若是爲false就不能修改與刪除

  • 二、enumerable: 若是爲true表示爲可枚舉的可使用for..in

  • 三、value:指定屬性的值

  • 四、writable:若是爲true表示能夠經過賦值語句修改對象屬性

  • 五、get定義gettter函數

  • 六、set定義setter函數

  • 七、測試案例

    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]}`);
    }
    複製代碼

5、對象的一些擴展

  • 一、對象的私有屬性

    function Foo() {
      let name;
      // 定義一個set方法賦值
      this.setName = (newVal) => name = newVal;
      // 定義一個get方法取值
      this.getName = () => name;
    }
    let foo = new Foo();
    foo.setName('哈哈');
    console.log(foo.getName());
    複製代碼
  • 二、對象的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);
    複製代碼
  • 三、使用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);
    複製代碼
  • 四、使用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);
    }
    複製代碼

6、關於原型的理解

  • 一、關於使用new關鍵詞建立對象所發生的事情

    • 建立一個新對象
    • 將構造函數的做用域賦值給新對象(this指向新對象)
    • 執行構造函數的代碼
    • 返回新的對象
  • 二、爲何要使用構造函數的原型

    在使用構造函數建立對象的時候,每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}`);
    }
    複製代碼
  • 三、全部的對象都有一個constructor指向原型

  • 四、構造函數都有prototype指向原型

7、深刻理解類的繼承(ES6前的版本)

在面向對象開發中繼承的概念是,新對象複用舊對象上的屬性和方法(有點相似拷貝Object.assign),相似生活中子繼承父的財產及工具的概念

  • 一、一個構造函數的原型指定另一個構造函數

    function Person() {
    }
    
    // 定義原型
    Person.prototype.dance = function () {
      return 'dance function';
    };
    
    // 定義一個子類
    function Foo() {
    }
    Foo.prototype = Person.prototype;
    
    // 總結:採用這種方式來建立類的繼承,只是地址指向(一個修改了,另一個也會隨之修改)
    複製代碼
  • 二、一個構造函數的原型指定另一個函數的實例對象

    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
    複製代碼
  • 三、修正方式二中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`的指向
    複製代碼

8、採用class的方式建立類

  • 一、建立一個類

    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());
    複製代碼
  • 二、實現類的繼承

    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());
    複製代碼
  • 三、使用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);
    複製代碼

9、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)

  • 一、使用案例

    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;
        }
      }
    });
    複製代碼
  • 二、代理方法

    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);
    複製代碼
相關文章
相關標籤/搜索