• js对象类型


    对象简介

    1. 对象的概念:一组"键值对"(key-value)的集合,无序的数据集合.(键值对是指"键名:键值"这种一对对的形式,其中键名(又称属性,成员)要遵守一定的命名和书写规则;键值可以是js的任何一种数据类型,这包括原始值primitive如number,string,boolean等,也包括一般对象object,函数Function,数组Array)
      [说明:键名/键值,属性名/属性值,成员/成员值都是指的同一个东西].

      • 键名/键值:形式结构上的描述
      • 属性名/属性值:css中的概念
      • 成员/成员值:java中的概念
    2. 键名/属性名的规则:

      • 对象的属性名都是字符串(ES6引入Symbol值也可作为键名)
      • 不是字符串的,自动转为字符串
      • 如果属性名不符合标识符条件(例如:包含空格),必须加上引号,否则会报错
        注:js标识符命名规则
        • js中标识符可以由 字母、数字、下划线、$ 组成,但不能是保留字;
        • js中标识符只能由 字母、下划线、$ 开始,而不能由数字开始;
        • js中标识符区分大小写
    3. 对象的属性(property):(详细内容,参照后面的章节)

      • 各个属性(键值对)之间用逗号","隔开,最后一项的逗号可加也可不加
      • 属性分类:数据属性(data property),访问器属性(accessor property),内部属性(internal property)
      • 各个属性又有各自的特性(attribute)与属性描述符对象(property descriptor)
    4. 函数的参数的传递方式:原始类型按值传递,复合类型按引用传递(对象的引用:该对象所在的内存地址,即"指向对象的指针")

    5. 属性的操作:

      • 属性的读取与赋值:

        • 点号".":obj.属性名(注意:数字键名不能用此种方法,点号会被当成小数点)
        • 方括号"[]":obj[‘属性名’],方括号内的两个单引号不能省略.并且方括号之内还可以进行字符串处理.例:obj[‘on’+‘click’]
      • 属性(名)查看:Object.keys(obj)方法(不能查看属性值,只能查看含有哪些属性)

      • 删除对象本身的属性:delete命令

        • 格式:delete obj.属性名;
        • 删除成功返回true;该属性不得删除,返回false.(见后续章节)
        • delete命令不能删除继承属性/原型属性
      • 验证属性存在性:in 运算符

        • 格式:‘字符串’ in obj;
        • 检查对象的键名而不是键值
        • 不区分本身属性与继承属性
      • 判断属性是否为本身属性:obj.hasOwnProperty(‘字符串’);

      • 遍历可enumerable的属性:for…in循环
        格式:for (var i in obj) {…}

      • 操作同一对象的多个属性:with语句
        with(obj) {a=1;b=2;}等同于obj.a=1;obj.b=2;
        [注意:with语句操作的必须是对象已经拥有的属性.否则就会创建一个仅在with语句的作用域内有效的新属性.with语句结束后,该属性又变成undefined.正因为如此,我们不推荐使用with语句]


    对象属性详解

    1. 属性分类:

      • 数据属性(data property):一般的键值对
      • 访问器属性(accessor property):不保存值,但可对访问和赋值操作的实际过程进行自定义
      • 内部属性(internal property):一般无法直接访问,需要借助相应的函数
    2. 数据属性(data property):

      • 就是我们说的一般的属性,它保存一个值,要么是数据本身(原始类型),要么是数据的引用(对象).

      • 数据属性的访问与赋值操作的实际过程是默认的,无法修改

      • 数据属性的特性(property attributes):

        • 属性(property)与特性(attribute)是两个不同的概念
        • 属性的特性(attribute)是对属性本身能够进行的行为的约束
        • 数据属性的特性有如下几种:

        在这里插入图片描述

        • 属性特性不能直接进行修改,必须使用专门的方法Object.defineProperty(obj,‘属性名’,属性描述符对象)

          注:属性描述符,或者说属性描述符对象是指将要修改的特性与修改值,以键值对的形式书写,并用对象封装.例如{configurable:false,writable:false}
        • 与属性描述符相关的函数:

          • Object.defineProperty(obj, ‘属性名’, 属性描述符)
          • Object.defineProperties(obj, 属性-描述符键值对对象)
            这里的 属性-描述符键值对对象 是指如下形式的封装对象:
            {属性名1:描述符对象1 , 属性名2:描述符对象2,…}
          • Object.create(proto, 属性-描述符键值对对象)
          • Object.getOwnPropertyDescriptor(obj, 属性名):返回特定属性的属性描述符对象;如果不存在该属性,返回undefined.
    3. 访问器属性(accessor property):

      • 访问器属性不包含数据值,他们有一对儿getter和setter函数(这两个函数不是必须的,保存在其属性特性Set和Get中)。允许用户在赋值或取值都经过预先设定的函数,从而实现内部属性的那一种特殊效果.

        读取访问器属性时,会调用getter函数,这个函数负责返回有效的值。 在写入访问器属性时,会调用setter函数,这个函数负责决定如何处理数据。
      • 属性特性:(前两个与数据属性相同,后两个不同)
        在这里插入图片描述
        小结:因为不保存值,所以没有Value和Writable特性,Set和Get取而代之.

      • 访问器属性的创建修改:不能直接修改,需要用到特定函数Object.defineProperty(obj,‘属性名’,属性描述符对象)或者Object.defineProperties(obj, 属性-描述符键值对对象)

    4. 内部属性(internal property):

      • 一些属性仅仅在规范之中用到,它们被称为"内部属性"是因为它们不能通过js直接访问,但也确确实实影响着代码.内部属性的书写都是包含在双方括号([[]])之中的.
      • 所有对象共有的内部属性:
        在这里插入图片描述
        在这里插入图片描述
        更多相关资料,请参考:ECMA5.1

    重要的内部属性详解:

    • [[prototype]]:存放当前对象的原型对象的引用
      1.函数与函数的原型对象(prototype object):

      • 在JavaScript中,创建一个函数A(就是声明一个函数), 浏览器就会在内存中创建一个对象B,而且该函数默认会有一属性 prototype 指向这个对象(即:prototype属性的值)
      • 这个对象B就是函数A的原型对象,简称函数的原型。这个原型对象B也默认会有一个属性 constructor 指向了这个函数A (即:constructor属性的值是函数A)
      • 凡是以函数A为构造函数而创建的对象C,D,E等等,也都有一个内部的[[prototype]]属性,也指向这个对象B.

      2.要点一:构造函数的prototype的属性与其实例对象的[[prototype]]属性的区别.
      前面的内容提到"内部属性"是不能直接访问到的,需要借助某些函数.而构造函数的prototype属性不是内部属性,而是普通属性;但是其实例对象的[[prototype]]确是内部属性,直接obj.prototype总是返回undefined.
      代码:
      function Test() {}
      var t1 = new Test();
      console.log(Test.prototype);
      console.log(t1.prototype);
      运行结果:
      在这里插入图片描述
      3.要点二:任何对象都有构造函数,都有原型对象
      对象可以分为字面量对象,new出来的对象和函数对象.显然,new出来的对象都是有构造函数和原型对象的.

      • 字面量对象
        代码:

        var square = {length: 10};
        var pro=Object.getPrototypeOf(square);
        console.log(pro);
        console.log(pro==Object.prototype);

        运行结果:
        在这里插入图片描述
        因此,字面量对象的原型是Object.prototype,其构造函数为Object().

      • 函数对象:
        代码:

        function Test(){}
        var proF=Object.getPrototypeOf(Test);
        console.log(proF);
        console.log(proF==Function.prototype);

        运行结果:
        在这里插入图片描述
        因此,函数对象的原型是Function.prototype,构造函数为Function().
        至此,我们可以得出开头的结论.

      4.要点三:任何函数都可以作为构造函数,但不一定都能对其实例对象初始化.
      例子1:
      代码:

      function Test2(x,y){
      length=x;
      name=y;
      }
      var T2 = new Test2(1,‘peter’);
      console.log(Object.getPrototypeOf(T2)==Test2.prototype);
      console.log(T2.length);

      运行结果:
      在这里插入图片描述

      例子2:
      代码:

      function Test3(x,y){
      this.length=x;
      this.name=y;
      }
      var T3 = new Test3(1,‘peter’);
      console.log(Object.getPrototypeOf(T3)==Test3.prototype);
      console.log(T3.length);

      运行结果:
      在这里插入图片描述
      5.我们约定,凡是构造函数,其函数名首字母必须大写.

    • 进一步探讨内部属性
      由上面的要点一,我们可以看出,prototype属性像是构造函数的私有属性(类似java的私有成员).构造函数自身可以直接访问,但其实例对象不能直接访问,需要借助在构造函数里定义的"特权"函数才能间接访问.
      我们再把我们的视野移到整个内部属性集合,像[[Class]],[[Extensible]]等.

      内部属性 访问方法
      [[Prototype]] Object.getPrototypeOf(obj) , obj.__proto__(访问器属性,类似于方法)
      [[class]] Object.prototype.toString.call(obj)
      [[Extensible]] Object.isExtensible , Object.preventExtensions

    那么,我们如何自定义一个函数的私有属性呢?
    在js中,我们通常通过闭包来实现私有属性.
    代码:

    function Student(num,str){
    var grade = num;
    var name = str;
    this.getGrade = function (){
    return grade;
    }
    this.getName = function(){
    return name;
    }
    }
    var s = new Student(98,‘peter’);
    console.log(s);
    console.log(s.grade);//undefined,不能直接访问私有属性
    s.name = ‘selena’;//对象新建了一个自身属性name,不是私有属性[[name]]
    console.log(s.name);//selena,访问自身属性
    console.log(s.getName());//peter,通过特权方法getName()访问私有属性

    运行结果:
    在这里插入图片描述
    这种实现的优缺点总结:
    1.私有属性和特权函数只能在构造函数中创建
    2.闭包的使用增加了资源占用,可能会导致一些问题


    对象的保护

    1. 阻止对象的扩展(Preventing Extension)
      效果:禁止向对象添加新属性,仍可以删除已有属性
      实现途径:Object.preventExtensions(obj)
      检查是否已阻止:Object.isExtensible(obj)

    2. 封闭对象(Sealing)
      效果:禁止添加新属性,全部已有属性"unconfigurable"(不可更改属性的特性值,不可删除自身属性),但基于历史原因,仍可以将writable改为read-only.
      实现途径:Object.seal(obj)
      检查对象是否已封闭:Object.isSealed(obj)

    3. 冻结对象(Freezing)
      效果:使所有属性变为只读,同时不可扩展(添加新属性),不可修改属性特性,不可删除属性
      实现途径:Object.freeze(obj)
      检查对象是否已冻结:Object.isFrozen(obj)


    严格模式

    1. 严格模式是ECMAScript的一部分.可以灵活切换,可以是整个文件,也可以仅在一个函数内

    2. 启用方式:
      整个文件----将’use strict’放在在文件开始处
      某个函数----将’use strict’放在在函数开始处

    3. 对安全性的需求是严格模式使用的主要动机

    4. 严格模式特征:

      • 安全性:极严格地限制eval()的使用,with语句禁止使用
      • 全局变量使用之前必须被明确地声明(不会再自动生成),这有助于预防输入上的错误
      • 未使用new调用构造函数时:
        在严格模式出现之前,this是绑定到全局变量的,这导致会有属性被添加到这个对象.
        严格模式中,如果构造函数不是经new调用的,那么this是绑定到undefined的,而且通常会有一个exception被抛出.
    5. 烦人的报错:尝试修改一个只读的属性的值或者删除一个不可配置的属性,会丢出exception.

    6. 不再支持八进制数:严格模式中,以0开头的数不会再被理解成八进制,0100就是十进制的100,而不是八进制的64.

    7. 参数对象:arguments.callee和arguments.caller属性被排除掉(基于安全原因:这样使得他们不被外部代码发现)

    8. 函数参数:禁止出现与形参同名的参数或变量名.

  • 相关阅读:
    [公告]Google个性化主页可以正常阅读博客园的RSS了
    致歉
    [公告]网站程序已经升级到ASP.NET 2.0
    GTF: Great Teacher Friedman
    Node.js : exports と module.exports の違い
    拨开历史的迷雾从篡夺者战争到五王之战的政经原因
    javascript模板系统 ejs v10
    window.name + postMessage实现不用代理页的跨域通信
    node.js Domain 時代のエラー処理のコーディングパターン
    鲜为人知的get,set操作符
  • 原文地址:https://www.cnblogs.com/peterzhangsnail/p/12521664.html
Copyright © 2020-2023  润新知