重新介绍 JavaScript(JS 教程)

您所在的位置:网站首页 对js语言的语法来说有特定意义吗 重新介绍 JavaScript(JS 教程)

重新介绍 JavaScript(JS 教程)

2023-09-19 00:24| 来源: 网络整理| 查看: 265

备注: 关于 JavaScript 中面向对象编程更详细的信息,请参考 JavaScript 面向对象简介 (en-US)。

在经典的面向对象语言中,对象是指数据和在这些数据上进行的操作的集合。与 C++ 和 Java 不同,JavaScript 是一种基于原型的编程语言,并没有 class 语句,而是把函数用作类。那么让我们来定义一个人名对象,这个对象包括人的姓和名两个域(field)。名字的表示有两种方法:“名 姓(First Last)”或“姓,名(Last, First)”。使用我们前面讨论过的函数和对象概念,可以像这样完成定义:

js

function makePerson(first, last) { return { first: first, last: last, }; } function personFullName(person) { return person.first + " " + person.last; } function personFullNameReversed(person) { return person.last + ", " + person.first; } var s = makePerson("Simon", "Willison"); personFullName(s); // "Simon Willison" personFullNameReversed(s); // "Willison, Simon"

上面的写法虽然可以满足要求,但是看起来很麻烦,因为需要在全局命名空间中写很多函数。既然函数本身就是对象,如果需要使一个函数隶属于一个对象,那么不难得到:

js

function makePerson(first, last) { return { first: first, last: last, fullName: function () { return this.first + " " + this.last; }, fullNameReversed: function () { return this.last + ", " + this.first; }, }; } s = makePerson("Simon", "Willison"); s.fullName(); // "Simon Willison" s.fullNameReversed(); // Willison, Simon

上面的代码里有一些我们之前没有见过的东西:关键字 this。当使用在函数中时,this 指代当前的对象,也就是调用了函数的对象。如果在一个对象上使用点或者方括号来访问属性或方法,这个对象就成了 this。如果并没有使用“点”运算符调用某个对象,那么 this 将指向全局对象(global object)。这是一个经常出错的地方。例如:

js

s = makePerson("Simon", "Willison"); var fullName = s.fullName; fullName(); // undefined undefined

当我们调用 fullName() 时,this 实际上是指向全局对象的,并没有名为 first 或 last 的全局变量,所以它们两个的返回值都会是 undefined。

下面使用关键字 this 改进已有的 makePerson函数:

js

function Person(first, last) { this.first = first; this.last = last; this.fullName = function () { return this.first + " " + this.last; }; this.fullNameReversed = function () { return this.last + ", " + this.first; }; } var s = new Person("Simon", "Willison");

我们引入了另外一个关键字:new,它和 this 密切相关。它的作用是创建一个崭新的空对象,然后使用指向那个对象的 this 调用特定的函数。注意,含有 this 的特定函数不会返回任何值,只会修改 this 对象本身。new 关键字将生成的 this 对象返回给调用方,而被 new 调用的函数称为构造函数。习惯的做法是将这些函数的首字母大写,这样用 new 调用他们的时候就容易识别了。

不过,这个改进的函数还是和上一个例子一样,在单独调用fullName() 时,会产生相同的问题。

我们的 Person 对象现在已经相当完善了,但还有一些不太好的地方。每次我们创建一个 Person 对象的时候,我们都在其中创建了两个新的函数对象——如果这个代码可以共享不是更好吗?

js

function personFullName() { return this.first + " " + this.last; } function personFullNameReversed() { return this.last + ", " + this.first; } function Person(first, last) { this.first = first; this.last = last; this.fullName = personFullName; this.fullNameReversed = personFullNameReversed; }

这种写法的好处是,我们只需要创建一次方法函数,在构造函数中引用它们。那是否还有更好的方法呢?答案是肯定的。

js

function Person(first, last) { this.first = first; this.last = last; } Person.prototype.fullName = function () { return this.first + " " + this.last; }; Person.prototype.fullNameReversed = function () { return this.last + ", " + this.first; };

Person.prototype 是一个可以被 Person 的所有实例共享的对象。它是一个名叫原型链(prototype chain)的查询链的一部分:当你试图访问 Person 某个实例(例如上个例子中的 s)一个没有定义的属性时,解释器会首先检查这个 Person.prototype 来判断是否存在这样一个属性。所以,任何分配给 Person.prototype 的东西对通过 this 对象构造的实例都是可用的。

这个特性功能十分强大,JavaScript 允许你在程序中的任何时候修改原型(prototype)中的一些东西,也就是说你可以在运行时 (runtime) 给已存在的对象添加额外的方法:

js

s = new Person("Simon", "Willison"); s.firstNameCaps(); // TypeError on line 1: s.firstNameCaps is not a function Person.prototype.firstNameCaps = function () { return this.first.toUpperCase(); }; s.firstNameCaps(); // SIMON

有趣的是,你还可以给 JavaScript 的内置函数原型(prototype)添加东西。让我们给 String 添加一个方法用来返回逆序的字符串:

js

var s = "Simon"; s.reversed(); // TypeError on line 1: s.reversed is not a function String.prototype.reversed = function () { var r = ""; for (var i = this.length - 1; i >= 0; i--) { r += this[i]; } return r; }; s.reversed(); // nomiS

定义新方法也可以在字符串字面量上用(string literal)。

js

"This can now be reversed".reversed(); // desrever eb won nac sihT

正如我前面提到的,原型组成链的一部分。那条链的根节点是 Object.prototype,它包括 toString() 方法——将对象转换成字符串时调用的方法。这对于调试我们的 Person 对象很有用:

js

var s = new Person("Simon", "Willison"); s; // [object Object] Person.prototype.toString = function () { return ""; }; s.toString(); //

你是否还记得之前我们说的 avg.apply() 中的第一个参数 null?现在我们可以回头看看这个东西了。apply() 的第一个参数应该是一个被当作 this 来看待的对象。下面是一个 new 方法的简单实现:

js

function trivialNew(constructor, ...args) { var o = {}; // 创建一个对象 constructor.apply(o, args); return o; }

这并不是 new 的完整实现,因为它没有创建原型(prototype)链。想举例说明 new 的实现有些困难,因为你不会经常用到这个,但是适当了解一下还是很有用的。在这一小段代码里,...args(包括省略号)叫作剩余参数(rest arguments)。如名所示,这个东西包含了剩下的参数。

因此,调用

js

var bill = trivialNew(Person, "William", "Orange");

可认为和调用如下语句是等效的

js

var bill = new Person("William", "Orange");

apply() 有一个姐妹函数,名叫 call,它也可以允许你设置 this,但它带有一个扩展的参数列表而不是一个数组。

js

function lastNameCaps() { return this.last.toUpperCase(); } var s = new Person("Simon", "Willison"); lastNameCaps.call(s); // 和以下方式等价 s.lastNameCaps = lastNameCaps; s.lastNameCaps();


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3