JS · 六-对象

来源:互联网 发布:python numpy split 编辑:程序博客网 时间:2024/05/02 04:19

对象的属性特性

  • 可写:表明是否可以设置该属性的值

  • 可枚举:表明是否可以通过for/in循环返回该属性(Object.prototype不可枚举)

  • 可配置:表明是否可以删除或修改该属性

对象特性

  • 对象的原型,即本对象的属性继承自它的原型对象

  • 对象的类是一个标识对象类型的字符串

  • 对象的扩展指明了在(ES5)是否可以向该对象添加新属性

三种对象类型的定义&两类属性

  • 内置对象:是由ES规范定义的对象或类

  • 宿主对象:是由JS解释器所嵌入的宿主环境(比如web浏览器)定义的。(客户端JS中表示网页结构的HTMLElement对象均是宿主对象)

  • 自定义对象:是由运行中的JS代码创建的对象

  • 自有属性:直接在对象中定义的属性

  • 继承属性:是在对象的原型对象中定义的属性

1、创建对象

1.1 对象直接量

var empty={};//没有任何属性的对象var point={ x:0,y:0}; //两个属性var book={   "main title":"living", //属性名有空格,必须用字符串表示   "sub-title":"arrive",//属性名有连字符,必须用字符串表示   "for":"you",//属性名师保留字,必须用字符串表示   author:{        first:"1",        second:"2"//属性名可以不用加引号        }    }//在ES5中(一些ES3的实现中)保留字可以用作不带引号的属性名

1.2 通过new创建对象

  • new后面跟着一个构造函数,用以初始化新创建的对象

1.3 原型

  • 每一个JS对象(除了null外)都和另一个对象关联

  • 通过对象直接量创建的对象都具有同一个原型对象(Object.prototype)

  • Object.prototype没有原型对象,不继承任何属性

  • 所有的内置构造函数(以及大部分自定义的构造函数)都继承自Object.prototype函数)

1.4 Object.creat()

Object.creat()是一个静态函数
作用:创建新对象
结构:两个参数,第一个参数是对象的原型,第二个参数是对对象属性的进一步描述(详情跳转至7)

var o2=Object.creat(null);// 不继承任何属性和方法// null参数可以用来创建没有原型的对象,不继承任何东西var o3=Object.creat(Object.prototype); // 创建普通空对象(也可以用{}或new Object()创建)
// 通过原型继承创建一个新对象//如果存在Object.creat()则使用,否则使用其他方法function inherit(){    if(p==null)throw TypeError();    if(Object.creat)return Object.creat(p);    var t=typeof p;    if(t!=="Object"&&t!=="function")throw TypeError();    function f(){         f.prototype=p; // 将其原型设置为p         renturn new f();        // inherit()不能传入null,且不可以接收可选的第二个参数

inherit其中一个用途是防止库函数无意间修改那些不受你控制的对象。利用继承的特性进行工作。

2 属性的查询和设置

  • 可以用过(.)和([])运算符来获取属性的值
  • 点运算符之后的字母不能是保留字(ES3)只能用([])。例如[“class”]。ES5之后则都可以使用
  • 当使用([])时,方括号内的表达式必须返回字符串或返回一个可转换为字符串的值

2.1 作为关联数组的对象

  • JS对象都是关联数组(也称作散列、映射和字典),数组元素是通过字符串索引
    强弱类型:为所有变量指定数据类型称为“强类型”。强弱类型是指类型 查的严格程度。
    严格模式下,JS的属性个数是有个数限制的。
    重点内容 for/in 一般用于循环遍历关联数组
function getyou(a){  for(var i in a){   ···  // 相关代码 } }

2.2 继承

1、原型链的构造:x->父对象->祖父对象->… 2、查找x的对象时,先从x内查找,若无则从父对象查找,否则去上一级查 找…以此类推。知道找到查找的对象或者找到一个原型为null的对象为止。 3、对属性赋值,若不继承原型对象则直接添加新属性,否则覆盖继承属性的值。(因此要首先检查原型链)

2.3 属性访问错误

  • 查询一个不存在是属性不报错(返回null 或者undefined),查询一个不存在对象的属性就报错。null和undefined没有属性。
//属性访问所得的length//一种冗余易懂的办法var len=undefined;if(book){   if(book.subtitle.length)len=book.subtitle.length;   }//一种简练的办法var len=book&&book.subtitle&&book.subtitle.length;
  • ES5之后,严格模式中,所有失败的属性设置操作都会抛出一个类型错误异常。
    以下场景对象o设置属性P会失败:

    1、p属性只读:不能给只读属性重新赋值(defineProperty()方法有一个例外)

    2、p属性是继承属性,且只读:不能通过同名属性覆盖只读的继承属性

    3、o中不存在自有属性p:o没有使用setter方法继承属性p,且o不可扩展,则o不能定义新属性。

3 删除属性

delete操作符可以删除对象的属性。
delete只能删除自有属性,不能删除继承属性。
delete删除成功后或没有任何副作用(比如:删除不存在的属性1,它返回true)

o={x:1};  //设置对象o有属性x,继承toString对象delete o.x;  //删除x属性delete o.x;  //什么都没做(x已经不存在),返回truedelete o.toString;  //什么都没做(无法删除继承属性),返回truedelete 1;  // 无意义,返回true

delete不能删除不可配置的属性,尽管可以删除不可扩展的可配置对象
以下在非严格模式中(或ES3),delete操作会返回false

delete Object.prototype;   //不能删除不可配置属性var x=1;  //声明一个全局变量delete this.1;   //不能删除该属性function f(){}   //声明一个全局函数delete this.f();  //不能删除全局函数

4 检测属性

检测方法:

1、n操作符检测:检测是否是某对象的属性2、hasOwnPreperty():检测自有属性3、PropertyIsEnumenrable():检测自有属性且可枚举4、属性查询:例如“!==”(但是难以查询属性值为undefined或者null的属性)以下为解决办法:
var o={x:undefined}; //属性被显式赋值为undefinedo.x!==undefined;  //false:属性存在但值为undefinedo.x!==undefined;   //false:属性不存在"x" in o; //true:属性存在"y" in o;  //false:属性不存在delete o.x;  //删除属性"x" in o;  //false:属性不存在 

5 枚举属性

  • 对象继承的内置方法不可枚举的,但在代码中给对象添加属性都是可枚举的(除非用方法转换为不可枚举)
  • 当方法不能定义为不可枚举时,为了避免它们在for/in循环中被枚举出来,需用以下方法:
for(p in o){    if(!o.hasOwnProperty(p))continue;    } //跳过继承的属性for(p in o){    if(typeof o[p]==="function")continue;    }  //跳过方法

用来枚举属性对象的工具函数:

extend(o,p)

1、 把p中的可枚举属性复制到o中,并返回o。
2、o和p如果有同名属性,则覆盖o的属性。
3、该函数不处理getter和setter以复制的属性

merge(o,p)

1、将p的可枚举属性复制到o中,并返回o
2、如果o和p中有同名属性,o中的属性将不受影响
3、该函数不处理getter和setter以及复制属性

restrict(o,p)

1、如果o的属性在p中没有同名属性,则删除o中的该属性
2、返回o

subtract(o,p)

1、如果o和p存在同名属性,则删除o中的该属性
2、返回o

union(o,p)

1、返回一个新对象,这个对象同时拥有o和p的属性
2、若o和p充满属性,则使用p的属性值

intersection(o,p)

返回一个新对象,这个对象拥有同时在o和p中出现的属性
类似于求o和p的交集,但p的值被忽略

keys(o)

返回一个数组,这个数组包含的是o中可枚举的自有属性的名字

  • ES5之后定义了两个用以枚举属性名称的函数:
  • a、Object.keys()工作原理与keys()类似。
  • b、Object.getOwnPropertyNames()与keys()类似,只是返回的对象是所有的自有属性。

6 属性getter和setter

getter/setter——存储器属性,不具有可写性(可继承),存取器定义为一个或两个属性的同名函数:

get r(){}, set r(value){},  // r是可读写的存取器属性get theta(){}  // theta是只读存储器

getter——查询值(每次读取可能返回不同值),只读
setter——设置值(可以检测属性的写入值),只写

拓展:代码中$符号加在属性名之前则暗示这个属性是私有属性


7 属性的特性

所有通过JS3的程序创建的属性都有可写的、可枚举的、可配置的,且无法修改的特性。

数据属性:

1、一个名字
2、四个特性:

  • 值 value
  • 可写性 writable
  • 可枚举 enumerable
  • 可配置 configurable
    后三个特性都是布尔值,但是getter和setter属性是函数值

存取器属性:

1、名字
2、特性:

  • 读取(getter)
  • 写入(setter)
  • 可枚举
  • 可配置
  • 通过调用Object.getOwnPropertyDescriptor()可以获得某个对象的特定属性的属性描述(对于继承属性和不存在的属性,返回undefined)。
  • 获得继承属性特性:遍历原型链(Object.getPrototypeOf())。

修改/设置属性特性:Object.definePeoperty()(多个则用Object.definePeoperties())
  • 当属性“只读”时,不可直接更改值,应通过Object.definePeoperty()更改value即可(不能修改继承属性,直接修改不报错,但严格模式下抛出类型错误异常)。
  • 方法的结构:

    Object.definePeoperty(o, "x",{ value:1});  // 修改单个属性Object.definePeoperties({},{   x:{value:1},   y:{value:2} });   //修改多个属性
  • Object.definePeoperty()(多个则用Object.definePeoperties())使用规则:

    • 若对象不可扩展,则可以编辑已有的自有属性,但不可添加新属性。
    • 不可配置的属性,不可修改他的可配置性和可枚举性。
    • 存储器不可配置,不可以修改其getter和setter方法,不能转换为数据属性。
    • 数据属性不可配置,不可转换为存取器属性,可写性可以将true->false,但不可以将false->true。
    • 数据属性不可配置且不可写,则不能修改其值。

问题一:JS中不可配置属性如何修改它的可写性?

解决办法:通过defineProperty()修改。

问题二:如何将不可配置属性变成可配置属性?

如果对象是定义为可配置的,那么你要对其进行修改。
还可以通过defineProperty来改变属性为可修改的或不可迭代的。
但是如果一旦定义属性为不可配置的,那么能做的事就只有一件了: 如果该属性是可修改的, 那么可以将其改为不可修改的。 其他任何类型的更新都将引发 TypeError 异常。

var ob = {};Object.defineProperty(ob, 'a', {configurable: false, writable: true});Object.defineProperty(ob, 'a', {enumerable: true}); // 抛出 TypeError 异常Object.defineProperty(ob, 'a', {value: 12}); // 抛出 TypeError 异常Object.defineProperty(ob, 'a', {writable: fasle}); // 唯一允许的操作Object.defineProperty(ob, 'a', {writable: true}); // 抛出 TypeError 异常

本段摘自网络

升级版的extend()函数:

  • 使用Object.getOwnPropertyDescriptor()和Object.defineProperty()对属性所有特性进行复制。
  • 作为不可枚举属性添加到Object.prototype中,所以是Object定义的新方法。

8 对象的属性

  • 原型
  • 可扩展性

8.1 原型属性

  • ES5中Object.getPrototype()可以查询原型
  • ES3中o.constructor.prototype()检测属性
  • 通过new表达式创建的对象通常继承一个constructor属性,指代该对象的构造函数
  • constructor.prototype才是对象直接量的真正原型
  • 检测对象是否处于原型链中,使用isPrototypeOf()

    var p={x:1};var o=Object.create(p);p.isPrototypeOf(o);  //检测p是否是o的原型Object.prototype.isPrototypeOf(o);  //检测Object是否是o的原型
  • __proto__属性用以直接查询/设置对象的原型(IE/Opera不支持)==>并不推荐使用

  • ES5 Firefox依然支持,但对修改不可扩展对象的原型做了限制

8.2 类属性(一个字符串,表示对象的类型信息)

查询类属性的间接方法(ES3/ES5未提供直接方法):

// 利用 toString()方法function classof(o){    if(o===null)return "Null";    if(o===undefined)return "Undefined";    return Object.prototype.toString.call(o).slice(8,-1); //返回第8到倒2位置直接的字符    }    // 为了防止继承使toString被重写,必须间接调用Function.call()【8.7.3】方法。classof()可以传入任何类型参数。

8.3 可扩展性(表示是否可以添加新属性)

  • 所有内置对象和自定义对象都是显式可扩展的(除非转换)

  • 判断是否可查询,可用ObjectesExtensible()。

  • 可扩展==>不可扩展需用Object.preventExtensions(),不可回转,只影响到对象本身的可扩展性。

  • Object.seal将对象设置为不可扩展还可以将对象所有自有属性都设置为不可配置(已有的可写属性依然可以设置),且不能解封。
    因此可以使用Object.isSealed来检测对象是否封闭。

  • Object.freeze()更严格地锁定对象——不可扩展,不可修改,不可配置,只读(但存取器属性具有setter的话,存取器属性将不受影响)

  • 使用Object.isFrozen检测是否冻结


9 序列化对象

  • ES5 提供函数序列化对象:JSON.Stringfy()还原对象:JSON.parse() 两函数都是内置函数
  • JSON——Javescript Object Notation:Javascript对象表示法
  • ES3可以引述json2.js模块,则可以引用ES5的JSON函数
  • JSON对象支持:对象、字符串、无穷大、数字、true、false和null、可序列和还原(NaN、Infinity和-Infinity序列化都为null
  • Date序列化是ISO格式的日期字符串,还原是保留字符串形态,不会还原为原始Date对象。
  • 函数、RegExp、Error对象和undefined值不能序列化和还原。强行序列化,输出字符串会将这个属性省略。

10 对象方法

Object.prototype中的对象方法

1、toString()

  • 无参数
  • 表示调用这个方法的对象值的字符串
  • 数组转化字符串===>每个元素都转换成字符串
  • 函数===>源代码

2、toLocaleString()返回一个表示该对象的本地化字符串

  • Object默认方法反调用toString()
  • Date和Number类对toLocaleString()方法做了定制
  • Array中每个数组元素会调用该方法转换为字符串,而不是调用各自的toString方法

3、 toJSON() 【实际上并没有定义该方法,但执行序列化需用调用】
4、valueOf()与toString()类似。

本文是《JS权威指南》第六章知识点的整理,如果有遗漏、描述不准确或者有错误的地方可以在下方留言,笔者将会十分感谢您的指正。

0 0
原创粉丝点击