2022.11.23 第10章 自定义对象
面向对象OOP(Object Oriented Programming)
对象是一个包含相关数据和方法的集合(通常由一些变量和函数组成,我们称之为对象里面的属性和方法)对象是存储在单个分组中的相关功能的集合。在 JavaScript 中,大多数事物都是对象,从作为核心功能的字符串和数组,到建立在 JavaScript 之上的浏览器 API。
继承与原型链
对于使用过基于类的语言 (如 Java 或 C++) 的开发者们来说,JavaScript 实在是有些令人困惑 —— JavaScript 是动态的,本身不提供一个 class
的实现。即便是在 ES2015/ES6 中引入了 class
关键字,但那也只是语法糖,JavaScript 仍然是基于原型的。
当谈到继承时,JavaScript 只有一种结构:对象。每个实例对象(object)都有一个私有属性(称之为 proto)指向它的构造函数的原型对象(prototype)。该原型对象也有一个自己的原型对象(proto),层层向上直到一个对象的原型对象为 null
。根据定义,null
没有原型,并作为这个原型链中的最后一个环节。
几乎所有 JavaScript 中的对象都是位于原型链顶端的 Object 的实例。
尽管这种原型继承通常被认为是 JavaScript 的弱点之一,但是原型继承模型本身实际上比经典模型更强大。例如,在原型模型的基础上构建经典模型相当简单。
在 JavaScript 中,函数(function)是允许拥有属性的。所有的函数会有一个特别的属性 —— prototype
-
创建类特性(class property),使用prototype对象
-
存储一次,能被所有实例访问,不必定要初始化
Blog.prototype.signature = "by Puzzler Ruby";
-
在实例内访问类特性用关键字this,跟访问实例特性一样
Blog.prototype.toHTML = function(highlight) { ... blogHTML += this.signature + "</em></p>"; ... };
-
-
类拥有的实例方法(class-owned instance method),使用prototype对象
- 存储一次运行多次,方法只有一份,由所有实例共享
- 虽然属于类,但能够访问实例特性
-
类方法(class method),不使用prototype对象
-
为类所有,不能访问实例特性或方法,但可以被实例调用(透过类名即可)
Blog.blogSorter = function(blog1, blog2) { return blog2.date - blog1.date; };
-
只能访问类特性,需要下探至prototype特性内
function showBlog(num) { blog.sort(Blog.blogSorter); ... }
-
对象实例instance
在 JavaScript 中,构造器其实就是一个普通的函数。当使用 new 操作符 来作用这个函数时,它就可以被称为构造方法(构造函数)。
function Graph() {
this.vertices = [];
this.edges = [];
}
Graph.prototype = {
addVertex: function(v){
this.vertices.push(v);
}
};
var g = new Graph();
// g 是生成的对象,他的自身属性有 'vertices' 和 'edges'。
// 在 g 被实例化时,g.[[Prototype]] 指向了 Graph.prototype。
其他知识点
-
<table>元素表示表格数据——即通过二维数据表表示的信息
内容分类 流动内容 允许的内容 按照这个顺序: • 一个可选的 <caption> 元素 表格的标题 • 零个或多个的 <colgroup> 元素 定义表中的一组列表 • 一个可选的 <thead> 元素 通过二维数据表表示的信息 • 下列任意一个: ◦ 零个或多个 <tbody> 封装了一系列表格的(<tr>) ◦ 零个或多个 <tr> 定义表格中的行
• 一个可选的 <tfoot> 元素 定义了一组表格中各列的汇总行 | | 标签省略 | 不允许,开始标签和结束标签都不能省略。 | | 允许的父元素 | 任何支持流内容 (en-US)的元素 | | 允许的 ARIA 角色 | Any | | DOM 接口 | HTMLTableElement |
<table> <caption>Color names and values</caption> <tbody> <tr> <th scope="col">Name</th> <th scope="col">HEX</th> <th scope="col">HSLa</th> <th scope="col">RGBa</th> </tr> <tr> <th scope="row">Teal</th> <td><code>#51F6F6</code></td> <td><code>hsla(180, 90%, 64%, 1)</code></td> <td><code>rgba(81, 246, 246, 1)</code></td> </tr> <tr> <th scope="row">Goldenrod</th> <td><code>#F6BC57</code></td> <td><code>hsla(38, 90%, 65%, 1)</code></td> <td><code>rgba(246, 188, 87, 1)</code></td> </tr> </tbody> </table>
-
<td>定义了一个包含数据的表格单元格。It participates in the table model.
-
vertical-align 指定行内元素(inline)或表格单元格(table-cell)元素的垂直对齐方式。
/* Keyword values */ vertical-align: baseline; vertical-align: sub; vertical-align: super; vertical-align: text-top; vertical-align: text-bottom; vertical-align: middle; vertical-align: top; vertical-align: bottom; /* <length> values */ vertical-align: 10em; vertical-align: 4px; /* <percentage> values */ vertical-align: 20%; /* Global values */ vertical-align: inherit; vertical-align: initial; vertical-align: unset;
-
<style >元素包含文档的样式信息或者文档的部分内容。默认情况下,该标签的样式信息通常是CSS的格式。
-
**JavaScript 控制台**是一个非常有用的工具,用于调试没有按预期运行的 JavaScript。它允许您针对浏览器当前加载的页面运行 JavaScript 行,并报告浏览器尝试执行代码时遇到的错误。要在任何浏览器中访问控制台,只需按控制台按钮。 (在 Internet Explorer 中,按 Ctrl + 2.)这将给你一个如下所示的窗口
案例:使用自定义对象实现blog目录
<html>
<head>
<title>YouCube - The Blog for Cube Puzzlers</title>
<script>
function Blog(body, date, image){
this.body = body;
this.date = date;
this.image = image;
}
Blog.prototype.toString = function(){
return "[" + this.date.shortFormat() + "]" + this.body;
};
Blog.prototype.toHTML = function(highlight){
var blogHTML = "";
blogHTML += highlight ? "<p style='background-color:#eeeeee'>" : "<p>";
if (this.image){
blogHTML += "<strong>" + this.date.shortFormat() + "</strong><br /><table><tr><td>" + "<img src='" + this.image +"'/> </td><td style='vertical-align:top'>" + "</br>" + this.body + "</td></tr></table><br /><em>" + this.signature + "</em></p>" ;
}
else
blogHTML += "<strong>" + this.date.shortFormat() + "</strong>" + "</br>" + this.body + "<br /><em>" + this.signature + "</em></p>" ;
return blogHTML;
};
Blog.prototype.containsText = function(text){
return(this.body.toLowerCase().indexOf(text.toLowerCase()) != -1);
};
Blog.prototype.signature = "pizzler ruby";
Date.prototype.shortFormat = function(){
return this.getFullYear() + "/" + (this.getMonth() + 1) + "/" + this.getDate();
};
Blog.blogSorter = function(blog1, blog2){
return blog2.date-blog1.date;
};
var blog = [new Blog("Got the new cube I ordered. It's a real pearl.", new Date("08/14/2008")),
new Blog("second line.", new Date("08/19/2008")),
new Blog("third line.", new Date("08/16/2008")),
new Blog("the fourth line.", new Date("08/21/2008"), "cube77.png"),
new Blog("Got the new cube I ordered. It's a real pearl.", new Date("08/14/2008")),
new Blog("second line.", new Date("08/19/2008")),
new Blog("third line.", new Date("08/16/2008")),
new Blog("the fourth line.", new Date("08/21/2008"))];
function showBlog(numEn){
//如果没有传入显示个数,则显示所有日志
if (!numEn)
numEn = blog.length;
//显示日志
var blogText = "";
for (var i=0; i<numEn; i++){
blogText += blog[i].toHTML(0 == i%2);
}
document.getElementById("blog").innerHTML = blogText;
}
//倒序排列
blog.sort(Blog.blogSorter);
function searchBlog(){
var searchText = document.getElementById("searchtext").value;
for (var i = 0; i<blog.length; i++){
if (blog[i].containsText(searchText)){
alert(blog[i]);
break;
}
}
if (blog.length == i)
alert("sorry,there are no blog entries containing the search text.");
}
function randomBlog(){
var i = Math.floor(Math.random() * blog.length);
alert(blog[i]);
}
</script>
</head>
<body onload = "showBlog(5);">
<h3>YouCube - The Blog for Cube Puzzlers</h3>
<img src="cube.png" alt="YouCube" />
<input type="button" id="search" value="search the blog" onclick="searchBlog();" />
<input type="text" id="searchtext" value="" />
<div id="blog"></div>
<input type="button" id="showall" value="show all blog" onclick="showBlog();" />
<input type="button" id="random" value="random the blog" onclick="randomBlog();" />
</body>
</html>