js 对象与类 -- ES5、ES6构造函数与类创建对象的详细区别

247 阅读4分钟

对象:most things are objects

  • 对象 = 属性 + 方法: 对象包(Object package, 或叫namespace)封装着数据,使得数据的访问和组织简洁;对象常作为数据存储体(data stiores),在网络上运输数据; 对象是一种代码重用的形式(Object package);

  • 创建对象的方式:1. 手动创建对象-literal; 2. 实例化创建;3. 其他,如Object.create

  • 属性

    • 属性 = name(type: string) + descriptor(type: Object)

      描述对象包括以下属性:

      configuratableenumablevaluewritablegetset
      数据描述符××
      存取描述符××
    • 表示方法: 1. obj.name -- 索引选择元素 2. obj['name'] -- 关联值的名字 // 对象做了字符串到值得映射,数组做了数字到值得映射

  • this指向运行时得对象: the current object the code is being written inside;

    • this在字面量对象中可能无法发挥优势,但在动态创建的对象中十分有用
    • this在运行时绑定,this的值取决于调用它的方式
    • 通过this指向的改变,允许一个对象拥有另一个对象的属性和方法
  • 对象间的通信: 对象间通过信息传递进行通信。当一个对象需要另一个对象执行一些操作,会调用另一个对象的方法并等待回应(返回值)

链接:对象常用方法

JavaScript: prototype-based language

javascript中每一个对象都有__proto__属性(访问器属性),指向它的原型对象;

每个对象都从原型上继承一个constructor,指向它的构造函数;

每一个构造函数都有prototype属性,值为所有可被继承的属性和方法,即不在prototype属性上的方法是不能被继承的;

当查找对象的属性或方法时会顺着原型链向上查找,直至最顶层null;

javaScript本身没有类的概念,使用原型实现面向对象编程;javaScript中的类本质上是基于prototype的进一步封装

创建构造函数

  • 关键词:

    箭头函数不能作为构造函数:它没有prototype属性,无法在原型链上实现继承; 它继承this,没有自己的this,无法改变自身的this指向

    实例化:构造函数(模板)运行创建实例(对象);在类中,类(模板)的构造函数运行创建实例对象

    多态: 不同数据类型的实体提供统一的接口;重写是实现父类与子类间多态的方式,运行时多态:重写同一个方法;重载是一个类里的多态,编译时多态:一个类中同一个方法名接收的参数不同

// old: 手工构造函数
function ConstrutorFunc() {
    let obj = {};
    obj.name = 'lili',
    obj.greeting = function() {console.log('hello')}
    return obj;
}
​
let instance = constructorFunc(); // 使用方式// new: new封装构造函数
function ConstructorFunc() {
    this.name = 'lili';
    this.greeting = funtion() {console.log('hello '+ this.name )}
}
​
let instance = new ConstructorFunc(); // 使用方式;
/** new封装后结构更清晰
* 可见,new做了什么:
*   1. 创建一个{}
*   2. 为该对象添加__proto__属性,属性值为ConstructorFunc.prototype
*   3. 绑定this:将步骤1创建的对象作为this的上下文
*   4. 返回该函数的返回值;若无,返回this
*/// 结果如下,注意:1this在运行时绑定,所以此处不能直接把greeting里的this.name换成lili;
(2)每创建一遍实例,就会创建一次函数,这不理想(js是动态脚本,要的是轻量方便)。所以我们将方法定义在原型上(.prototype),一次定义便可使用,即可动态扩展;
instance = {
 name: 'lili',
 greeting: funtion() { console.log('hello ' + this.name) } 
}
​
// 补充: 创建对象的其他方式
let instance = new Object({name: 'lili'});
instance.genter = 'male';
// or
let instance = Object.create(instance1);

构造函数与实例在内存中的位置

image-20211207145254671.png

  • 由上图也可以看出构造函数创建对象和Object.create创建对象的区别:

    创建方式创建结果添加属性
    构造函数创建对象image-20211210103600484.pngimage-20211210104019768.png
    Object.create创建对象image-20211210103709450.pngimage-20211210104031137.png

ES6 类

继承与实例化

ES5 构造函数实例化ES6 类实例化
image-20211207122728611.pngimage-20211209184625833.png

ES6 类与ES5 构造函数相同使用

image-20211210143600929.png

ES6 类与ES5 构造函数区别

  • 类中默认使用严格模式(原因是let x = class className {};class y extends x {};中let不能提升,而这是class提升了就会报错),类中所有方法不可枚举,类必须new来创建;

  • 继承的实现

    • ES5 继承:先创建子类的实例对象this,再把父类方法绑定到this上
    • ES6 继承:先将父类实例对象的属性和方法放到this上(super中实现,但this运行时指向子类实例哦),再使用子类构造函数修改this;子类要想使用this,必须先super()创建父类实例

super

  • 作为函数使用,只能在构造函数中使用,代表父类构造函数
  • 作为对象使用,代表父类的原型对象(prototype);在静态方法中指向父类
  • super必须显示调用,明确是作为函数还是对象,否则会报错

静态属性与私有属性

  • 静态属性是类本身的属性,只能在类内部访问,可继承,关键字为static
  • 私有属性仅在类内部可使用的属性