js是面向对象的语言

126 阅读4分钟

js起源

在编程语言中,抽象描述对象有原型和类两种方式,例如C++,java就是使用“类”的方式来描述对象,而JavaScript早年选择了原型。后来因为被要求模仿Java,就在“原型运行时”的基础上引入了new、this、等语言特性。

在ES6之前,大量的JavaScript程序员试图在原型体系的基础上,把JavaScript变得更像基于类的语言,进而产生了很多框架,比如Dojo。

JavaScript对象的特征

不管什么样的编程语言,对象都有下面3个本质特征:

  • 对象具有唯一标识性:看起来相同的两个对象,并非同一个对象(因为唯一标识的内存地址)
  • 对象有状态:同一对象可能处于不同状态之下
  • 对象具有行为:对象的状态可能因为行为发生变迁

var o1 = { a: 1 }; var o2 = { a: 1 }; console.log(o1 == o2); // false

在JavaScript中统一将状态和行为抽象为“属性”。 和其他编程语言一样,JavaScript中的对象都很好的表现了对象的基本特征:标示性、状态和行为。

但是在JavaScript独有的特色是:对象具有动态性,也就是我们可以在运行时为对象添加属性。

JavaScript对象的两类属性

1.数据属性

  • value:就是属性的值。
  • writable:决定属性能否被赋值。
  • enumerable:决定 for in 能否枚举该属性。
  • configurable:决定该属性能否被删除或者改变特征值。 2.访问器属性
  • getter:函数或 undefined,在取属性值时被调用。
  • setter:函数或 undefined,在设置属性值时被调用。
  • enumerable:决定 for in 能否枚举该属性。
  • configurable:决定该属性能否被删除或者改变特征值。 可以用内置函数:getOwnPropertyDescriptor来查看 改变属性特征,或者定义访问器,可以使用object.defineProperty

因为JavaScript区别于主流编程语言一个比较重要的部分:JavaScript是基于原型的方式来实现面向对象的,而像C++,java等基于类来实现面向对象。那么原型的概念就很重要了。

JavaScript的原型

在我的认知里,每个实例上都有一个__proto__的属性(这个属性只是各家浏览器规定的,并不是一种规范),指向构造函数,而几乎每一个构造函数上都有私有字段prototype,指向该构造函数的原型,原型上除了你挂载的属性外,还有constructor,指回构造函数。

早期版本中的类与原型

在早期的JavaScript 版本中,“类”的定义是一个私有属性[[class]],内置类型Number,String等都指定了[[class]]属性。我们唯一访问[[class]]属性的方式是Object.prototype.toString。下面是所有具有内置class属性的对象。

var o = new Object;
var n = new Number;
var s = new String;
var b = new Boolean;
var d = new Date;
var arg = function(){ return arguments }();
var r = new RegExp;
var f = new Function;
var arr = new Array;
var e = new Error;
console.log([o, n, s, b, d, arg, r, f, arr, e].map(v => Object.prototype.toString.call(v)));
//(10) ["[object Object]", "[object Number]", "[object String]", "[object Boolean]", "[object Date]", "[object Arguments]", "[object RegExp]", "[object Function]", "[object Array]", "[object Error]"]

在ES5中,[[class]]私有属性被Symbol.toStringTag替代。我们可以使用Symbol.toStringTag来自定义Object.prototype.toString的行为。

var o = { [Symbol.toStringTag]: "MyObject" }
console.log(o + "");//[object MyObject]

因为new运算符是JavaScript面向对象的一部分,所以new运算符具体做了哪些事情是我们需要了解的:

  • 以构造器的prototype属性为原型,创建新对象。
  • 将this和调用参数传给构造器,执行构造器代码。
  • 如果构造器返回的是对象,则返回;否则返回第一步创建的对象。

JavaScript中对象的分类

对象可以分为:

  • 宿主对象:最常见的宿主就是浏览器环境和node环境。
  • 内置对象:由JavaScript语言提供的对象。 内置对象又包含:
  1. 固有对象:由标准规定,随着 JavaScript 运行时创建而自动创建的对象实例。
  2. 原生对象:可以由用户通过 Array、RegExp 等内置构造器或者特殊语法创建的对象(通过构造器,用new创建的新对象)。
  3. 普通对象:由{}语法、Object 构造器或者 class 关键字定义类创建的对象,它能够被原型继承。

另外一种角度看对象分类

对象还可以被分为函数对象和构造器对象,任何对象只需要具有[[call]]私有字段,就可以作为函数被调用;如果具有[[construct]],就可以作为构造器使用。

同时用户用function关键字创建的函数必定同时是函数和构造器,不过,它们表现出来的行为效果却并不相同。而在ES6之后,()=>语法创建的函数仅仅是函数,无法被当成构造器使用。