JavaScript基础知识点解读—对象

在这篇文章中来说一说JavaScript中的“对象”。

凡是接触过经典面向对象编程语言(比如Java、C++等)的同学应该知道经典面向对象思想中一个核心概念就是“类”,世间万物按照一定特性皆可按类划分,一类事物中有一些共同特性。比如动物是一类,植物是一类···动物这类里面的每个对象(实例)都有一个共同的特性就是“会动”···

然而当我们的大脑经过Java那些语言的特性洗礼过之后去接受JavaScript中的对象心里难免有些不爽。你会在JavaScript思考如何定义一个类(尤其是在es6之前,es6中引入了class关键词)?你还会思考JavaScript中的类和对象到底是什么东东?

不用怕,我们一点点分析JavaScript中的对象。

JavaScript对象是基于引用类型创建,存储于堆内存中,是一组数据(属性和值)和功能(函数)的集合

创建对象

es5创建对象
《JavaScript高级程序设计》中提供了多种方式(如工厂模式、构造函数模式、原型模式···),他们都是基于下面几种方式衍生出来的。

// 1
var obj1 = {
  name: 'Zhang san'
};
// 2
var obj2 = new Object();
obj2.name = 'Li si';
// 3
function Person(name, age) {
  this.name = name;
  this.age = age;
  this.sayName = function() {
    console.log(this.name);
   }
}
var obj3 = new Person('Wang wu', 27);
// 4
var obj4 = Object.create({'name':'Zhao liu'});
console.log(obj4); // {}
console.log(obj4.name); // 'Zhao liu'

第一种字面量创建方式非常简单。
第二种和第三种都是基于构造函数进行创建。
第四种方式是不是感觉很诡异?没关系,我们后面文章中解开揭开它的面纱。

在Java等经典面向对象语言中new关键词后面那个构造函数的名字应该是它们的“类”。但是在在es6之前并没有类的概念,Object和Person是构造函数,通过构造函数即可创建一个对象实例。

注意,JavaScript中的构造函数也是函数,也是可以执行的。任何函数,只要通过new操作符来调用,那它就可以作为构造函数;而任何函数,如果不通过new操作符来调用,那它跟普通函数一样。关于JavaScript函数我们会在后续文章中专门讨论。

// 当构造函数使用
function Person(name, age) {
  this.name = name;
  this.age = age;
  console.log('我是构造函数,我也可以执行的哦!');
}
var person = new Person('Wang wu', 27);
console.log(person.name); // Wang wu
// 作为普通函数使用
Person('Jack', 22); // "我是构造函数,我也可以执行的哦"  //同时将属性添加到window对象里面
console.log(window.name); // Jack

思考!使用new关键词操作一个构造函数生成一个对象实例的过程中经历了哪些步骤?

  1. 创建一个新对象(在堆内存中申请一块空间);
  2. 将构造函数的作用域赋给新对象(因此this就指向了这个新对象);
  3. 执行构造函数中的代码(为这个新对象添加属性);
  4. 返回新对象。
var person = new Person('Wang wu', 27);
//具体的的执行过程
var person = {}; // 第一步
this = person; // 第二步
person.name = 'Wang wu'; // 第三步
person.age = 27; // 第三步
return person; // 第四步

es6创建对象
es6 提供了更接近传统语言的写法,引入了 Class(类)这个概念,作为对象的模板。通过class关键字,可以定义类。

es6 的class可以看作只是一个语法糖,它的绝大部分功能es5 都可以做到,新的class写法只是让对象原型的写法更加清晰、更像面向对象编程的语法而已。

class Person {
  // 构造函数
  constructor(name, age) {
    this.name = name;
    this.age = age;
  }
  // 下面的方法都是定义在es5构造函数prototype上来实现
  sayName() {
    console.log(this.name);
  }
}

关于class的详细介绍请查阅阮一峰的Class的基本语法

操作对象

  1. 获取对象中的所有属性
// 如果对象中某一属性的enumerable为false,则该属性是不能被循环出来
for(x in person) {
  console.log(x); // name age
}
  1. 对象属性类型(Object.defineProperty())
    JavaScript对象的属性类型分为数据属性和访问器属性
// 数据属性
var person = {};
Object.defineProperty(person, "name", {
  configurable: true, // 能否通过delete删除属性从而重新定义属性
  enumerable: true, // 能否通过for-in循环返回属性
  writable: true, // 能否修改属性的值
  value: "Jack" // 属性值
});
// 访问器属性
var cat = {
  name: "Tom",
  color: "gray"
};
Object.defineProperty(cat, "name", {
  configurable: true, // 能否通过delete删除属性从而重新定义属性
  enumerable: true, // 能否通过for-in循环返回属性
  get: function() {
    return this.name;
  },
  set: function(newValue) {
    this.color = newValue;
  }
});

对象的数据属性和访问器属性是非常重要的,尤其是其访问器属性,在现在流行的angular.js和vue.js的双向数据绑定都是基于这一特性实现。我们会在后续文章中深入探索。

Object对象

思考!上面代码中的Object是什么?它和Object()构造函数有什么关系?

JavaScript 原生提供Object对象(注意起首的O是大写),JavaScript的所有其他对象都继承自Object对象,即那些对象都是Object的实例。

var obj = {};
console.log(obj instanceof Object) // true

var arr = [];
console.log(arr instanceof Object) // true

function Person(name, age) {
  this.name = name;
  this.age = age;
}
var person = new Person("rose", 22);
console.log(person instanceof Person) // true
consle.log(person instanceof Object) // true

Object对象有一些原生方法,这些方法分成两类:Object本身的方法与Object的实例方法。

  1. Object本身的方法(静态方法)
    什么是Object本身的方法?比如下面这些。
/*遍历对象的属性的方法*/
Object.keys(); 
Object.getOwnPropertyNames(); 

/*对象属性模型的相关方法*/
Object.getOwnPropertyDescriptor() // 获取某个属性的对象描述
Object.defineProperty() // 通过描述对象,定义某个属性
Object.defineProperties() // 通过描述对象,定义多个属性

/*控制对象状态的方法*/
Object.preventExtentions() // 防止对象扩展
Object.isExtensiable() // 判断对象是否可扩展
Object.seal() // 禁止对象可配置
Object.isSealed() // 判断一个对象是否可配置
Object.freeze() // 冻结对象
Object.isFrozen() // 判断一个对象是否被冻结

/*原型链相关方法*/
Object.create() // 该方法可以指定原型对象和属性,返回一个新的对象
Object.getPrototypeOf() // 获取对象的prototype对象
  1. Object的实例方法
    除了静态方法,还有不少方法定义在Object.prototype对象。它们称为实例方法,所有Object的实例对象都继承了这些方法。
Object.prototype.valueOf() // 返回当前对象对应的值
Object.prototype.toString() // 返回当前对象对应的字符串形式
Object.prototype.toLocalString() // 返回当前对象对应的本地字符串形式
Object.prototype.hasOwnProperty()  // 判断某个属性是当前对象自身的属性还是继承自原型对象的属性
Object.prototype.isPrototypeOf() // 判断当前对象是否是另一个对象的原型
Object.prototype.propertyIsEnumerable() // 判断某个属性是否可枚举

上面这些方法的详细介绍请参考《JavaScript 标准参考教程(alpha)》—JavaScript对象

看到这里我们的印象中一直把Object当做JavaScript对象来理解,那么我们看下面的程序输出。

console.log(typeof Object) // "function"

怪了,为什么是“function”?

在JavaScript中Object是构造函数,使用typeof检测返回的是“function”,是可以理解的。再看下面的程序。

console.log(Object()); // "object"
console.log(new Object()); // "object"

Object本身当作工具方法使用时,可以将任意值转为对象。这个方法常用于保证某个值一定是对象。比如下面的写法。详细介绍请阅读JavaScript——Object对象

Object() // 返回一个空对象
Object(null) // 返回一个空对象
Object(undefined) // 返回一个空对象
Object(NaN) // 等同于 new Number(NaN)
Object('') // new String('')length=0
Object(1) // 等同于 new Number(1)
Object('foo') // 等同于 new String('foo')
Object(true) // 等同于 new Boolean(true)

在JavaScript“中对象”和“函数”是什么关系?

在内存方面,“对象”和“函数”都是引用类型。在程序方面,JavaScript中的对象其实可以分为普通对象和函数对象。函数是对象,对象是由函数创造的,这就是函数与对象最简单的关系描述。既然函数也是对象,那么对函数也可以添加相应的属性和方法,比如:

function Person(name, age) {
  this.name = name;
  this.age = age;
}
Person.sayName = function() {
  alert(this.name);
}
Person.job = "programer";
console.log(Person.job); // "programer"

看到这里知道为什么Object既可以当做一个对象使用其自带的一些方法,也可以当做构造函数来生成相应的对象实例了吧。
关于普通对象和函数对象的详细介绍请阅读最详尽的 JS 原型与原型链终极详解,没有「可能是」

在JavaScript的世界中,宏观意义上一切事物皆对象。这句话该如何理解,希望能抛砖引玉,期待你们的答复。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 221,135评论 6 514
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 94,317评论 3 397
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 167,596评论 0 360
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,481评论 1 296
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,492评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 52,153评论 1 309
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,737评论 3 421
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,657评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,193评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,276评论 3 340
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,420评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 36,093评论 5 349
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,783评论 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,262评论 0 23
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,390评论 1 271
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,787评论 3 376
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,427评论 2 359

推荐阅读更多精彩内容

  • 第2章 基本语法 2.1 概述 基本句法和变量 语句 JavaScript程序的执行单位为行(line),也就是一...
    悟名先生阅读 4,151评论 0 13
  • JavaScript面向对象程序设计 本文会碰到的知识点:原型、原型链、函数对象、普通对象、继承 读完本文,可以学...
    moyi_gg阅读 764评论 0 2
  • 函数和对象 1、函数 1.1 函数概述 函数对于任何一门语言来说都是核心的概念。通过函数可以封装任意多条语句,而且...
    道无虚阅读 4,572评论 0 5
  • 《道德经》第三十二章 (原文译文/古文典籍大全) 道常无名,朴。虽小,天下莫能臣。侯王若能守之,万物将自宾。天地相...
    燦々阅读 582评论 0 0
  • 第一次参加禅修,第一次禁语,我感觉整个晚上都在各种妄念中度过,好像只睡了一小会,一直躺在床上,期待“尺八”声的响起...
    38bf51a0dc06阅读 686评论 4 2