JavaScript中类与函数行为差异探究:为何二者表现不同?
嘿,这个问题问到点子上了!很多刚摸透JS原型链的同学都会有这个疑惑——毕竟咱们都知道ES6的class本质是基于原型的构造函数的语法糖,但你给的例子里,明明写法不一样,输出却相同,背后的细节差异才是关键。咱们一步步拆解:
先看你代码里的核心差异
你写的AnimalFunc把sayName直接定义在了构造函数内部,而AnimalClass的sayName是类的原型方法——这是二者表现“看似一致但本质不同”的核心原因:
1. 方法的挂载位置完全不同
- 对于
AnimalFunc:每new一个实例,都会在实例对象上创建一个全新的sayName函数。比如你再创建一个cat2 = new AnimalFunc("cat2"),cat.sayName === cat2.sayName的结果是false——俩实例的方法是完全独立的对象,会浪费内存。 - 对于
AnimalClass:sayName是挂载在AnimalClass.prototype上的,所有实例共享同一个函数。dog.sayName === new AnimalClass("dog2").sayName的结果是true,这才是更高效的写法。
如果想让函数式构造器实现和类一样的共享方法,你得把方法挂到原型上,写法改成这样:
function AnimalFunc(name) { this.name = name; } // 把方法挂载到原型上 AnimalFunc.prototype.sayName = function() { console.log(this.name); }
这时候再对比两个实例的sayName,就和类的行为完全一致了。
2. 类自带严格模式保护
类内部的所有代码(构造函数、方法)默认运行在严格模式下,而普通构造函数如果没手动加'use strict',就会在非严格模式下执行:
- 比如你在
AnimalFunc里不小心写了name = name(忘了加this),非严格模式下会偷偷创建全局变量;但在类里这么写,会直接抛出错误,帮你提前踩坑。
3. 类不能被当作普通函数调用
普通构造函数如果忘了加new,直接AnimalFunc("cat")调用,会把this绑定到全局对象(浏览器里是window),甚至污染全局变量;但类如果不加new直接调用,JS引擎会直接报错:Class constructor AnimalClass cannot be invoked without 'new'——这是类的语法约束,避免你犯低级错误。
4. 类的原型方法默认不可枚举
用Object.keys()遍历实例属性时:
Object.keys(cat)会把sayName也列出来(因为它是实例自身的属性);Object.keys(dog)只会列出name,因为类定义的原型方法默认是不可枚举的,更符合面向对象的封装逻辑。
总结
你觉得的“行为差异”其实是因为构造函数的写法不规范——你把方法写在了构造函数内部,而类默认采用了更高效的原型挂载方式。如果调整构造函数的写法,让方法挂载到原型上,二者的核心行为就会一致。本质上类就是构造函数的语法糖,但它加了很多语法约束和默认行为,让代码更规范、更不容易出错。
内容的提问来源于stack exchange,提问作者happy_sisyphus

