zoukankan      html  css  js  c++  java
  • JavaScript快速入门笔记(7):对象

    本系列随笔是本人的学习笔记,初学阶段难免会有理解不当之处,错误之处恳请指正。转载请注明出处:https://www.cnblogs.com/itwhite/p/12230148.html

    简介

    JavaScript 中没有类似于C++、Java等语言中所谓“类”的概念,JavaScript 是一门基于“对象”的语言(相对于C++、Java等基于“类”的语言来说):

    • 基于“类”的语言:对象是类的实例,一个类可以从另一个(或多个)类中继承,比如:“人类”继承“动物类”的特性;
    • 基于“对象”的语言:对象可以从其它对象直接继承,比如:Jack继承他父亲Smith的特性(脾气、性格、手艺等)。

    正是基于原型而非类的缘故,JavaScript 弱化了对象的类型,而强化了对象的功能。

    原理概述: 

    • 每一个函数对象都包含一个 prototype 属性(该属性值自身也是一个对象,其中默认包含一个 constructor 属性),通过构造函数创建的对象默认会继承该对象(该对象也称为“原型对象”)。基于此,我们可以通过为原型对象添加方法属性,从而让多个对象共享一组方法。
    • 所有对象默认都继承自 Object.prototype(其中有一个 constructor 属性哦,例外:Object.create(null)创建一个不继承自任何对象的对象),所以所有对象都默认包含一个 constructor 属性(继承而来的嘛)。

    对象

    JavaScript 中,对象是一组属性(包括属性名、属性值以及属性的读写特性等)的集合。因为没有“类”的概念,因此创建对象时也无需指定类名。

    JavaScript 中可以用以下三种方式创建对象:

    1. 直接使用字面值对象(看起来同JSON格式);
    2. 使用 new 运算符创建(new 后面跟一个构造函数调用,这种方式看起来很像C++、Java等语言中创建对象的方式);
    3. 使用 Object.create() 方法,其第一个参数指定对象的原型对象,第二个参数为可选参数,用以指定属性相关特性(同Object.defineProperties()的第二个参数)

    示例:

    var a = {};                 // #1,字面值创建方式,创建一个空对象
    var b = { x: 1, y: 2 };     // #2,字面值创建方式,创建一个非空对象
    var c = new Object();       // #3,通过 new 运算符创建,创建一个空对象,同 #1
    var d = new Date();         // #4,通过 new 运算符创建,创建一个日期对象
    var e = Object.create(Object.prototype); // #5,创建一个空对象,同 #1 和 #3
    var f = Object.create(b);   // #6,创建一个继承自 b 的对象
    f.x = 3;          // 并不会影响父对象 b 中的属性值
    console.log(b);   // { x: 1, y: 2 }
    console.log(f);   // { x: 3 },这里虽然没有输出 y 属性,但是通过 f.y 能访问 y 属性值
    console.log(f.y); // 2

    其中:

    • #1 和 #2 是通过字面值方式创建的,创建时无法指定父对象;
    • #3 和 #4 是通过构造函数创建的,对象的继承关系由构造函数的 prototype 属性决定(后面“继承”一节会详细描述);
    • #5 和 #6 是通过 Object.create() 方法创建的,创建时同时可以指定父对象。

    对象属性

    JavaScript 中,对象可以看做是“属性”的集合(这里的“属性”不仅包括属性名,还包括属性值和一组特性)。

    属性的特性可以表明该属性是否为只读属性、是否可枚举、是否可配置等。

    查看一个属性的特性,可以使用 Object.getOwnPropertyDescriptor() 方法,例如(下面的示例查看对象 o 中的 x 属于性的特性):

    var o = { x: 1, y: 2 };
    console.log(Object.getOwnPropertyDescriptor(o, "x")); // {value: 1, writable: true, enumerable: true, configurable: true}
    View Code

    修改某个属性的特性,可以使用 Object.defineProperty() 方法,例如:

    var o = { x: 1, y: 2 };
    console.log(Object.getOwnPropertyDescriptor(o, "x")); // {value: 1, writable: true, enumerable: true, configurable: true}
    Object.defineProperty(o, 'x', { writable: false });   // 这里可以同时修改多个特性,也可以单独修改某个特性
    console.log(Object.getOwnPropertyDescriptor(o, "x")); // {value: 1, writable: false, enumerable: true, configurable: true}
    View Code

    如果想要同时修改多个属性,请参考:Object.defineProperties()

    如果想要在创建对象的时候指定属性特性,可通过 Object.create()  方法的第二个参数进行设置。

     设置属性的 getter 和 setter 

    属性值可以是一个简单的数据,这样的属性称为“数据属性”。

    与之相对的,JavaScript 还支持为属性设置读写方法(getter和setter),这样的属性称为“存取器属性”。如果设置了 getter 表明该属性可读,如果设置了 setter 表明该属性可写,例如:

    "use strict"
    var c = {
        x: 3,
        y: 4,
        get r() { // r 设置了 getter 和 setter,所以它是个可读、可写属性
            return Math.sqrt(Math.pow(this.x, 2) + Math.pow(this.y, 2));
        },
        set r(v) {
            var ratio = v / this.r;
            this.x = this.x * ratio;
            this.y = this.y * ratio;
        },
        get s() { return Math.PI * Math.pow(this.r, 2); } // s 只设置了 getter,所以它是个只读属性
    };
    
    console.log(c.x, c.y, c.r, c.s); // 3 4 5 78.53981633974483
    c.r = 10;
    console.log(c.x, c.y, c.r, c.s); // 6 8 10 314.1592653589793
    c.s = 20; // Uncaught TypeError: Cannot set property s of #<Object> which has only a getter,只有在严格模式下,这里才会报错
    View Code

    注意:

    • “数据属性”包含 value、writable、enumerable、configurable 四个特性;
    • 而“存取器属性”因为 其值 和 writable 分别根据是否设置了 getter 和 setter 决定可否访问,因此它没有 value、writable 这两个特性,示例:
    console.log(Object.getOwnPropertyDescriptor(c, "x")); // {value: 3, writable: true, enumerable: true, configurable: true}
    console.log(Object.getOwnPropertyDescriptor(c, "r")); // {enumerable: true, configurable: true, get: ƒ, set: ƒ}
    console.log(Object.getOwnPropertyDescriptor(c, "s")); // {set: undefined, enumerable: true, configurable: true, get: ƒ}
    View Code

    使用 in 和 hasOwnProperty() 检测对象属性(是否存在)

    in 可以检测对象的自有属性和继承属性,而 hasOwnProperty() 仅可用于检测对象的自有属性,例如:

    var p = { x: 1, y: 2 };
    var c = Object.create(p);
    c.z = 3;
    console.log("x" in c); // true
    console.log("z" in c); // true
    console.log(c.hasOwnProperty("x")); // false
    console.log(c.hasOwnProperty("z")); // true
    View Code

    构造函数

    示例:

    function Person(name, age, gender) {
        this.name = name;
        this.age = age;
        this.gender = gender;
        this.show = function() {    // 所有通过 Person() 构造函数创建的对象都会新建一个 Function 属性
            console.log(this.name, this.age, this.gender);
        }
    }
    var jack = new Person("Jack", 23, "male");     // Person 明明是个函数,不过在某些文章里也被当做了一个“类”
    var linda = new Person("Linda", 19, "female"); // 由此说: jack 和 linda 都是 Person 的对象(或者说实例)
    jack.show();
    linda.show();
    alert(jack.show != linda.show); // true,但实际上,我们可能希望多个对象来共享同一个 show() 方法

    上面的示例中,jack 和 linda 同属一类对象,但是它们却没能共享同一个方法,通过函数的 prototype 属性我们可以实现对象属性的共享,例如:

    Person.prototype.show = function() {
        console.log(this.name, this.age, this.gender);
    }
    function Person(name, age, gender) { // 通过 Person 创建的对象会继承 Person.prototype 对象的属性哦
        this.name = name;
        this.age = age;
        this.gender = gender;
    }
    var jack = new Person("Jack", 23, "male");
    var linda = new Person("Linda", 19, "female");
    jack.show();
    linda.show();
    alert(jack.show === linda.show); // true,共享同一个 show() 方法
    View Code

     

    伪类:模拟其它语言中的类和继承

    模拟类的数据成员和函数成员(方法):

    • 普通态数据成员:通过普通对象属性模拟
    • 静态数据成员:通过构造函数的属性模拟
    • 普通函数成员:通过对象方法模拟
    • 静态函数成员:通过构造函数的方法属性模拟

    例如:

    Person.count = 0;       // 模拟静态数据成员
    function Person(name) { // 模拟“类”,Person 可以当做一个“类”
        this.name = name;   // 模拟普通数据成员
        Person.count++;
    }
    Person.prototype.sayHi = function() { // 模拟普通函数成员
        console.log("Hi " + this.name + "!");
    }
    Person.showCount = function() {       // 模拟静态函数成员
        console.log(Person.count);
    }
    var jack = new Person("Jack");
    var bob = new Person("Bob");
    var linda = new Person("Linda");
    jack.sayHi();       // 输出:Hi Jack!
    Person.showCount(); // 输出:3
    View Code

    模拟类的继承关系(例如:Dog继承Animal),请参考:阮一峰文章 Javascript面向对象编程(二):构造函数的继承

    参考:

    《JavaScript权威指南(第六版)》第6章、第9章

    《JavaScript高级程序设计(第3版)》第6章

    《JavaScript语言精粹》第3章、第5章

    阮一峰:Javascript继承机制的设计思想

    阮一峰:Javascript面向对象编程(二):构造函数的继承

    完。

  • 相关阅读:
    CVE-2020-0796 SMBv3 RCE漏洞检测+复现
    Tomcat文件包含漏洞的搭建与复现:CVE-2020-1938
    Web for pentester_writeup之XML attacks篇
    Web for pentester_writeup之LDAP attacks篇
    PhpStudy2018后门漏洞预警及漏洞复现&检测和执行POC脚本
    2016ACM/ICPC亚洲区沈阳站 E
    CodeForces 599C Day at the Beach(贪心)
    CodeForces 652C Foe Pairs(思维题)
    Codeforces 557D. Vitaly and Cycle(二分图判断)
    poj 1091跳蚤(容斥定理+质因子分解)
  • 原文地址:https://www.cnblogs.com/itwhite/p/12230148.html
Copyright © 2011-2022 走看看