资讯专栏INFORMATION COLUMN

JavaScript || 对象

lavor / 1545人阅读

摘要:通过对返回字符串切片第位到倒数第位即可获得对象的类型。测试对象是的深拷贝是的子集,不能表示中所有值。序列化结果是,对象序列化结果是日期字符串不能表示函数对象和只能序列化对象自有的可枚举属性。

对象

对象是JavaScript的基本数据类型:属性的无序集合。每个属性key: value和属性描述符descripter组成。

属性名key:字符串或合法的变量标识符;

属性值value:可以是任意JavaScript值(numberstringbooleannullundefined和数组、对象).
value可以是gettersetter

属性描述符descripter:每个属性的三个相关特性writableenumerableconfigurable,其值都是布尔类型,默认都为true

1 创建对象

创建对象有三种方法:对象字面量{a: 1}new Constructor()Object.create()

1.1 对象字面量
var book = {
    "main title": "JavaScript",                   //有空格或其他非标识符、关键字,必须使用双引号
    "sub-title": "The Definitive Guide",
    "for": "all audiences",
    author: {
        firstname: "David",
        lastname: "Flanagan"
    }
}
1.2 new操作符调用构造函数

可以使用new操作符调用一个构造器函数Constructor()创建一个对象。

var o = new String();
var d = new Date();
1.3 Object.create()方法

原型:每个JS对象都有一个与之相关联的原型对象prototype,对象其原型对象上继承属性。(当前对象中的__proto__属性是其原型对象的链接)

所有通过字面量创建的对象的原型都是Object.prototype,一个字面量对象{}相当于调用new Object()

Object.prototype的原型是null,所以null是原型的出口。

Object.create()是一个静态函数(不是提供给对象调用的方法),用于创建对象:

第一个参数:原型对象,创建的新对象以该参数为原型;

第二个参数:可选,用于对对象属性的描述

创建一个没有原型的对象:Object.create(null);

创建一个普通空对象({}new Object()):Object.create(Object.prototype);

2 对象三个特殊属性

每个对象都有与之相关的3个属性:原型prototype、类属性calss attribute、可扩展性extensible attribute

2.1 原型

每个JS对象都与另一个原型对象(prototype),利用原型可以实现继承。

字面量的原型是:Object.prototype

new操作符创建的对象其原型:构造器函数的原型(prototype属性)

Object.create()创建的对象,其原型:第一个参数

查询对象的原型

ES5中定义了Object.getPrototypeOf()函数,来查询对象的原型

利用new创建的对象会继承constructor属性,指向创建该对的构造器函数,所有该对象的原型是:obj.constructor.prototype

字面量{}constructor属性指向Object()

使用isPrototypeOf()方法查看一个对象是否为另一个对象的原型(或处于原型链中)

Array.prototype.isPrototypeOf([]);   //  ==> true

2.2 类属性

对象的类属性class attribute是一个字符串,用来表示对象的信息。ES3与ES5均为提供设置类属性的API,只能通过继承自Object.prototypetoString()方法来简洁查询。

{}.toString();    //  ==> "[object Object]"

通过对返回字符串切片:第8位到倒数第2位即可获得对象的类型。但是许多对象重写了toString()方法,需要间接调用Functioncall()方法

function classof(o) {
    if(o === null) {return "Null";}
    if(o === undefined) {return "Undefined"}
    return Object.prototype.toString.call(o).slice(8, -1);
}

classof()方法可以返回传递给它的任意对象的类型,参数为numberstringboolean时,使用包装类型将其转化为对象,再进行操作。

    classof(null);  // ==> "Null"
    classof(2);  // ==> "Number"
    classof(false);  // ==> "Boolean"
    classof(new Date());  // ==> "Date"
    classof("");  // ==> "String"
    classof({});  // ==> "Object"
    classof([]);  // ==> "Array"
    classof(/./);  // ==> "RegExp"
    classof(window);  // ==> "Window",宿主对象
    function F() {};    //自定义一个构造器函数
    classof(new F());  // ==> "Object"
2.3 可扩展性extensible attribute

对象的课扩展性用来描述对象是否可以添加新的属性。所有的内置对象和自定义对象都是可扩展的,除非将其转化为不可扩展

Object.esExtensible()函数判断传入对象是否可以扩展;

Object.preventExensible()函数将传入的对象设置为不可扩展,并且过程不可逆;只影响对象本身的可扩展性

Object.seal()函数将对象设置为不可扩展,属性描述符configurable设置为false(不能添加新属性,已有的属性不能删除或配置,但是对于writable: true时,可以修改属性的值);过程不可逆

Object.isSealed()函数判断一个对象是否封闭

Object.freeze()函数将对象设置为不可扩展,属性描述符configurable: false;writable: false;只读。valueaccessor property含有setter函数,不受影响

3 组成对象的属性

每个对象是无需的属性集合,属性名可以是合法的变量标识符或字符串;变量值可以是任意JavaScript值;属性由描述符descripter来控制特性;

3.1 属性的查询与设置

属性可以通过.[]来访问:

使用.访问时,其右侧必须是属性名称命名的简单标识符

使用[]访问时,括号内必须是计算结果为字符串的表达式,字符串是属性的名字。变量名为关键字、含有空格或属性名是变量时,必须使用[]

var author = book.author;
var name = author.surname;
var title = book["main title"];

属性的设置:与访问相似,将其放在赋值表达式的左侧

    book.edtion = 6;
    book["main title"] = "ECMAScript";
继承与错误

在查询一个对象是否存在时,先查看自身属性,如果没有;通过原型链逐层向上查找,直到原型链顶端null为止。

如果自身属性与原型链中均为找到,属性访问返回undefined,不报错

如果查询不存在对象的属性,会报错

nullundefined设置属性会报错

3.2 属性删除

使用delete操作符,可以删除对象的属性(其描述符中configurabletrue),并且只能删除自有属性,不能删除继承属性

3.3 属性检测

判断某个属性是否在某个对象中,JS有三种方法:inhasOwnProperty()propertyIsEnumerable()

in:如果对象自身属性或继承属性中包含该属性,返回true;

hasOwnProperty():只有对象自身属性包含该属性时,才返回true

propertyIsEnumerable():只有对象自身属性包含该属性,并且该属性是可以枚举(描述符中enumerable: true;

var o = {a : 1};
"a" in o;  //  ==> true
o.hasOwnProperty("a");  //  ==> true
o.propertyIsEnumerable("a");  //  ==> true

3.4 枚举属性

使用for-in循环可以遍历对象中所有可枚举的属性(包括自身属性与继承属性),把属性名赋值给循环变量。ES5定义了Object.keys()Object.getOwnPropertyNames()两个函数用来枚举属性名称。

Object.keys():返回对象中可枚举的自有属性名组成的数组

Object.getOwnPropertyNames():返回对象所有的自有属性名组成的数组,包括不可枚举的属性

对象继承的内置方法都是不可枚举的,给对象中增加的属性都可以枚举(除非设置其enumerable: false

有许多使用工具库为Object.prototype增加新的属性,这些属性可以被所有对象继承使用,但是在ES5之前,不能将其设置为不可枚举,所以在for-in循环时会被枚举出来。

//过滤继承的属性
for(p in o) {
    if(!o.hasOwnProperty(p)) {continue;}
}
//跳过方法
for(p in o) {
    if(typeof p === "function") {continue;}
}

操作对象属性的工具函数:

/**
 * 枚举属性的工具函数
 * 将对象p中可枚举的属性复制到对象o中,返回对象o;
 * 如果p和o含有同名的属性,则覆盖o中的属性
 * 不处理getter和setter以及复制属性
 */
function extend(o, p) {
  for(let prop in p) {
    o[prop] = p[prop];
  }
  return o;
}

/**
 * 将对象p中可枚举的属性复制到对象o中,返回对象o;
 * 如果o和p有同名属性,不影响o中的属性
 * 不处理getter和setter以及复制属性
 */
function merge(o, p) {
  for(let prop in p) {
    if(o.hasOwnProperty(prop)) {
      continue;
    }
    o[prop] = p[prop];
  }
  return o;
}

/**
 * 如果o中的属性在p中没有同名属性,从o中删除这个属性,并返回o
 */
function restrict(o, p) {
  for(let prop in o) {
    if(!(prop in p)) {
      delete o[prop];
    }
  }
  return o;
}

/**
 * 如果o中的属性在p中存在同名属性,从o中删除这个属性,并返回o
 */
function substrict(o, p) {
  for(let prop in o) {
    if(prop in p) {
      delete o[prop];
    }
  }
  return o;
}

/**
 * 返回一个数组,包含o中可枚举的自有属性的名字
 */
function keys(o) {
  //o必须是对象
  if(typeof o !== "object") {
    throw TypeError();
  }
  var result = [];
  for(let prop in o) {
    if(o.hasOwnProperty(prop)) {
      result.push(prop);
    }
  }
  return result;
}
3.5 属性settergetter

属性的组成:keyvaluedescripter。在ES5中,value可以用一个或两个方法替代(gettersetter方法)

所有JavaScript的value叫做数据属性data property

gettersetter定义的属性叫做存取器属性:accessor property

不同于data propertyaccessor property的读写属性由gettersetter决定。

如果属性同时有gettersetter,它是一个可读写的属性;

如果属性只有getter,它是一个只读的属性;

如果属性只有setter,它是一个只写的属性;读取只写属性总是返回undefined

gettersetter定义
var o = {
    data_prop: value;        //普通数据属性
    
    //存取器属性是成对定义的函数,函数名是该属性名,没有冒号分隔函数体以属性名
    get accessor_prop() {...},
    set accessor_prop(value) {...}
}
var p = {
  //x、y是普通可读写的数据属性
  x: 1.0,
  y: 1.0,

  //r是可读写的存取器属性,具有getter和setter
  //函数结束后要带上逗号
  get r() {return Math.sqrt(this.x * this.x + this.y * this.y)},
  set r(newvalue) {
    var oldvalue = Math.sqrt(this.x * this.x + this.y * this.y);
    var ratio = newvalue / oldvalue;
    this.x *= ratio;
    this.y *= ratio;
  },
  //theta是只读存取器属性,只有getter方法
  get theta() {return Math.atan2(this.y, this.x)}
};

函数体内的this指向表示这个点的对象

3.6 属性的描述符descripter

属性除keyvalue,还有一组用于描述其特性的descripter,其中有writableenumerableconfigurable三个属性,其值都为布尔类型,默认为true

假设将settergetter看做descripter,同理将属性的value也看做descripter

data property的四个特性:valuewritableenumerableconfigurable

accessory property的四个特性:gettersetterenumerableconfigurable

ES5提供操作descripter的API:

调用Object.getOwnPropertyDescripter()函数,获取某个对象中特定自有属性的descirpter

调用Object.getPrototypeOf()函数可以获取继承属性的descirpter

调用Object.defineProperty()函数可以设置属性的特性,或者新建属性,使其具有某种特性

//返回{ value: 1, writable: true, enumerable: true, configurable: true }
Object.getOwnPropertyDescriptor({a: 1}, "a");

//继承属性和不存在的属性,返回undefined
Object.getOwnPropertyDescriptor({});
Object.getOwnPropertyDescriptor({}, "toString");
var o = {};   //创建空对象
//添加一个不可枚举的属性,其值为1
Object.defineProperty(o, "x", {value: 1, writable: true, enumerable: false, configurable: true});

o.x;  //属性存在,但不可枚举, ==>1
Object.keys(o);     //  ==>  []

//对x属性进行修改,使其变为只读
Object.defineProperty(o, "x", {writable: false});

o.x = 2;     //操作失败,但不报错;在严格模式下抛出类型错误
o.x;    //  ==> 1

//属性的值可以配置
Object.defineProperty(o, "x", {value: 2});
o.x;    //  ==> 2

//将x从数据属性修改为存取器属性
Object.defineProperty(o, "x", {get function() {return 0;}});
o.x;   //==> 0

4 序列化对象

序列化对象指将对象的状态转化为字符串,同时可以将JSON字符串转化为对象。ES5内置JSON对象的JSON.stringgify()JSON.parse()可以完成序列化和解析。

var o = {x: 1, y: {z: [false, null, ""]}};   //测试对象
var s =JSON.stringify(o);         //  "{"x":1,"y":{"z":[false,null,""]}}"
var p = JSON.parse(s);         //p是s的深拷贝

JSON是JavaScript的子集,不能表示JavaScript中所有值。

可以表示:objectArraystringnumberbooleannull,可以序列化与还原。infinityNaN序列化结果是nullDate对象序列化结果是日期字符串

不能表示:函数、RegExpError对象和undefined

JSON.stringify()只能序列化对象自有的可枚举属性。

5 Object.prototype对象的方法

hasOwnProperty():检测该属性是否为对象自有属性

propertyIsEnumerable():检测该属性是否是对象自有,并且可枚举的属性

isPrototypeOf:检测某对象是否为另一个对象的原型

toString():无参数,返回调用该方法对象值的字符串,由于功能有限,某些对象重写了该方法:Array.toString()Date.toString()Function.toString()

toLoaclString()Object中的toLoaclString()只是调用toString(),只有DateNumber类对toLoaclString()定制,可以对数字、日期和时间进行本地化处理

6 总结

JS中对象是属性的无序集合,每个对象有三个相关特性:原型prototype、类属性class property、可扩展性extensible

对象的创建三种方法:对象字面量、new调用构造函数和Object.create()

每个属性由三个部分组成:keyvaluedescripter

key只能是字符串或者值为字符串的变量标识符

value可以是任意JavaScript值(数据属性data property);可以是一个或两个方法,gettersetter(控制区属性accessor property

descripterwritableenumerableconfigurable,其值都是布尔类型,默认都为true。可以使用Object.defineProperty()操作描述符特性。

writable指该属性是否可以写入数据;enumerable指该属性是否可以枚举,(使用for-in循环可以列出,ES5提供Object.keys()Object.getOwnPropertyNames());configurable指该属性是否可以用delete操作符删除和配置。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/81811.html

相关文章

  • JavaScript 闯关记

    摘要:对象数组初始化表达式,闯关记之上文档对象模型是针对和文档的一个。闯关记之数组数组是值的有序集合。数组是动态的,根闯关记之语法的语法大量借鉴了及其他类语言如和的语法。 《JavaScript 闯关记》之 DOM(下) Element 类型 除了 Document 类型之外,Element 类型就要算是 Web 编程中最常用的类型了。Element 类型用于表现 XML 或 HTML 元素...

    mj 评论0 收藏0
  • JavaScript深入浅出

    摘要:理解的函数基础要搞好深入浅出原型使用原型模型,虽然这经常被当作缺点提及,但是只要善于运用,其实基于原型的继承模型比传统的类继承还要强大。中文指南基本操作指南二继续熟悉的几对方法,包括,,。商业转载请联系作者获得授权,非商业转载请注明出处。 怎样使用 this 因为本人属于伪前端,因此文中只看懂了 8 成左右,希望能够给大家带来帮助....(据说是阿里的前端妹子写的) this 的值到底...

    blair 评论0 收藏0
  • JavaScript中的面向对象(object-oriented)编程

    摘要:对象在中,除了数字字符串布尔值这几个简单类型外,其他的都是对象。那么在函数对象中,这两个属性的有什么区别呢表示该函数对象的原型表示使用来执行该函数时这种函数一般成为构造函数,后面会讲解,新创建的对象的原型。这时的函数通常称为构造函数。。 本文原发于我的个人博客,经多次修改后发到sf上。本文仍在不断修改中,最新版请访问个人博客。 最近工作一直在用nodejs做开发,有了nodejs,...

    JerryZou 评论0 收藏0
  • 10分钟了解Javascript-天码营

    摘要:然后将构造函数的原型设为,便实现了对象继承。首先,我们定义一个构造函数,并在其中定义一个局部变量。这里的是局部变量,其作用域仍然存在是闭包现象,而非对象属性。 Javascript是动态的,弱类型的,解释执行的程序设计语言。 Javascript极其灵活,支持多种程序设计范式:面向对象、指令式、函数式。JavaSCript最初被用于浏览器脚本,现在已经是所有主流浏览器的默认脚本语言。浏...

    trigkit4 评论0 收藏0
  • JavaScriptCore全面解析

    摘要:可嵌入动态文本于页面,对浏览器事件作出响应,读写元素,控制等。年月,发布了一款面向普通用户的新一代的浏览器版,市场份额一举超过。网景将这门语言作为标准提交给了欧洲计算机制造协会。线程和的并发执行都是线程安全的。后面会详细讲解对象类型的转换。 本文由云+社区发表作者:殷源,专注移动客户端开发,微软Imagine Cup中国区特等奖获得者 JavaScript越来越多地出现在我们客户端开...

    OnlyMyRailgun 评论0 收藏0
  • JavaScript设计模式与开发实践 | 01 - 面向对象JavaScript

    摘要:在中,并没有对抽象类和接口的支持。例如,当对象需要对象的能力时,可以有选择地把对象的构造器的原型指向对象,从而达到继承的效果。本节内容为设计模式与开发实践第一章笔记。 动态类型语言 编程语言按数据类型大体可以分为两类:静态类型语言与动态类型语言。 静态类型语言在编译时已确定变量类型,动态类型语言的变量类型要到程序运行时,待变量被赋值后,才具有某种类型。 而JavaScript是一门典型...

    suxier 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<