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));
相关推荐
超梦dasgg1 分钟前
Java 生产环境 MQ 技术选型全解析
java·开发语言·java-rocketmq·java-rabbitmq
霸道流氓气质2 分钟前
Spring AI 多工具链式调用(Tool Chain)极简实战
java·人工智能·spring
罗超驿37 分钟前
22.深入剖析JDBC架构:从原生API到企业级数据交互核心
java·数据库·mysql·面试
桀人38 分钟前
C++——模板初阶(收录在专栏C++入门到精通)
开发语言·c++
一直有一个ac的梦想1 小时前
cmu15445 2025fall lec 18 transactions with two-phase lock
java·开发语言·数据库
九皇叔叔1 小时前
Spring-Ai-Alibaba [04] 04-llm-platform-custom-demo
java·人工智能·spring
技术路上的探险家1 小时前
Sa-Token 单点登录(SSO)三种模式大白话详解:告别重复登录
java·sa-token·单点登录·sso
JAVA社区1 小时前
Java进阶全套教程(四)—— SpringMVC框架详解
java·开发语言·spring·面试·职场和发展
ㄣ知冷煖★1 小时前
统一网关架构实践:从 Token 鉴权到路由、策略与凭证池转发全链路解析
java·服务器·架构
Lumbrologist1 小时前
【C++】零基础入门 · 第 2 节:变量、基本数据类型与输入输出
java·开发语言·c++