美文网首页技术码头
JS关于对象的属性和方法整理

JS关于对象的属性和方法整理

作者: 石菖蒲_xl | 来源:发表于2020-01-02 17:08 被阅读0次

    对象简介

    • 对象是js的基本数据类型,对象是一种复合值,它将很多值聚合在一起,可通过名字访问这些值。
    • 对象也可看做是属性的无序集合,每个属性都是一个名/值对,属性名是字符串,因此我们也可以把对象看成是从字符串到值的映射
    • 这种基本数据结构还有很多叫法,“散列”、“散列表”、“字典”、“关联数组”。
    • js对象还可以从一个称为原型的对象继承属性(核心特性)。
    • 除了字符串、数字、truefalsenullundefined之外,js的值都是对象。
    三类js对象
    • 内置对象(native object) :数组、函数、日期、正则表达式
    • 宿主对象(host object)js所运行的环境提供的对象比如:BOM中的WindowDOM中的document
    • 自定义对象(user-defined object):代码创建的对象。
    两类属性
    • 自有属性:直接在对象中定义的属性。
    • 继承属性:是在对象的原型对象中定义的属性。

    创建对象

    • 对象直接量(创建对象最简单的方式)
    • 关键字new
    • Object.create()函数

    1、对象直接量

    // 没有任何属性的对象
    var empty = {};
    
    // 复杂对象
    var book = {
      x:0,                        // 正常属性
      "main title":"Js",          // 属性名字有空格,必须用字符串表示
      "sub-title":"js js",        // 属性名字有连字符,必须用字符串表示
      "for":"all"                 // for 是关键字,必须用引号,不建议使用关键字作为属性名
    }
    

    如上:对象直接量是一个表达式,这个表达式每次运算都创建并且初始化一个新的对象,每次计算对象直接量的时候,也都会计算它的每个属性的值,所以,如果在一个重复调用的函数中的循环体内使用了对象直接量,它将创建很多新对象,并且每次创建的对象的属性值也有可能不同。

    2、new一个对象
    new运算符创建并初始化一个新对象,关键字new后跟随一个函数调用,这里的函数称做构造函数(constructor),构造函数用以初始化一个新创建的对象。

    var o = new Object(); // 创建一个空对象,和{}一样
    var a = new Array(); //  创建一个空数组,和 []一样
    var d = new Date(); // 创建一个表示当前时间的Date对象
    var r = new RegExp('js'); // 创建一个可以进行模式匹配的RegExp对象
    

    3、Object.create()
    Object.create()是一个静态函数,而不是提供给某个对象调用的方法,使用它的方法只需传入所需原型对象即可。*·what·? ? ? *

    • Object.create()只能传入对象或者 null,什么都不传报错。
    var o1 = Object.create({x:1}); // o1继承了属性x
    

    如上代码所示:o1继承了属性x,注意是继承,此时我们打印o1,输出{},但是打印o1.x却能输出1,再看o1.__proto__输出{x:1}o1的原型对象是{x:1}{x:1}的原型对象是Object,这一系列链接的原型对象就是所谓的“原型链”。

    原型链
    • 可以传入参数null来创建一个没有原型的新对象,但是通过这种方法创建的对象不会继承任何东西,甚至不包括基本方法,比如toString()
    var o2 = Object.create(null); // o2不继承任何属性和方法。
    
    o2
    • 如果想创建一个普通的空对象,需要传入Object.prototype
    var o3 = Object.create(Object.prototype); // o3和{}和 new Object() 一样
    
    o3

    继承

    js对象具有“自有属性”,也有一些属性是从原型对象继承而来的。

    function inherit(p) {
      if(p == null){
        throw TypeError();            // p 是一个对象,但是不能是null
      }
      if(Object.create) {
        return Object.create(p);     // 如果Object.create()存在就直接使用
      }
      var t = typeof p;
      if(t !== "Object" && t !== "function") {
        throw TypeError();
      }
      function f(){};           // 定义一个空构造函数
      f.prototype = p;         // 将其原型属性设置为p
      return new f();         // 使用f()创建p的继承对象
    }
    
    var o = {};                 // o 从 Object.prototype 继承对象的方法
    o.x = 1;                   // 给o定义一个属性x
    var p = inherit(o);       // p 继承 o 和 Object.prototype
    p.y = 2;                 // 给p定义一个属性y
    var q = inherit(p);      //  q 继承 p、o、Object.prototype
    q.z = 3;                // 给 q 定义一个属性 z
    var s = q.toString();  // toString 继承自Object.prototype
    q.x + q.y;             // => 3     x 和 y 分别继承自 o 和 p
    

    假设要查询对象 o 的属性 x,如果 o 中不存在 x,那么将会继续在 o 原型对重查询属性 x,如果原型对象中也没有 x,但这个原型对象也有原型,那么继续在这个原型对象的原型上执行查询,直到找到x或者查找到一个原型是null的对象为止,可以看到,对象的原型属性构成一个“链”,通过这个“链”可以实现属性的继承。

    现在假设给对象o的属性x赋值,如果o中已经有属性x(这个属性不是继承而来的),那么这个赋值操作只改变这个已有属性x的值,如果o中不存在属性x,那么赋值操作给o添加一个新属性x,如果之前o继承自属性x,那么这个继承的属性就被新创建的同名的属性覆盖了。

    var unitcircle = {r:1};
    var c = inherit(unitcircle);
    c.x = 1;
    c.y = 1;
    c.r = 2;
    unitcircle.r;         // => 1 原型对象没有修改
    

    原型
    每一个js对象(除了null)都和另一个对象相关联,“另一个”对象就是我们熟知的原型,每一个对象都是从原型继承属性。


    属性访问错误

    • 查询一个不存在的属性并不会报错,如果在对象o自身的属性或继承的属性中均未找到属性x,属性访问表达式o.x返回undefined
    var o = {y:1};
    o.x; // => undefined
    
    • 如果对象不存在,那么查询这个不存在的对象的属性就会报错,nullundefined值都没有属性,因此查询这些值的属性户报错。
    var o = null;
    o.x; // => Uncaught TypeError: Cannot read property 'x' of null
    
    var p = {y:1};
    o.x.z; // =>  Uncaught TypeError: Cannot read property 'z' of undefined
    

    删除属性

    • delete运算符可以删除对象的属性
    • delete运算符只能删除自有属性,不能删除继承属性(要删除继承属性必须从定义这个属性的原型对象上删除它,而且这会影响到所有继承自这个原型的对象)

    检测属性

    js对象可以看做属性的集合,我们经常会检测集合中成员的所属关系,判定某个属性是否存在某个对象中。
    js提供四种个方式:

    • in运算符,会去查继承属性
    • hasOwnPreperty() ,只会查自有属性,不会去查继承的属性
    • propertyIsEnumerable() ,只查自有且可枚举的属性,不查继承属性
    • 通过属性查询 ,不能区分值是undefined的属性
      1、in运算符
      in运算符的左侧是属性名(字符串),右侧是对象,如果对象的自有属性或继承属性中包含这个属性则返回true
    var o = {x:1};
    "x" in o;            // => true 自有属性
    "y" in o;            // => false 不存在属性
    "toString" in o;     //=> true 继承属性
    

    2、 hasOwnProperty()
    hasOwnProperty()用来检测给定的名字是否是对象的自有属性,对于继承的属性它将返回false

    var o  = {x:1};
    o.hasOwnProperty("x");            // => true 自有属性
    o.hasOwnProperty("y");            // => false 不存在属性
    o.hasOwnProperty("toString");    // => false ,继承属性
    

    3、propertyIsEnumerable()
    propertyIsEnumerable()hasOwnProperty()的增强版,只有检测到是自有属性且这个属性可枚举为true时它才返回true

    var o = inherit({y:2});
    o.x = 1;
    o.propertyIsEnumerable("x");   // => true 自有可枚举属性
    o.propertyIsEnumerable("y");  // => false 继承属性
    Object.prototype.propertyIsEnumerable("toString"); // => false 不可枚举属性
    

    4、使用!==判定一个属性是否是undefined

    var o = {x:1,y:undefined};
    o.x !== undefined;              // => true 自有属性
    o.y !== undefined;              // => false 不存在属性
    o.toString !== undefined;      // => true 继承属性
    o.y !== undefined;            // => false 属性存在但是值为undefined
    

    如上代码:当属性存在,但是值是undefined!==不能返回希望的结果。


    枚举属性

    除了检测对象的属性是否存在,我们还会经常的遍历对象的属性。

    • for/in循环遍历 ,所有可枚举属性
    • Object.keys(),(ES5提供)返回由可枚举的自有属性的名称组成的数组
    • Object.getOwnPropertyNames()ES5提供)只返回自有属性

    1、for/in
    for/in循环可以在循环体重遍历对象中所有可枚举的属性(自有和继承),把属性名称赋值给循环遍历。

    var o = {x:1};
    var p = inherit(o);
    p.y = 2;
    for (var key in p){
      console.log(key);
    }
    // => y 自有属性
    // => x 继承属性
    // 没有输出 toString ?
    "toString" in p;                     // => true 继承属性
    p.propertyIsEnumerable("toString"); // => false 不可枚举属性
    

    如何过滤继承属性?

    for (var key in p){
      if(!p.hasOwnProperty(key)) continue; // 跳过继承属性
       console.log(key)
    }
    // => x 只输出自有属性
    

    2、Object.keys()
    Object.keys() 枚举属性名称的函数,它返回一个数组,这个数组由对象中可枚举的自有属性的名称组成。

    var o = {x:1};
    var p = inherit(o);
    p.y = 2;
    p.z = 3;
    Object.keys(p); // => ["y","z"] 未返回继承属性x
    

    3、Objcet.getOwnPropertyNames()
    只返回对象的自有属性名称,而不仅仅是可枚举属性,不可枚举属性也会返回。

    var o = {x:1};
    var p = inherit(o);
    p.y = 2;
    p.z = 3;
    Object.defineProperty(p,"h",{value:4,enumerable:true}); // 添加可枚举属性
    Object.defineProperty(p,"w",{value:5,enumerable:false}); // 添加不可枚举属性
    Object.keys(p); // => ["y","z","h"]  未返回不可枚举属性w 和继承 属性 x
    Object.getOwnPropertyNames(p); // => ["y","z","h","w"] 只是未返回继承属性 x
    

    属性getter和setter

    ES5中属性值可以用一个或两个方法代替,这俩方法就是gettersetter。由gettersetter定义的属性称做“存取器属性”

    • 如果属性同时具有gettersetter方法,那么它是一个读/写属性。
    • 如果它只有一个getter方法,那么它是一个只读属性。
    • 如果它只有一个setter方法,那么它是一个只写属性,读取只写属性总是返回undefined
    var o = {
      x:1,
      y:2,
      h:undefined,
      get product(){
        return this.x * this.y;
      },
      set product(value){
        this.x = value;
        this.y = value * 2;
      },
      get sum(){
        return this.x + this.y;
      },
      set z(value){
        this.h = value;
      }
    }
    // product 是一个读/写属性
    o.product;     // => 2 
    o.product = 2;
    o.product;     // => 8
    
    // sum 是一个只读属性
    o.sum;       // => 3
    o.sum = 5;
    o.sum;       // => 3
    
    // z 是一个只写属性
    o.z;      // => undefined
    o.z = 4;
    this.h; // => 4
    

    属性的特性

    除了包含名字和值之外,属性还包含一些标识它们可写、可枚举、可配置的特性。ES3无法设置这些特性。

    • 可以通过这些API给原型对象添加方法,并将它们设置成不可枚举,这让它们看起来更像内置方法。
    • 可以通过这些API给对象定义不能修改或删除的属性,借此“锁定”这个对象。
    • 数据属性4个特性分别是:
      value
      可写性(writable
      可枚举性(enumerable
      可配置性(configurable
    • 存取器属性 不具有 可写性 它们的可写性由setter方法存在与否决定,存取器属性的4个特性是:
      读取(get)
      写入(set)
      可枚举
      可配置

      ES5定义了一个名为“属性描述符”的对象,这个对象代表那4个属性。
    {
      value:数据属性,表示属性的值,默认: undefined
      writable: 可写性,表示能否修改属性。默认值:true
      enumerable:可枚举性,表示能否通过 for/in 遍历得到属性,默认true
      configurable:可配置性,如果属性为false则不可在对属性描述符进行修改,默认值为true。
    }
    

    通过调用Object.getOwnPropertyDescriptor()可以获得某个对象特定属性的属性描述对象

    var o = {x:1};
    Object.getOwnPropertyDescriptor(o,"x");
    // => {"value":1,"writable":true,"enumerable":true,"configurable":true}
    Object.getOwnPropertyDescriptors(o);
    // => {"x":{"value":1,"writable":true,"enumerable":true,"configurable":true}}
    

    由上边代码可见,这个方法只能得到自有属性的描述符。
    那么如何设置属性的特性呢? Object.defineProperty()

    • 第一个参数:要修改的对象
    • 第二个参数:要创建或者修改的属性名称
    • 第三个对象:属性描述符对象

    这个方法要么修改已有属性要么新建自有属性,但是不能修改继承属性。

    var o = {x:1};
    // 设置一个不可枚举的属性,其他属性默认true
    Object.defineProperty(o,"x",{value:1,enumerable:false});
    Object.keys(o); // => []
    

    Object.defineProperties()
    如果要同时修改或者创建多个属性:

    • 第一个参数:要修改的对象
    • 第二个参数:一个映射表,它包含要新建或修改的属性的名称以及它们的属性描述符
    var o = {};
    // 给对象o添加俩个属性,x 和 y 其中 y 不可枚举不可配置
    Object.defineProperties(o,{
      x:{"value":1,"writable":true,"enumerable":true,"configurable":true},
      y:{"value":2,"writable":true,"enumerable":false,"configurable":false}
    });
    // y不可配置,如果这个时候我们想要修改y的属性描述符,会报出错误异常
    Object.defineProperties(o,{
      y:{"value":2,"writable":true,"enumerable":true,"configurable":false}
    });
    // => Uncaught TypeError: Cannot redefine property: y
    

    对象的三个属性

    • 原型
    • 可扩展性
    原型属性
    • 对象的原型属性是用来继承属性的。
    • 原型属性是在实例对象创建之初就设置好的。
    • ES5中,将对象作为参数传入Objcet.getPrototypeOf()可以查询它的原型(一个并不可靠的方法)。
    • 要检测一个对象是否是另一个对象的原型,可以使用isPrototypeOf()
    var o = {x:1};
    var p = Object.create(o);
    o.isPrototypeOf(p);        // => true p继承自o
    Object.prototype.isPrototypeOf(o); // true  o 继承自Object.prototype
    
    可扩展性

    对象的可扩展性用以表示是否可以给对象添加新属性。


    序列化对象

    对象序列化是指将对象的状态转换为字符串,也可以将字符串还原为对象。
    ES5提供了内置函数JSON.stringify()JSON.parse()用来序列化和还原js对象。

    • NaNInfinity-Infinity序列化的结果是null
    • 函数、RegExpError对象和undefined值不能序列化和还原
    • JSON.stringify() 只能序列化对象可枚举的自有属性
    JSON.stringify(NaN); // => "null"
    JSON.stringify(Infinity); // => "nulll"
    JSON.stringify(undefined); // => undefined
    

    instanceof 运算符

    instanceof运算符希望左操作数是一个对象,右操作数标识对象的类,如果左侧对象是右侧类的示例,则表达式返回true,否则返回false
    js对象的类是通过初始化它们的构造函数来定义的,这样的话instanceof的右操作数应当是一个函数

    • 所有对象都是Object的实例
    • 如果instanceof左操作数不是对象的话,返回false
    • 如果右操作数不是函数,则抛出一个类型错误的异常
    var d = new Date(); // 通过Date()构造函数来创建一个新对象
    d instanceof Date; // => true d是由Date创建的
    d instanceof Object ; // => true 所有的对象都是Object的实例
    d instanceof Number; // => false 
    

    相关文章

      网友评论

        本文标题:JS关于对象的属性和方法整理

        本文链接:https://www.haomeiwen.com/subject/xezpoctx.html