JavaScript 系列博客之(四)

前言

本篇介绍 JavaScript 中的对象。在第一篇博客中已经说到 JavaScript 是一种‘’对象模型‘’语言。所以可以这样说,对象是 JavaScript 语言的核心概念,也是最重要的数据类型。

概述

生成方法

在 JavaScript 中声称对象相当方便,直接定义一个空字典就 ok。想要添加属性或者方法的话可以在定义结束之后动态添加。注意:对象时无序的复合数据集合。

上面代码中,大括号就可以直接定义一个对象,被赋值给变量 a,所以 a 就指向一个对象。该对象为一个空对象,但是会有一些默认的方法,像 constructor 是构造方法,想要动态的添加属性和方法就是这个方法的功劳。

在这里添加了一个属性为name,那么 name 是键名(成员名称),字符串 musibii 是键值(成员的值)。键名与键值之间用冒号分隔。如果再添加一个属性,那么属性之间使用逗号分隔。

具体生成方法

// 1.单一对象
var obj = {
// 属性
name: 'Zero',
// 方法
teach: function () {
console.log("教学");
}
};
obj.name | obj.teach() // 2.构造函数
function Person(name) { // 类似于python中的类一样来使用
// this代表Person构造函数实例化出的所有具体对象中的某一个
this.name = name;
this.teach = function () {
console.log(this.name + "正在教学");
}
}
// ①通过构造函数实例化出具体对象
// ②通过对象.语法调用属性与方法
var p1 = new Person("张三");
p1.name // 张三, this指向p1对象
var p2 = new Person("李四");
p2.teach // 李四正在教学, this指向p2对象 // 3.ES6类语法
class Student {
// 需要构造器(构造函数)来完成对象的声明与初始化
constructor (name) {
// 属性在构造器中声明并完成初始化
this.name = name;
}
// 类中规定普通方法
study () {
console.log(this.name + "正在学习");
}
// 类方法
static fn() {
console.log("我是类方法")
}
}
// 类中的普通方法由类的具体实例化对象来调用
// 类中的类方法由类直接来调用(这类型的方法大多是功能性方法,不需要对象的存在)

键名

对象的所有键名都是字符串(ES6又引入了 Symbol 值也可以作为键名:还没了解过),所以加不加引号都可以。如果键名是数值,会被自动转为字符串。如果键名不符合标识名的条件(比如第一个字符为数字,或者含有空格或运算符),且也不是数字,则必须加上引号,否则会报错。

对象的每一个键名又称为‘’属性‘’,它的键值可以是任何数据类型。如果一个属性的值为函数,通常把这个属性称为方法,调用方法和函数一样。

特别的如果属性的值指向的还是一个对象,那么就行成了链式引用。对象的属性之间用逗号分隔,最后一个属性后面可以加逗号,也可以不加。

对象的引用

如果不同的变量名指向同一个对象,那么它们都是这个对象的引用,也就是说指向同一个内存地址。修改其中一个变量,会影响到其他所有的引用。和 JavaScript 中的基本数据类型不一样,复合数据类型是传址传递。

a 和 b指向同一个对象,因此为其中任何一个变量添加属性,另一个变脸都可以读写该属性。如果取消某一个对象的引用,不会影响到其他变量。

这种引用只局限于对象,在之前的博客也提到,两个变量指向同一个原始类型(基本数据类型)的值,那么变量只是对值得拷贝(传值传递)。

属性的操作

属性的读取

读取对象的属性,有两种方法,一种是使用点运算符;另一种是使用方括号运算符。(在 python 中,字典只能通过方括号取值;对象只可以通过点运算符取值。不过可以通过自定义字典类改写 getattr 魔术方法改变。)

注意:如果使用方括号运算符,键名必须放在引号里面,否则会被当做变量处理。

var foo = 'bar';

var obj = {
foo: 1,
bar: 2
}; obj.foo // 1
obj[foo]// 2

上面代码中,引用对象obj 的 foo 属性时,如果使用点运算符,foo 就是字符串;如果使用方括号运算符,但是不使用引号,那么 foo 就是一个变量,指向字符串 bar。

方括号运算符内部还可以使用表达式:

obj['hello' + 'world']
obj[3 + 3]

数字键可以不加引号,因为会自动转为字符串。

var obj = {
0.7: 'hello world'
};
obj['0.7'] // 'Hello World'
obj[0.7] // 'Hello World'

上面代码对象的数字键0.7加不加引号都可以,因为会自动转为字符串。

var obj = {
123: 'Hello musibii'
}; obj.123 // 报错
obj[123] // 'Hello musibii'

如果对数值键名123使用点运算符,会报错,使用方括号运算符才是正确的方式。

属性的赋值

点运算符和方括号运算符,不仅可以用来读取值,还可以用来赋值。

JavaScript 允许属性的后绑定,也就是说可以在任意时刻新增属性,没必要在定义对象的时候就把属性全都定义好。

属性的查看

查看一个对象的所有属性使用 Object.keys 方法。

var obj = {
key1: 1,
key2: 2
}; Object.keys(obj); // [key1, key2]

属性的删除

delete 命令用于删除对象的属性,删除成功后返回 true。

var obj = {
p: 1;
} delete obj.p; // true
obj.p // undefined
Object.keys(obj) // []

上述代码中,delete 命令删除对象 obj 的 p 属性。删除后,再读取 p 属性就会返回 undefined,而且 Object.keys 方法的返回值也不再包括该属性。

注意:删除一个不存在的属性,delete 不会报错而是返回 true。因此不能根据 delete 命令的结果认为某个属性的存在。(那么到底哪种方式才可以证明某个属性的存在与否)

如果删除属性时返回 false那就说明该属性存在,但是不可以删除。

var obj = Object.defineProperty({}, 'p', {
value: 'musibii',
configurable: false
}); obj.p // 'musibii'
delete obj.p // false

上述代码中,通过 Object 的defineProperty方法给对象 obj创建了一个属性,属性的configurable(可配置) 的值为 false,这样的一个属性就是不可以删除的。

另外需要注意的是,delete 命令只能删除对象本身的属性,无法删除继承的属性。

可以看出虽然 delete 命令返回 true,但是删除的属性依然存在。但是如果通过 proto 删除的话就可以删除。

判断属性的存在

in 运算符用于检出对象是否包含某个属性(注意,检查的是键名,不是键值)。如果包含就返回 true,否则就返回 false。它的左边是一个字符串,表示属性名,右边则是一个对象。

var obj = {p: 1};
'p' in obj //true
'toString' in obj // true

拿上面删除的 constructor 来说:

in 运算符的一个问题是,它不能识别哪些属性时对象自身的,哪些属性是继承的。就像上面,对象 obj 本身并没有 toString 属性,但是 in 运算符会返回 true,因为这个属性是继承的。

这时可以通过对象的 hasOwnProperty 方法判断,是否为对象自身属性

var obj = {};
if ('toString' in obj) {
console.log(obj.hasOwnProperty('toString')); // fasle
}

属性遍历

for...in 循环用来遍历一个对象的所有属性。

for...in 循环有两个注意点;

  • 它遍历的是对象所有可遍历的属性,会跳过不可遍历的属性;
  • 它不仅遍历对象自身的属性,还遍历继承的属性。

如果继承的属性是可遍历的,那么就会被 for...in 循环遍历到。但是,一般情况下,都是只想遍历对象自身的属性,所以使用 for...in 的时候,应该结合使用 hasOwnProperty 方法,在循环内部判断一下,某个属性是否为对象自身的属性。

var person = {name: '老张'};

for (var key in person) {
if (person.hasOwnProperty(key)) {
console.log(key);
}
} // name

with 语句

with 语句的格式如下:

with (对象) {
语句;
}

它的作用是操作同一个对象的多个属性时,提供一些书写的方便。

注意:如果 with 区块内部有变量的赋值操作,必须是当前对象已经存在的属性,否则会创造一个当前作用域的全局变量。

var obj = {};
with (obj) {
p1 = 4,
p2 = 5
} obj.p1 // undefined
p1 // 4

上面代码中,对象 obj 并没有 p1属性,对 p1赋值等于创造了一个全局变量 p1.正确的写法应该是,先定义对象 obj 的属性 p1,然后在 with 区块内操作它。

这是因为 with 区块没有改变作用域,它的内部依然是当前作用域。这造成了with 语句的一个很大的弊病,就是绑定对象不明确。

with (obj) {
console.log(x);
}

单纯从上面的代码块,根本无法判断 x 到底是全局变量,还是对象 obj 的一个属性。这非常不利于代码的除错和模块化,编译器也无法对这段代码进行优化,只能留到运行时判断,这就拖慢了运行速度。因此,建议不要使用 with 语句,可以考虑用一个临时变量代替 with。

with (obj1.obj2.obj3) {
console.log(p1 + p2);
}
// 可以写为
var temp = obj1.obj2.obj3;
console.log(temp.p1 + temp.p2);

JavaScript 系列博客(四)的更多相关文章

  1. JavaScript 系列博客(一)

    JavaScript 系列博客(一) 前言 本系列博客为记录学习 JavaScript 的学习笔记,会从基础开始慢慢探索 js.今天的学习笔记主要为 js 引入.定义变量以及 JavaScript 中 ...

  2. JavaScript 系列博客(七)

    JavaScript 系列博客(七) 前言 本篇博客介绍页面节点概念.文档结构以及如何使用 js 操作文档节点还有事件 target 以及 BOM 操作. 节点 dom与dom属性 // DOM: 文 ...

  3. JavaScript 系列博客(六)

    JavaScript 系列博客(六) 前言 本篇博客介绍 js 操作高级,通过 js 获取标签的全局属性.设置标签的全局属性,以及事件的绑定与取消.js 盒模型与 js 动画. 对象使用的高级 对象的 ...

  4. JavaScript 系列博客(五)

    JavaScript 系列博客(五) 前言 本篇博客学习 js 选择器来控制 css 和 html.使用事件(钩子函数)来处理事件完成后完成指定功能以及js 事件控制页面内容. js 选择器 在学习 ...

  5. JavaScript 系列博客(三)

    JavaScript 系列博客(三) 前言 本篇介绍 JavaScript 中的函数知识. 函数的三种声明方法 function 命令 可以类比为 python 中的 def 关键词. functio ...

  6. JavaScript 系列博客(二)

    JavaScript 系列博客(二) 前言 本篇博客介绍 js 中的运算符.条件语句.循环语句以及数组. 运算符 算术运算符 // + | - | * | / | % | ++ | -- consol ...

  7. Django 系列博客(十四)

    Django 系列博客(十四) 前言 本篇博客介绍在 html 中使用 ajax 与后台进行数据交互. 什么是 ajax ajax(Asynchronous Javascript And XML)翻译 ...

  8. Django 系列博客(四)

    Django 系列博客(四) 前言 本篇博客介绍 django 如何和数据库进行交互并且通过 model 进行数据的增删查改 ORM简介 ORM全称是:Object Relational Mappin ...

  9. JavaScript学习系列博客_1_JavaScript简介

    这个系列博客主要用来记录本人学习JavaScript的笔记,从0开始,即使有些知识我也是知道的.但是会经常忘记,干脆就写成博客,没事的时候翻来看一看,留下一点学习的痕迹也好.可能写博客的水平暂时不太好 ...

随机推荐

  1. PHP引用(&)练习

    <?php class talker { private $data = 'Hi'; public function & get(){ //返回值指向一个内容,这里是指向$data的内容 ...

  2. Splinter常用API介绍(转)

    # Example from splinter import Browser with Browser() as browser: # Visit URL url = "http://www ...

  3. Jmeter学习过程中遇到的那些坑

    开个新帖,持续记录学习jmeter过程中遇到的坑... (1)出师不利 由于公司的产品都是客户端模式,所以所有的接口测试都从获取access-token开始.妹的...上来就是一个坑... 一开始的配 ...

  4. html、css基础整理

    1.块元素与行内元素之间的转换: HTML可以将元素分类方式分为行内元素.块状元素和行内块状元素三种.这三者是可以互相转换的,使用display属性能够将三者任意转换: (1)display:inli ...

  5. impala教学视频

    https://www.iqiyi.com/playlist394935102.html

  6. postgresql数据库查询慢SQL

    --查询总耗时最长SQLselect * from pg_stat_statements order by total_time desc;--查询平均耗时最长SQLselect * from pg_ ...

  7. pycharm激活码

    MTW881U3Z5-eyJsaWNlbnNlSWQiOiJNVFc4ODFVM1o1IiwibGljZW5zZWVOYW1lIjoiTnNzIEltIiwiYXNzaWduZWVOYW1lIjoiI ...

  8. 201671010147 2017年8月27号 初学java的感想

    在IT行业中,java无疑是最热门的,很多企业也青睐java,因为他的扩展性好,可以处理更多客户的数据,正是因为java有前景所以才吸引更多人去学习.在大一我们已经接触vhleC语言,大二开始就解除了 ...

  9. MySQL--自增列学习

    ##=====================================================================================## 在数据库表设计中会纠 ...

  10. 安全圈玩起了直播,"学霸”带你玩转CTF

    [i春秋]安全圈玩起了直播,"学霸”带你玩转CTF 跟着学霸(汪神)打CTF,摸清CTF套路 汪神,是浙江大学电气工程系的“风云人物”,曾因首度破解特斯拉汽车安全系统而名声大噪.本套题目是自 ...