首先,请记住,JavaScript主要是一种原型语言,而不是基于类的语言1。 不是一个类,它是一个函数,它是一个对象。您可以使用关键字从该函数实例化对象,这将允许您创建类似于标准OOP语言中的类的内容。Foo
new
我建议忽略大多数时候,因为它的跨浏览器支持很差,而是专注于学习工作原理。__proto__
prototype
如果您有一个从函数2 创建的对象的实例,并且您以任何方式访问其成员之一(方法、特性、属性、常量等),则访问将沿着原型层次结构向动,直到它 (a) 找到该成员,或者 (b) 找不到另一个原型。
层次结构从被调用的对象开始,然后搜索其原型对象。如果原型对象具有原型,则返回重复,如果不存在原型,则返回该重复。undefined
例如:
foo = {bar: 'baz'};
console.log(foo.bar); // logs "baz"
foo = {};
console.log(foo.bar); // logs undefined
function Foo(){}
Foo.prototype = {bar: 'baz'};
f = new Foo();
console.log(f.bar);
// logs "baz" because the object f doesn't have an attribute "bar"
// so it checks the prototype
f.bar = 'buzz';
console.log( f.bar ); // logs "buzz" because f has an attribute "bar" set
在我看来,你至少已经在某种程度上理解了这些“基本”部分,但我需要明确它们才能确定。
在 JavaScript 中,一切都是对象3。
一切都是一个对象。
function Foo(){}
它不仅定义了一个新函数,还定义了一个可以使用 访问的新函数对象。Foo
这就是为什么您可以使用 访问 的原型的原因。Foo
Foo.prototype
您还可以做的是在 上设置更多功能:Foo
Foo.talk = function () {
alert('hello world!');
};
可以使用以下命令访问此新功能:
Foo.talk();
我希望到现在为止,您已经注意到函数对象上的函数与静态方法之间的相似性。
可以考虑创建类实例,为类定义共享方法,并为类定义公共静态方法。f = new Foo();
Foo.prototype.bar = function(){...}
Foo.baz = function(){...}
ECMAScript 2015 为这些类型的声明引入了各种语法糖,以使它们更易于实现,同时也更易于阅读。因此,前面的示例可以写为:
class Foo {
bar() {...}
static baz() {...}
}
它允许被称为:bar
const f = new Foo()
f.bar()
并被称为:baz
Foo.baz()
1:class
在 ECMAScript 5 规范中是“未来保留字”,但 ES6 引入了使用 class
关键字定义类的功能。
2:本质上是一个由构造函数创建的类实例,但是有很多细微差别,我不想误导你
3:基元值(包括未定义
、null
、布尔值、数字和字符串)在技术上不是对象,因为它们是低级语言实现。布尔值、数字和字符串仍然与原型链交互,就好像它们是对象一样,因此,为了这个答案的目的,即使它们不完全是“对象”,也更容易将它们视为“对象”。