第三章 对象

1、语法

两种形式定义:声明(文字)形式和构造形式

(1)文字语法大概是这样

1 var myObj = {
2 key: value
3 // ...
4 };

(2)构造形式大概是这样

1 var myObj = new Object();
2 myObj.key = value;

两者其实都是一样的,唯一区别就是,在文字声明中可以添加多个键值对,但是在构造形式中必须逐个添加

2、类型

javascript总共有六种主要类型(语言类型):string、 number、boolean、null、undefined、object

(1)内置对象(javascript里面一些对象子类型)

String、Number、Boolean、Object、Function、Array、Date、RegExp、Error

实际上他们是内置函数,内置函数可以当作构造函数来使用,从而可以构造一个对应子类型的新对象

举个栗子,第一个的原始值"I am a string"并不是一个对象,只是一个字面量并且是一个不可变的值。如果要在这个字面量上执行一些操作,比如获取长度、访问其中某个字符窜等,都需要将其转换为String对象。

1 var strPrimitive = "I am a string";
2 typeof strPrimitive; // "string"
3 strPrimitive instanceof String; // false
4 var strObject = new String( "I am a string" );
5 typeof strObject; // "object"
6 strObject instanceof String; // true
7 // 检查 sub-type 对象
8 Object.prototype.toString.call( strObject ); // [object String]

但是在必要时语言会自动把字符串字面量转换成一个 String 对象,也就是说你并不需要显式创建一个对象。引擎自动把字面量转换为String对象。

var strPrimitive = "I am a string";
console.log( strPrimitive.length ); // 13
console.log( strPrimitive.charAt( 3 ) ); // "m"

3、内容

存储在对象容器内部的是这些属性的名称,它们就像指针(从技术角度来说就是引用)一样,指向这些值真正的存储位置。在对象中,属性名永远都是字符串。

属性和方法

即使你在对象的文字形式中声明一个函数表达式,这个函数也不会“属于”这个对象——它们只是对于相同函数对象的多个引用

1 var myObject = {
2 foo: function() {
3 console.log( "foo" );
4 }
5 };
6 var someFoo = myObject.foo;
7 someFoo; // function foo(){..}
8 myObject.foo; // function foo(){..}

4、数组

数组也是对象,所以虽然每个下表都是整数,但是仍然可以给数组添加属性(但是不推荐),

最好只用对象来存储键 / 值对,只用数组来存储数值下标 / 值对

var myArray = [ "foo", 42, "bar" ];
myArray.baz = "baz";
myArray.length; // 3
myArray.baz; // "baz"

5、复制对象(浅复制和深复制)

(1)浅复制:ES6定义了Object.assign(...)方法来实现浅复制。Object.assign(...)方法的第一个参数是目标对象。它会遍历一个或多个源对象的所有可枚举的自有键并把它们复制(使用=操作符赋值)到目标对象,最后返回目标对象。

【由于 Object.assign(..) 就是使用 = 操作符来赋值,所以源对象属性的一些特性(比如 writable )不会被复制到目标对象】举个栗子:

function anotherFunction() { /*..*/ }
var anotherObject = {
c: true
};
var anotherArray = [];
var myObject = {
a: 2,
b: anotherObject, // 引用,不是复本!
c: anotherArray, // 另一个引用!
d: anotherFunction
};
anotherArray.push( anotherObject, myObject ); var newObj = Object.assign( {}, myObject );
newObj.a; // 2
newObj.b === anotherObject; // true
newObj.c === anotherArray; // true
newObj.d === anotherFunction; // true

6、属性描述

从 ES5 开始,所有的属性都具备了属性描述符。

三个特性: writable (可写)、enumerable (可枚举)和 configurable (可配置)

在创建普通属性时属性描述符会使用默认值,我们也可以使用 Object.defineProperty(..)来添加一个新属性或者修改一个已有属性(如果它是 configurable )并对特性进行设置。

var myObject = {};
Object.defineProperty( myObject, "a", {
value: 2,
writable: true,
configurable: true,
enumerable: true
} );
myObject.a; // 2

7、Getter 和 Setter

在 ES5 中可以使用 getter 和 setter 部分改写默认操作,但是只能应用在单个属性上,无法应用在整个对象上。getter 是一个隐藏函数,会在获取属性值时调用。setter 也是一个隐藏函数,会在设置属性值时调用。

 1 var myObject = {
2 // 给 a 定义一个 getter
3 get a() {
4 return 2;
5 }
6 };
7 Object.defineProperty(
8 myObject, // 目标对象
9 "b", // 属性名
10 { // 描述符
11 // 给 b 设置一个 getter
12 get: function(){ return this.a * 2 },
13 // 确保 b 会出现在对象的属性列表中
14 enumerable: true
15 }
16 );
17 myObject.a; // 2
18 myObject.b; // 4

通常来说 getter 和 setter 是成对出现的(只定义一个的话通常会产生意料之外的行为)

 1 var myObject = {
2 // 给 a 定义一个 getter
3 get a() {
4   return this._a_;
5 },
6 // 给 a 定义一个 setter
7 set a(val) {
8   this._a_ = val * 2;
9 }
10 };
11 myObject.a = 2;
12 myObject.a; // 4

8、枚举

举个栗子:

 1 var myObject = { };
2 Object.defineProperty(
3 myObject,
4 "a",
5 // 让 a 像普通属性一样可以枚举
6 { enumerable: true, value: 2 }
7 );
8 Object.defineProperty(
9 myObject,
10 "b",
11 // 让 b 不可枚举
12 { enumerable: false, value: 3 }
13 );
14 myObject.b; // 3
15 ("b" in myObject); // true
16 myObject.hasOwnProperty( "b" ); // true
17 // .......
18 for (var k in myObject) {
19 console.log( k, myObject[k] );
20 }
21 // "a" 2

myObject.b 确实存在并且有访问值,但是却不会出现在 for..in 循环中(尽管可以通过 in 操作符来判断是否存在)。原因是“可枚举”就相当于“可以出现在对象属性的遍历中”

还有另外一个方法可以区分属性是否可枚举

var myObject = { };
Object.defineProperty(
myObject,
"a",
// 让 a 像普通属性一样可以枚举
{ enumerable: true, value: 2 }
);
Object.defineProperty(
myObject,
"b",
// 让 b 不可枚举
{ enumerable: false, value: 3 }
);
myObject.propertyIsEnumerable( "a" ); // true
myObject.propertyIsEnumerable( "b" ); // false
Object.keys( myObject ); // ["a"]
Object.getOwnPropertyNames( myObject ); // ["a", "b"]
  • propertyIsEnumerable(..) 会检查给定的属性名是否直接存在于对象中(而不是在原型链上)并且满足 enumerable:true 。
  • Object.keys(..) 会返回一个数组,包含所有可枚举属性, Object.getOwnPropertyNames(..)会返回一个数组,包含所有属性,无论它们是否可枚举。
  • in 和 hasOwnProperty(..) 的区别在于是否查找 [[Prototype]] 链,然而, Object.keys(..)和Object.getOwnPropertyNames(..) 都只会查找对象直接包含的属性。

9、遍历

ES5 中增加了一些数组的辅助迭代器,包括 forEach(..) 、 every(..) 和 some(..) 。每种辅助迭代器都可以接受一个回调函数并把它应用到数组的每个元素上,唯一的区别就是它们对于回调函数返回值的处理方式不同。

1、forEach(..) 会遍历数组中的所有值并忽略回调函数的返回值。

2、 every(..) 会一直运行直到回调函数返回 false (或者“假”值)

3、some(..) 会一直运行直到回调函数返回 true (或者“真”值)

但是上面的方法都只是遍历下标,怎样可以直接遍历值而不是数组的下标(或者对象属性)?噔噔噔噔...ES6增加了一种用来遍历数组的for..of循环语法【如果对此熬过本身定义了迭代器的话也可以遍历对象】:

1 var myArray = [ 1, 2, 3 ];
2 for (var v of myArray) {
3 console.log( v );
4 }
5 // 1
6 // 2
7 // 3

上面的例子,for..of循环首先会向被访问对象请求一个迭代器对象,然后通过调用迭代器对象的next()方法来遍历所有返回值。for..of只适用于数组,数组有内置的 @@iterator ,因此 for..of 可以直接应用在数组上。

1 ar myArray = [ 1, 2, 3 ];
2 var it = myArray[Symbol.iterator]();
3 it.next(); // { value:1, done:false }
4 it.next(); // { value:2, done:false }
5 it.next(); // { value:3, done:false }
6 it.next(); // { done:true }

但是,和数组不一样,普通的对象里面并没有内置对象@@iterator ,所以无法自动完成for..of遍历。但是可以给任何想遍历的对象定义 @@iterator

 1 var myObject = {
2 a: 2,
3 b: 3
4 };
5 Object.defineProperty( myObject, Symbol.iterator, {
6 enumerable: false,
7 writable: false,
8 configurable: true,
9 value: function() {
10 var o = this;
11 var idx = 0;
12 var ks = Object.keys( o );
13 return {
14 next: function() {
15 return {
16 value: o[ks[idx++]],
17 done: (idx > ks.length)
18 };
19 }
20 };
21 }
22 } );
23 // 手动遍历 myObject
24 var it = myObject[Symbol.iterator]();
25 it.next(); // { value:2, done:false }
26 it.next(); // { value:3, done:false }
27 it.next(); // { value:undefined, done:true }
28 // 用 for..of 遍历 myObject
29 for (var v of myObject) {
30 console.log( v );
31 }
32 // 2
33 // 3

你不知道的JavaScript(上)this和对象原型(二)的更多相关文章

  1. 读书笔记-你不知道的JavaScript(上)

    本文首发在我的个人博客:http://muyunyun.cn/ <你不知道的JavaScript>系列丛书给出了很多颠覆以往对JavaScript认知的点, 读完上卷,受益匪浅,于是对其精 ...

  2. 《你不知道的javascript(上)》笔记

    作用域是什么 编译原理 分词/词法分析 这个过程会将由字符组成的字符串分解成(对编程语言来说)有意义的代码块,这些代码块被称为词法单元 解析/语法分析 词法单元流(数组)转换成一个由元素逐级嵌套所组成 ...

  3. 你不知道的JS之 this 和对象原型(一)this 是什么

     原文:你不知道的js系列 JavaScript 的 this 机制并没有那么复杂 为什么会有 this? 在如何使用 this 之前,我们要搞清楚一个问题,为什么要使用 this. 下面的代码尝试去 ...

  4. 《你不知道的Javascript》感悟篇—对象属性遍历的那些事

    划重点 本篇笔者将重点介绍JavaScript中 getOwnPropertyNames .Object.keys.for ... in 的使用及他们之间的异同点. getOwnPropertyNam ...

  5. JavaScript -基础- 函数与对象(二)String

    一.判断数据类型typeof与判断对象类型instanceof 1.typeof typeof只能判断基础数据类型,无法判断引用数据类型 <script> var s="hell ...

  6. JavaScript的构造器与对象(二)

    constructor 的用法:对象的构造函数  每一个函数的Prototype属性指向的对象都包含唯一一个不可枚举属性constructor,该属性的值是这么一个对象:它指向了它所在的构造函数. 语 ...

  7. JavaScript对象原型

    一.MDN上的解释(有点抽象) 基于原型的语言? JavaScript 常被描述为一种基于原型的语言 (prototype-based language)——每个对象拥有一个原型对象,对象以其原型为模 ...

  8. JavaScript 之 原型对象、对象原型 —— { }

    JavaScript -- 构造函数 // 构造函数 function Player(name, age) { this.name = name; this.age = age; } JavaScri ...

  9. JavaScript中的对象与原型—你不知道的JavaScript上卷读书笔记(四)

    一.对象 对象可以通过两种形式定义:声明(文字)形式和构造形式.即: var myObj = { key: value // ... }; 或: var myObj = new Object(); m ...

  10. 《你必须知道的javascript(上)》- 2.this与对象原型

    1 关于this 1.1 为什么使用this 随着你的使用模式越来越复杂,显式传递上下文对象会让代码变得越来越混乱,使用this则不会这样.当我们介绍对象和原型时,你就会明白函数可以自动引用合适的上下 ...

随机推荐

  1. 菜鸟手把手学Shiro之shiro授权流程

    一.首先我们从整体去看一下授权流程,然后再根据源码去分析授权流程.如下图: 流程如下: 1.首先调用 Subject.isPermitted*/hasRole*接口,其会委托给 SecurityMan ...

  2. Nginx服务器安装及配置解释

    nginx是高性能的轻量级web服务器. 特性: 1.http代理 2.反向代理 3.负载均衡 4.缓存机制 一,安装及启动(centos7,nginx 1.14.0) 1.下载 wget http: ...

  3. ubuntu 16.04上源码编译opengv | compile opengv on ubuntu 16.04

    本文首发于个人博客https://kezunlin.me/post/1e5d14ee/,欢迎阅读! compile opengv on ubuntu 16.04 Series compile open ...

  4. pwnable.kr第二天

    3.bof 这题就是简单的数组越界覆盖,直接用gdb 调试出偏移就ok from pwn import * context.log_level='debug' payload='A'*52+p32(0 ...

  5. Three.js - 走进3D的奇妙世界

    本文将通过Three.js的介绍及示例带我们走进3D的奇妙世界. 文章来源:宜信技术学院 & 宜信支付结算团队技术分享第6期-支付结算部支付研发团队前端研发高级工程师-刘琳<three. ...

  6. webpackd学习的意义

    高速发展的前端技术,与浏览器支持的不相匹配.导致前端必须把前端比较先进的技术进行一层编码从而使得浏览器可以加载. 比如前端框架Vue,Angular,React.Less,Sass.TypeScrip ...

  7. DG中模拟failover故障与恢复

    问题描述:情形是当主库真正出现异常之后,才会执行的操作,那么我们执行过failover 之后,如何在重新构建DG,这里我们利用flashback database来重构.模拟前主库要开启闪回区,否则要 ...

  8. logistic回归介绍以及原理分析

    1.什么是logistic回归? logistic回归虽然说是回归,但确是为了解决分类问题,是二分类任务的首选方法,简单来说,输出结果不是0就是1 举个简单的例子: 癌症检测:这种算法输入病理图片并且 ...

  9. QQ登录功能之如何获取用于本地测试的APPID

    本文主要说明一下开发者如何在QQ互联创建测试应用,从而分配给我们一套APP ID和APP KEY,在我们平时学习的时候使用. 一.QQ互联注册开发者 要想使用QQ登陆的功能,首先你必须是腾讯开发者.腾 ...

  10. 获取Zabbix 中资源的使用率

    import pymysql as MySQLdb import time import datetime import xlsxwriter # zabbix数据库信息: zdbhost = 'xx ...