JS中的类与对象

面向对象是使用最广泛的一种编程范式,最具代表性的面向对象语言就是Java和C++,在它们的理念中,面向对象的三大特性:封装,继承,多态。类,对象,公有/私有方法/属性,各种继承就是在语法层面实现这些理念的工具。这种面向对象的理念取得了巨大的成功,以至于我们说到面向对象时,认为这是面向对象的标准。

其实以JS为代表的面向对象理念跟它们完全不同,JS才可以说是真正的面向对象语言,因为在JS中一切皆为对象。在Java/C++语言中,面向对象的最基础的两个概念是对象通过类来抽象事物,通过对象来模拟具体事物。

类是静态的,类定义后,就是变成了一个"印刷模板",属性和方法都不能再变动,通过"印刷模板" 产生的对象,属性和方法也不能变动。要添加新的属性和方法,得产生新的"模板"。

在JS中没有类的概念,只有一个行为类似于"类"的对象,就是构造器函数。因为通过new表达式它也可以创建对象。但它本质上不是类,它也无法表达类的含义。

JS中的对象的属性和方法可以任意添加,删除,完全是动态化。构造器函数也是如此,因为它也是一个对象。那么从这个特性上理解就与类的概念相隔十万八千里了。

所以不要把Java/C++这类面向对象的概念往JS上套,这样很容易绕晕。要明白JS的核心一切皆对象。

通过构造器函数创建对象

构造器函数

它是JS中的"类",可以批量产生对象的函数,如下代码:

javascript 复制代码
function Foo(){
  ...
}

var a = new Foo();

函数Foo的行为与类很类似,通过new表达式产生一个对象a。如果通过这种表面的方式去理解,可以认为它是"类"。

但是Foo函数它也是对象,只是通过new表达式,产生一个新的对象a,所以特殊的是new表达式,它在背后做了些事情,让函数Foo像类

new表达式

函数Foo通过new表达式来调用,会执行下面的操作:

  • 创建一个全新的对象。
  • 这个新对象会被执行Prototype链接,与构造器函数的原型相连。
  • 这个新对象会绑定到函数调用的this。
  • 如果函数没有返回其他对象,那么new表达式中的函数调用会自动返回这个新对象。

函数本身就是对象,通过new表达式调用后,函数调用变成"构造函数调用"。这个函数也变成了构造器函数。


new表达式产生的新的对象其实是与Foo对象产生了关联,并且是通过原型对象产生关联**,新对象的原型属性指向了Foo的原型对象。

所以所谓的"类"创建"对象",其实只是改变各自的原型属性的指向,产生一个链接,从而建立关系。

(这里要注意了构造器函数产生的对象,通过 proto (\[Prototype])属性访问原型对象。
构造器函数对象通过Prototype属性访问原型)

构造器函数创建对象,如下代码:

javascript 复制代码
function Foo(){
}

var a = new Foo();
//输出true
console.log(Object.getPrototypeOf(a) === Foo.prototype);
//输出true
console.log(a.__proto__ == Foo.prototype);

相互之间的链接

javascript 复制代码
function Foo(name,age){
  this.name = name;
  this.age = age;
};

var a = new Foo("hhh",32);
//a与Foo的原型相同
console.log(Object.getPrototypeOf(a) === Foo.prototype);//输出为true
//a是否是Foo的实例
console.log(a instanceof Foo);//输出为true
//a的构造函数
console.log(a.constructor);//输出为[Function: Foo]

**通过console.log(Object.getPrototypeOf(a) === Foo.prototype)可以知道a的原型对象与Foo的原型对象相同,这就是它们之间的联系。**后面两条语句,从表面上看就是对象与类的关系即a 是Foo的实例,a的构造函数为Foo。

instanceofconstructor

instanceof操作符是判断一个对象是否另一个对象的实例,constructor属性指向对象的构造器,它们是检查对象间是否有建立关系。

instanceof操作符判断a的整条原型链中是否有指向Foo.prototype的对象,而constructor也并非是永远指向Foo。如果把这两个属性的指向一换,那建立的"类"和"对象"的关系就没了。在Jave/C++这种行为是完全被禁止。如下代码:

javascript 复制代码
function Foo(name,age){
  this.name = name;
  this.age = age;
};

var a = new Foo("hhh",32);
//将a的原型设置为空对象(构造器函数产生的对象a要用__proto__访问原型)
a.__proto__ = {};
console.log(Object.getPrototypeOf(a) === Foo.prototype);//输出为false
//a是否是Foo的实例
console.log(a instanceof Foo);//输出为false
//a的构造函数
console.log(a.constructor);//输出为[Function: object]

加入语句a.__proto__={}即将a的原型对象设置为空,切断了a与Foo的关联。

那么结果就不同了 instanceof返回false, a.constructor指向object,而object并非a的构造函数。

javascript 复制代码
function person(name,age) {
    this.name = 'mmm';
    this.age = 18;
    this.msg = "123456";
}

let p = new person('cc',19);
console.log("对象p的构造对象:"+p.__proto__.constructor);


console.log("person是否是p的原型:"+person.isPrototypeOf(p));
console.log("person的原型是否p的原型:"+person.prototype.isPrototypeOf(p));
相关推荐
sibylyue1 分钟前
# Web端流媒体JS播放器开源库
前端·javascript·开源
薛定猫AI7 分钟前
【深度解析】DeepSeek Harness:可插拔智能体运行时如何连接大模型与真实计算机
java·运维·网络
rannn_11113 分钟前
【力扣hot100】回溯专题|全排列、子集、字母组合、组合总和、括号生成、单词搜索、分割回文串、N皇后
java·算法·leetcode·回溯
落魄大学生之流水线上谋生计15 分钟前
Python Literal[] 类型提示详解
开发语言·python
铁皮饭盒16 分钟前
网页端, 5.5mb谷歌模型, 识别躯干, 视频都不卡
前端·javascript·后端
WongKyunban20 分钟前
Go语言的简洁并发编程
开发语言·后端·golang
重生之后端学习28 分钟前
438. 找到字符串中所有字母异位词[中等]✅
开发语言·数据结构·算法·leetcode·职场和发展
晴天1632 分钟前
Gradio 与 Streamlit:Python 快速构建 Web 应用的双子星-Day28
开发语言·前端·python
nxb55633 分钟前
云原生:控制器
java·开发语言·云原生
码哥DFS37 分钟前
LRU缓存
前端·javascript·缓存