JavaScript基础

JavaScript基础知识点解读—对象

2018-07-05  本文已影响0人  狂躁的山羊

在这篇文章中来说一说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的世界中,宏观意义上一切事物皆对象。这句话该如何理解,希望能抛砖引玉,期待你们的答复。

上一篇下一篇

猜你喜欢

热点阅读