你不知道的JavaScript(上)this和对象原型(二)
第三章 对象
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和对象原型(二)的更多相关文章
- 读书笔记-你不知道的JavaScript(上)
本文首发在我的个人博客:http://muyunyun.cn/ <你不知道的JavaScript>系列丛书给出了很多颠覆以往对JavaScript认知的点, 读完上卷,受益匪浅,于是对其精 ...
- 《你不知道的javascript(上)》笔记
作用域是什么 编译原理 分词/词法分析 这个过程会将由字符组成的字符串分解成(对编程语言来说)有意义的代码块,这些代码块被称为词法单元 解析/语法分析 词法单元流(数组)转换成一个由元素逐级嵌套所组成 ...
- 你不知道的JS之 this 和对象原型(一)this 是什么
原文:你不知道的js系列 JavaScript 的 this 机制并没有那么复杂 为什么会有 this? 在如何使用 this 之前,我们要搞清楚一个问题,为什么要使用 this. 下面的代码尝试去 ...
- 《你不知道的Javascript》感悟篇—对象属性遍历的那些事
划重点 本篇笔者将重点介绍JavaScript中 getOwnPropertyNames .Object.keys.for ... in 的使用及他们之间的异同点. getOwnPropertyNam ...
- JavaScript -基础- 函数与对象(二)String
一.判断数据类型typeof与判断对象类型instanceof 1.typeof typeof只能判断基础数据类型,无法判断引用数据类型 <script> var s="hell ...
- JavaScript的构造器与对象(二)
constructor 的用法:对象的构造函数 每一个函数的Prototype属性指向的对象都包含唯一一个不可枚举属性constructor,该属性的值是这么一个对象:它指向了它所在的构造函数. 语 ...
- JavaScript对象原型
一.MDN上的解释(有点抽象) 基于原型的语言? JavaScript 常被描述为一种基于原型的语言 (prototype-based language)——每个对象拥有一个原型对象,对象以其原型为模 ...
- JavaScript 之 原型对象、对象原型 —— { }
JavaScript -- 构造函数 // 构造函数 function Player(name, age) { this.name = name; this.age = age; } JavaScri ...
- JavaScript中的对象与原型—你不知道的JavaScript上卷读书笔记(四)
一.对象 对象可以通过两种形式定义:声明(文字)形式和构造形式.即: var myObj = { key: value // ... }; 或: var myObj = new Object(); m ...
- 《你必须知道的javascript(上)》- 2.this与对象原型
1 关于this 1.1 为什么使用this 随着你的使用模式越来越复杂,显式传递上下文对象会让代码变得越来越混乱,使用this则不会这样.当我们介绍对象和原型时,你就会明白函数可以自动引用合适的上下 ...
随机推荐
- convert svn repo to git
https://john.albin.net/git/convert-subversion-to-git 1. 抓取Log 在linux 上做的,其余是在win上做的. 2. svn co svn:/ ...
- 2019-10-16:渗透测试,基础学习,burpsuit学习,爆破的四种方式学习
Burp Suite 是用于攻击web 应用程序的集成平台,包含了许多工具.Burp Suite为这些工具设计了许多接口,以加快攻击应用程序的过程.所有工具都共享一个请求,并能处理对应的HTTP 消息 ...
- Java 9 ← 2017,2019 Java → 13 ,都发生了什么?
距离 2019 年结束,只剩下 35 天了.你做好准备迎接 2020 年了吗? 一到年底,人就特别容易陷入回忆和比较之中,比如说这几天, 的对比挑战就火了! 这个话题登上了微博的热搜榜,也刷爆了朋友圈 ...
- 网页采集器-UA伪装
网页采集器-UA伪装 UA伪装 请求载体身份标识的伪装: User-Agent: 请求载体身份标识,通过浏览器发起的请求,请求载体为浏览器,则该请求的User-Agent为浏览器的身份标识,如果使用爬 ...
- c# 窗体开发3 文件处理技术
以字节形式向磁盘写入数据通常称为字节流(比特流) 常常使用System.Io 常用的类 类 说明 File 提供用于创建.复制.删除.移动和打开文件的静态方法,并协助创建 FileStream 对象. ...
- Windows下通过VMWare安装linux
VMWare虚拟机安装linux 虚拟机的概念 虚拟机,其本质其实也是一个程序. 但是这个程序,模仿了一台完整的主机常用的有 VMware,VirtualBox,Microsoft Virtual P ...
- Qt之高DPI显示器(一) - 解决方案整理
目录 DPI发展 1.PPI 2.DPI 一.Win自适应系统 二.Qt机制 1.Windows系统DWM缩放 2. Qt适配高DPI 3.适配DPI结论 三.Qt适配 四.自己适配 1.窗口大小 2 ...
- 基于Docker搭建分布式消息队列Kafka
本文基于Docker搭建一套单节点的Kafka消息队列,Kafka依赖Zookeeper为其管理集群信息,虽然本例不涉及集群,但是该有的组件都还是会有,典型的kafka分布式架构如下图所示.本例搭建的 ...
- 大型情感剧集Selenium:9_selenium配合Pillow完成浏览器局部截图
网页截图 上次提到了selenium的四种截图方法,最终截图了整张网页.但很多时候,我们仅仅需要截图部分的内容.比如截取某个关键信息,或者现在已经不常见的截图验证码(现在都是各种按规则点击-).那么我 ...
- Flink入门(三)——环境与部署
flink是一款开源的大数据流式处理框架,他可以同时批处理和流处理,具有容错性.高吞吐.低延迟等优势,本文简述flink在windows和linux中安装步骤,和示例程序的运行,包括本地调试环境,集群 ...