JavaScript面向对象编程

目录

面向对象编程OOP(Object Oriented Programming)

定义:

自定义类

创建自定义类

new函数执行的过程(加粗文字是与普通函数执行不同的地方)

原型、原型链的底层运行机制


面向对象编程OOP(Object Oriented Programming)

定义:

  • 对象: 万物皆对象
  • 类: 对对象的细分
  • 实例: 类中的具体事物

在JavaScript中, 对实例、类和对象的划分如下:

实例对象
1Number

Object

"1"String

Object

[1,2,3]Array

Object

ture、falseBoolean

Object

nullNullObject
UndefinedUndefinedObject
function()FunctionObject
DateDateObject
{name:"1"}ObjectObject
/^$/RegExpObject

上面这些类都是JavaScript自身所拥有的, 那么应该如何创建一个自定义类呢?创建自定义类的过程中都发生了什么?

自定义类

创建自定义类

function func() {
    this.num = 100;
}

func(); //此情况为普通函数执行, this指向window
new func(); //此情况new执行, 就是一个自定义类

new函数执行的过程(加粗文字是与普通函数执行不同的地方)

  • 形成一个全新的执行上下文(EC) [每一次new都会形成一个新的实例对象]
  • 形成AO变量对象
  • 初始化作用域链
  • 默认创建一个对象, 这个对象就是当前类的实例
  • 声明this指向新创建的实例
  • 代码执行
  • 不论是否有return, 都会将新创建的实例返回
  1. 如果有return, 且返回值是一个引用类型值, 就会返回return的值, 如果不是引用类型值, 就会返回创建的实例
  2. 如果没有return, 就会返回创建的实例
// 1.无return
function func() {
  this.num = 100;
}

let f = new func();
console.log(f); //func {num: 100}

// 2.有return, 且返回值为引用类型值
function func1() {
  let obj = {};
  obj.num = 10;
  this.num = 100;
  return obj;
}

let f1 = new func1();
console.log(f1); // {num:10}

// 3.有return, 但是返回值不是引用类型值
function func2() {
  this.num = 100;
  return 1;
}

let f2 = new func2();
console.log(f2); //func2 {num: 100}

其实在上面的例子中, 返回的实例里面并不是只有num一个键值对, 我们在浏览器中的输出展开实例会发现, 其中还有一个__proto__

下面说一下prototype和__proto__

原型、原型链的底层运行机制

原型和原型链就是对应上面所说的prototype和__proto__, 在此之前我们先了解一下作用链

  • 每一个类都具备prototype, 并且属性值是一个对象
  • 对象上天生具备一个属性: constructor, 指向类本身
  • 每一个对象(普通对象、prototype、实例...)都具备__proto__, 属性值是当前实例所属类的原型
  • __proto__的机制: 先找私有属性, 如果没有则开始找基于 __proto__所属实例prototype上的公有属性, 如果还是没有, 则继续向上查找, 一直到找到 Object.prototype

接下来, 看一道面试题, 我们还是用绘图的方式进行理解:

function Fn() {
  this.x = 100;
  this.y = 200;
  this.getX = function () {
    console.log(this.x);
  }
}
Fn.prototype.getX = function () {
  console.log(this.x);
};
Fn.prototype.getY = function () {
  console.log(this.y);
};
let f1 = new Fn;
let f2 = new Fn;
console.log(f1.getX === f2.getX);
console.log(f1.getY === f2.getY);
console.log(f1._proto_.getY === Fn.prototype.getY);
console.log(f1._proto_.getX === f2.getX);
console.log(Fn.prototype.getX === f1.getX);
console.log(f1.constructor);
console.log(Fn.prototype._proto_.constructor);
f1.getX();
f1._proto_.getX();
f2.getY();
f2.prototype.getY();

上面的图中, 展示了这道题中的几个关系, 其中第六条说, 每一个__proto__都会指向当前实例所属类的原型, 那么Fn和Fn.prototype的__proto__指向了哪里?我们知道, 函数所属的类是Object, 那它们两个就是指向了Object, 下面是示意图: 

依据上面两张图, 我们就可以知道上面的答案了

console.log(f1.getX === f2.getX); // false (每new一次, 都创建一个新的实例对象)
console.log(f1.getY === f2.getY); // true (两个实例都是根据Fn创建的, 他们共享相同的getY函数)
console.log(f1._proto_.getY === Fn.prototype.getY); // true (f1.__proto__ 指向了 Fn.prototype,所以他们指向的getY函数是同一个)
console.log(f1._proto_.getX === f2.getX); // ture (f2 的 getX 方法是通过 Fn.prototype 继承而来的,所以它们是同一个函数。)
console.log(Fn.prototype.getX === f1.getX); // false (f1.getX 是在构造函数内部定义的,它不是通过 Fn.prototype 继承而来的)
console.log(f1.constructor); // [Function: Fn]
console.log(Fn.prototype._proto_.constructor); // [Function: Object]
f1.getX(); // 100
f1._proto_.getX(); // undefined (f1.__proto__ 中并没有定义 x 属性)
f2.getY();  // 200 
f2.prototype.getY(); // undefined (f2 的实例对象没有 prototype 属性)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值