• 【ES新特性三】Object 原型、原型链相关方法


    一、Object 原型、原型链相关方法

    1.1 静态方法(Object 调用):

    • Object.setPrototypeOf(obj,prototype) 方法用于设置某个实例对象的原型(可以是null,也可以是一个对象)

    • Object.getPrototypeOf(obj)

    ​ 注:ES5之前,实例化对象通过 __proto__ 属性来获取原型对象;ES5中,不推荐以 __ 开头的语句,所以提供了 getPropertyOf() 方法用于获取对象的原型对象

    原生JavaScipt案例合集
    JavaScript +DOM基础
    JavaScript 基础到高级
    Canvas游戏开发

    1.2 原型方法(实例调用)

    此方法为 Object.prototype 原型方法,Object.prototype 作为任意对象在原型链上的顶级原型对象,在 JS 中定义的任意一个对象(自定义对象、数组对象等都可以调用子方法)。

    • isPrototypeOf() 方法用于测试一个对象是否存在于另一个对象的原型链上。
    • hasOwnProperty() 方法会返回一个布尔值,指示对象自身属性中是否具有指定的属性(也就是,是否有指定的键)。
    
    
    • 111
    • 222
    • 333
    • 444
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • __proto__ 属性是一个访问器属性(一个 getter 函数和一个 setter 函数), 暴露了通过它访问的对象的内部[[Prototype]] (一个对象或 null)。proto 属性也可以在对象文字定义中使用对象 [[Prototype]] 来创建,作为Object.create() 的一个替代。

    1.3 操作属性的方法(Object 调用)

    **Object.getOwnPropertyNames()**方法返回一个由指定对象的所有自身属性的属性名(包括不可枚举属性但不包括 Symbol 值作为名称的属性)组成的数组。

    Object.getOwnPropertySymbols() 方法返回一个给定对象自身的所有 Symbol 属性的数组。

    Object.hasOwn() 如果指定的对象自身有指定的属性,则返回 true。如果属性是继承的或者不存在,该方法返回 false

    备注: Object.hasOwn() 旨在取代 Object.hasOwnProperty()

    // 类数组对象
    var obj = { 0: "a", 1: "b", 2: "c"};
    console.log(Object.getOwnPropertyNames(obj).sort()); // ["0", "1", "2"]
    
    // 数组对象
    var arr = ["a", "b", "c"];
    console.log(Object.getOwnPropertyNames(arr).sort()); // ["0", "1", "2", "length"]
    
    // Symbols 
    var obj = {};
    var a = Symbol("a");
    var b = Symbol.for("b");
    obj[a] = "localSymbol";
    obj[b] = "globalSymbol";
    var objectSymbols = Object.getOwnPropertySymbols(obj);
    
    // hasOwn()
    const example = {};
    Object.hasOwn(example, 'prop');   // false - 'prop' has not been defined
    
    example.prop = 'exists';
    Object.hasOwn(example, 'prop');   // true - 'prop' has been defined
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    二、Object 相关方法

    2.1 Object.preventExtensions() 取消对象可拓展性

    Object.preventExtensions(obj) 方法用于取消对象的可拓展性

    Object.isExtensible(obj) 判断对象是否取消了可拓展性。返回值是一个布尔值,返回true对象可以拓展属性 返回false对象不可拓展属性

    注:当一个对象被取消了可拓展性之后,对象不能再拓展属性,但是可以修改和删除属性

    var obj = {
        a:1,
        b:2
    }
    
    console.log("取消对象可拓展性前对象:",obj);
    
    // 取消对象拓展
    Object.preventExtensions(obj);
    
    // 拓展属性
    obj.c = 3;
    
    // 删除属性
    delete obj.a;
    
    // 修改属性值
    obj.b = 22;
    
    // 判断对象是否可拓展
    console.log(Object.isExtensible(obj));//true
    
    console.log("取消对象可拓展性后并操作属性后的对象:",obj);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    2.2 Object.seal() 封闭对象

    Object.seal(obj) 封闭对象的属性

    Object.isSealed(obj) 判断对象属性是否被封闭。返回值布尔值,返回true 对象被封闭 返回false对象没有被封闭

    注:当一个对象被封闭后,不能拓展和删除属性,但是可以修改属性。

    var obj = {
        a:1,
        b:2
    }
    
    console.log("封闭前对象:",obj);
    
    // 封闭对象
    Object.seal(obj);
    
    // 拓展属性
    obj.c = 3;
    
    // 删除属性
    delete obj.a;
    
    // 修改属性值
    obj.b = 22;
    
    // 判断对象是否被封闭
    console.log(Object.isSealed(obj));//true
    
    console.log("封闭后并操作属性后的对象:",obj);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    2.3 Object.freeze() 冻结对象

    Object.freeze(obj) 方法用于冻结对象的属性

    Object.isFrozen(obj) 方法用于判断对象属性是否被冻结。返回值 一个布尔值 返回true对象被冻结,返回false对象没有被冻结

    注:当一个对象被冻结后,不能拓展、修改和删除对象的属性

    var obj = {
        a:1,
        b:2
    }
    
    console.log("冻结前对象:",obj);
    
    // 冻结对象
    Object.freeze(obj);
    
    // 拓展属性
    obj.c = 3;
    
    // 删除属性
    delete obj.a;
    
    // 修改属性值
    obj.b = 22;
    
    // 判断对象是否被冻结
    console.log(Object.isFrozen(obj));//true
    
    console.log("冻结后并操作属性后的对象:",obj);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    2.4 Object.create() 创建对象

    Object.create(proto,[ propertiesObject ]) 方法使用现有对象作为新创建的对象的原型来创建新对象。

    • 参数

      • proto 该对象应该是新创建对象的原型。可以是null
      • propertiesObject 可选的。指定要添加到新创建的对象的属性描述符,以及相应的属性名称。这些属性对应于的第二个参数Object.defineProperties()对象属性的特性。
    • 返回值 具有指定原型对象和属性的新对象。

    // 学过的创建对象的方式
    // var obj = {};
    // var obj1 = new Object();
    // var obj2 = Object();
    
    // ES5新增创建一个空对象  第一个参数新创建对象的原型设置为null
    // var obj3 = Object.create(null);
    // console.log(obj3)
    
    //使用Object.create() 来创建一个对象,第一个参数原型对象为一个常量对象
    // var obj = Object.create({
    //     sayHi:function(){
    //         console.log("Hello");
    //     }
    // })
    
    // 第一个参数为空,第二个参数为 要创建对象的空对象的属性特性描述(类似于Object.defineProperty()设置的对象特性)
    // var obj = Object.create(null,{
    //     name:{
    //         // 配置值
    //         value:"张三",
    //         // 配置是否可写
    //         writable:false,
    //         // 配置是否可枚举
    //         enumerable:false
    //     },
    //     age:{
    //         // 配置值
    //         value:10,
    //          // 配置是否可写
    //          writable:false,
    //     }
    // })
    // console.log(obj);
    // console.log(obj.name);
    // // 通过这种对象特性的方式创建的对象,默认属性不能被删除 修改
    // obj.name = "haha";
    // delete obj.age;
    // console.log(obj);
    // console.log(obj.name);
    
    
    // 创建一个对象,并能继承另外一个对象的方法;将一个对象作为另外一个对象的原型
    // 创建需要的原型对象
    var prototype = {
        sayHi:function(){
            console.log("Hello");
        }
    }
    
    // 创建需要的特性属性对象
    var options = {
        name:{
            // 配置值
            value:"张三",
            // 配置是否可写
            writable:false,
            // 配置是否可枚举
            enumerable:false
        },
        age:{
            // 配置值
            value:10,
             // 配置是否可写
             writable:false,
        }
    }
    
    // 两者组合创建对象
    var obj = Object.create(prototype,options);
    
    console.log(obj)//查看原型
    obj.sayHi();
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73

    2.5 Object.create()完善继承

    // 定义父类
    function People(name,sex,age){
        this.name = name;
        this.sex = sex;
        this.age = age;
    }
    
    // 原型中定义方法
    People.prototype.sayHi = function(){
        return "姓名:" + this.name + ",性别:" + this.sex + ",年龄:" + this.age;
    }
    
    People.prototype.sayHello = function(){
        return "Hello";
    }
    
    // 定义子类
    function Student(name,sex,age,score){
        // applay实现继承(改变调用对象
        People.apply(this,arguments);
    
        // 定义子类拓展的属性
        this.score = score;
    }
    
    // var p = new People();
    // delete p.name;
    // delete p.sex;
    // delete p.age;
    
    // 子类继承父类中的方法 必须要使用原型继承 将子类的原型指向父类的实例
    // Student.prototype = new Student();
    
    // 使用Object.create()优化继承
    Student.prototype = Object.create(People.prototype);
    
    // 原型继承会造成结构的紊乱,将原型对象的构造函数手动改回到Student
    Student.prototype.constructor = Student;
    
    // 实例化对象
    var s = new Student("张三","男",23,100);
    
    // 调用父类原型中的方法
    console.log(s.sayHi());
    
    /*
    * 原型继承,子类的原型就是父类的实例,这种方式会在子类的原型中多出几个无用的属性
    * 此时,会在子类的原型中多出几个属性:name:undefined,age:undifined,sex:undefined
    * 如果不考虑寄生组合继承这种方式进行优化,ES5还提供了Object.create()方法来优化
    **/
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50

    2.6 封装实现Object.create()方法

    // 定义父类
    function People(name,sex,age){
        this.name = name;
        this.sex = sex;
        this.age = age;
    }
    
    // 原型中定义方法
    People.prototype.sayHi = function(){
        return "姓名:" + this.name + ",性别:" + this.sex + ",年龄:" + this.age;
    }
    
    People.prototype.sayHello = function(){
        return "Hello";
    }
    
    // 定义子类
    function Student(name,sex,age,score){
        // applay实现继承(改变调用对象
        People.apply(this,arguments);
    
        // 定义子类拓展的属性
        this.score = score;
    }
    
    // 取消Object.create方法
    Object.create = null;
    // 重新自定义 create 方法,实现相同的功能
    Object.create = function(prototype){
        // 定义一个构造函数
        var F = function(){
    
        }
    
        // 将F的原型指向传入的原型
        F.prototype = prototype;
    
        // 返回F的实例
        return new F();
    }
    
    // 使用Object.create方法实现继承
    Student.prototype = Object.create(People.prototype);
    
    // 实例化对象
    var s = new Student("张三","男",23,100);
    console.log(s.sayHi());
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47

    2.7 Object.entries() 等返回可枚举数组方法

    Object.entries() 方法返回一个给定对象自身可枚举属性的键值对数组,其排列与使用 for...in 循环遍历该对象时返回的顺序一致(区别在于 for-in 循环还会枚举原型链中的属性)。

    Object.keys() 方法会返回一个由一个给定对象的自身可枚举属性组成的数组,数组中属性名的排列顺序和正常循环遍历该对象时返回的顺序一致。

    Object.values() 方法返回一个给定对象自身的所有可枚举属性值的数组,值的顺序与使用 for...in 循环的顺序相同(区别在于 for-in 循环枚举原型链中的属性)。

    const info = {
    	name: "Jack",
        country: "Russia",
        age: 35
    }
    
    // 使用 Object.keys() 将对象所有自身可枚举属性收集到一个新数组中
    const keys = Object.keys(info);
    
    // 使用 Object.values() 将对象所有自身可枚举值收集到一个新数组中
    const values = Object.values(info);
    
    // 使用 Object.entries() 将对象所有自身可枚举所有键值对收集到一个新数组中
    const keyVals = Object.entries(info)
    // 使用 for...of 遍历自身的键值对(key 和 value)
    for (const [key, value] of keyVals) {
      console.log(`${key}: ${value}`);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    2.8 Object.assign()

    Object.assign(target, …sources) 方法将所有可枚举Object.propertyIsEnumerable() 返回 true)的自有Object.hasOwnProperty() 返回 true)属性从一个或多个源对象复制到目标对象,返回修改后的对象。如果目标对象与源对象具有相同的 key,则目标对象中的属性将被源对象中的属性覆盖

    参数: target 目标对象,接收源对象属性的对象,也是修改后的返回值。

    ​ sources 源对象,包含将被合并的属性。

    返回值:目标对象

    注意点

    1. 针对 深拷贝, 需要使用其他办法,因为 Object.assign() 只复制属性值。假如源对象是一个对象的引用,它仅仅会复制其引用值(地址)。
    2. 原型链生的属性以及不可枚举属性不能被复制
    'use strict';
    
    // Object.assign() 属于浅拷贝
    let obj1 = { a: 0 , b: { c: 0}};
    let obj2 = Object.assign({}, obj1);
    console.log(JSON.stringify(obj2)); // { "a": 0, "b": { "c": 0}}
    
    obj1.a = 1;
    console.log(JSON.stringify(obj1)); // { "a": 1, "b": { "c": 0}}
    console.log(JSON.stringify(obj2)); // { "a": 0, "b": { "c": 0}}
    
    obj2.a = 2;
    console.log(JSON.stringify(obj1)); // { "a": 1, "b": { "c": 0}}
    console.log(JSON.stringify(obj2)); // { "a": 2, "b": { "c": 0}}
    
    obj2.b.c = 3;
    console.log(JSON.stringify(obj1)); // { "a": 1, "b": { "c": 3}}
    console.log(JSON.stringify(obj2)); // { "a": 2, "b": { "c": 3}}
    
    // 深拷贝(深度克隆)
    obj1 = { a: 0 , b: { c: 0}};
    let obj3 = JSON.parse(JSON.stringify(obj1));
    obj1.a = 4;
    obj1.b.c = 4;
    console.log(JSON.stringify(obj3)); // { "a": 0, "b": { "c": 0}}
    
    
    // 合并对象
    const o1 = { a: 1 };
    const o2 = { b: 2 };
    const o3 = { c: 3 };
    
    const obj = Object.assign(o1, o2, o3);
    console.log(obj); // { a: 1, b: 2, c: 3 }
    console.log(o1);  // { a: 1, b: 2, c: 3 }, target object itself is changed.
    
    
    //合并相同属性的对象
    const o1 = { a: 1, b: 1, c: 1 };
    const o2 = { b: 2, c: 2 };
    const o3 = { c: 3 };
    
    const obj = Object.assign({}, o1, o2, o3);
    console.log(obj); // { a: 1, b: 2, c: 3 }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44

    2.9 Object.is() 判断两个值是否为同一个值。

    Object.is(value1, value2) 方法判断两个值是否为同一个值,如果满足以下任意条件则两个值相等:

    • 都是 undefined
    • 都是 null
    • 都是 true 或都是 false
    • 都是相同长度、相同字符、按相同顺序排列的字符串
    • 都是相同对象(意味着都是同一个对象的值引用)
    • 都是数字且
      • 都是 +0
      • 都是 -0
      • 都是 NaN
      • 都是同一个值,非零且都不是 NaN

    Object.is()== 不同。== 运算符在判断相等前对两边的变量(如果它们不是同一类型)进行强制转换(这种行为将 "" == false 判断为 true),而 Object.is 不会强制转换两边的值。

    Object.is()=== 也不相同。差别是它们对待有符号的零和 NaN 不同,例如,=== 运算符(也包括 == 运算符)将数字 -0+0 视为相等,而将 Number.NaNNaN 视为不相等。

    // Case 1: Evaluation result is the same as using ===
    Object.is(25, 25);                // true
    Object.is('foo', 'foo');          // true
    Object.is('foo', 'bar');          // false
    Object.is(null, null);            // true
    Object.is(undefined, undefined);  // true
    Object.is(window, window);        // true
    Object.is([], []);                // false
    var foo = { a: 1 };
    var bar = { a: 1 };
    Object.is(foo, foo);              // true
    Object.is(foo, bar);              // false
    
    // Case 2: Signed zero
    Object.is(0, -0);                 // false
    Object.is(+0, -0);                // false
    Object.is(-0, -0);                // true
    Object.is(0n, -0n);               // true
    
    // Case 3: NaN
    Object.is(NaN, 0/0);              // true
    Object.is(NaN, Number.NaN)        // true
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
  • 相关阅读:
    Redis集群(Cluster)
    Unsupervised Embedding Learning via Invariant and SpreadingInstance Feature
    Relational Message Passing for Fully InductiveKnowledge Graph Completion
    限时分享!字节算法大佬亲撰1200页数据算法笔记:GitHub标星79K
    《The Art of InnoDB》第二部分|第4章:深入结构-磁盘结构-撕裂的页面(doublewrite buffer)
    URI 和 URL
    webpack5 之 css与js相关
    那些在开源世界顶半边天的女同胞们
    java计算机毕业设计校园点餐系统源程序+mysql+系统+lw文档+远程调试
    SQLite FTS5 扩展(三十)
  • 原文地址:https://blog.csdn.net/qq_39335404/article/details/132575784