学习笔记:MDN的JavaScript

JavaScript 第一步

什么是JavaScript

每次当你浏览网页时不只是显示静态信息—— 显示即时更新的内容, 或者交互式的地图,或 2D/3D 图形动画,又或者自动播放视频等,你可以确信,JavaScript 参与其中。

HTML是一种标记语言,用来结构化我们的网页内容和赋予内容含义,例如定义段落、标题、和数据表,或在页面中嵌入图片和视频。

CSS 是一种样式规则语言,我们将样式应用于我们的 HTML 内容, 例如设置背景颜色和字体,在多个列中布局我们的内容。

JavaScript 是一种编程语言,允许你创建动态更新的内容,控制多媒体,图像动画,和一些其他的东西。好吧,虽然不是一切,但是它的神奇之处是你能够用几行JavaScript代码就能实现。

JavaScript 语言的核心包含一些普遍的编程特点,以让你可以做到如下的事情:

  • 在变量中储存有用的值。比如,我们用prompt请求输入一个新的名字,然后把那个名字储存到一个叫 name 的变量.
  • 对一段文本(在编程中被称为“字符串”)进行操作。在上面的例子中,我们取出字符串 "Player 1: ",然后把它和 name 变量连结起来,创造出完整的文本标签,例:''Player 1: Chris"。
  • 运行代码以响应在网页中发生的特定事件。在上述的例子中,我们用了一个 click 事件来检测按钮什么时候被点击,然后运行更新文本标签的代码。
  • 以及更多!

然而更令人兴奋的是建立在 JavaScript 语言的核心之上的功能。在你的 JavaScript 代码里,被称为应用程序编程接口 [Application Programming Interfaces (APIs)] 的功能会提供额外的超能力给你使用。

APIs 是已经建立好的一套代码组件,目的是让开发者可以实现除了用APIs之外很难甚至不可能实现的程序。它们的作用就像是已经制作好的家具套件对家居建设的作用一样——从一堆已经切好的木板开始组装一个书柜,显然比自己设计,寻找合适的木材,裁切至合适的大小和形状,找到合适大小的螺丝钉,然后组装成一个书柜要简单得多。

APIs通常分成两个分类:

浏览器 APIs (Browser APIs) 已经安装在你的浏览器中,而且能够从周围的计算机环境中揭露数据,或者做有用的复杂事情。举个例子:

  • 文档对象模型 API [DOM (Document Object Model) API] 允许你操作 HTML 和 CSS,创建,移除和修改 HTML,动态地应用新的样式到你的页面,等等。比如说每次你在一个页面里看到一个弹出窗口,或者显示一些新的内容,这就是 DOM 在运作。
  • 地理定位 API [Geolocation API] 获取地理信息。这就是为什么谷歌地图可以找到你的位置,而且标示在地图上。
  • 画布 [Canvas] 和 WebGL APIs 允许你创建生动的 2D 和 3D 图像。人们正运用这些网页技术进行一些令人惊叹的事情——比如说 Chrome Experiments 和 webglsamples
  • 音像和影像 APIs [Audio and Video APIs],像 HTMLMediaElement 和 WebRTC 允许你运用多媒体去做一些非常有趣的事情,比如在网页中播放音像和影像,或者从你的网页摄像头中获取获取录像,然后在其他人的电脑上展示。

第三方 APIs (Third party APIs)(这些 APIs 是高级的) 默认是没有安装到浏览器中的,而你通常需要从网络上的某些地方取得它们的代码和信息。举个例子:

  • 推特 API [Twitter API] 允许你做一些像是在你的网站上展示你的最新推送之类的事情。
  • 谷歌地图 API [Google Maps API] 允许你去嵌入定制的地图到你的网站,和其他的功能。

在 HTML 和 CSS 已经被集合和组装成一个网页后,浏览器的 JavaScript 引擎执行 JavaScript。这保证了当 JavaScript 开始运行时,网页的结构和样式已经在该出现的地方了。这是一个好事情,正如 JavaScript 的普遍用处是通过 DOM API(如之前提及的那样)动态地修改 HTML 和 CSS 来更新用户交界面。如果 JavaScript 在 HTML 和 CSS 加载完成之前加载运行,那么会发生错误。

每个浏览器标签本身就是一个用来运行代码的分离的容器(这些容器用专业术语称为“运行环境”)——这意味着在大多数情况中,每个标签中的代码是完全分离地运行,而且在一个标签中的代码不能直接影响在另一个标签中的代码——或者在另一个网站中的。这是一个好的安全措施——如果不是这样的话,那么海盗们就可以开始写从其他网站偷取信息的代码,和其他像这样的坏事。注意:有安全的方式去在不同网站/标签中传送代码和数据,但这些方法是高级的技术。

当浏览器遇到一块 JavaScript 代码时,它通常会按顺序运行这代码块,从上往下。这意味着你需要注意你放置代码的顺序。

在编程环境中,你或许听说过这两个术语 解释 [interpreted] 和 编译 [compiled]。JavaScript 是一个解释语言——代码从上到下运行,而运行的结果会马上被返回。在浏览器运行代码前,你不必先把它转化为其他形式。另一方面来说,编译语言则需要在运行前转化为另一种形式。比如说 C/C++ 则要先被编译成汇编语言,然后再由电脑运行。

客户端[client-side]代码是在用户的电脑上运行的代码——当浏览一个网页时,这个网页的客户端代码就会被下载,然后由浏览器来运行和展示。在另一方面,服务器端[server-side]代码则在服务器上运行,然后它的结果会由浏览器进行下载和展示。JavaScript也是流行的服务器端网页语言!JavaScript 同时也能用作服务器端语言,比如说在流行的 Node.js 环境中。

JavaScript 是区分大小写的,而且非常的讲究。

把 JavaScript 放置在一个外部文件中,对于规划你的代码来说,这通常是一件好事,让它可以在多个 HTML 文件中重复使用,再加上 HTML 中没有一大堆脚本的话,HTML 会更容易阅读。请不要内联JavaScriptHTML这是一个用 JavaScript 来污染你的 HTML 的坏实践,而且它还不高效——你会需要在每个想要 JavaScript 应用到的按钮上包含 onclick="createParagraph()" 属性使用一个纯 JavaScript 结构允许你使用一个指令来应用于所有的按钮,无论页面上有多少个,和有多少个按钮被添加或者移除。不需要对 JavaScript 进行任何修改。

JavaScript的注释方式和C++一样,有两种(CSS只有C++的其中一种,HTML也是一种,但和C++的不一样)。

进入JavaScript的第一课

像程序员一样思考。

您可以使用关键字var以及变量的名称创建一个变量。

函数Window.alert:即警告。弹出警告窗口。

===:Strict equality (is it exactly the same?)

!==:Non-equality (is it not the same?)

您可能会看到有些人在他们的代码中使用==和!=来平等和不相等,这些都是JavaScript中的有效运算符,但它们与===/!==不同,前者测试值是否相同, 但是数据类型可能不同,而后者的严格版本测试值和数据类型是否相同。 严格的版本往往导致更少的错误,所以我们建议您使用这些严格的版本。

小于等于和大于等于都只有一个等号,而不是两个。

事件(Events)是浏览器中发生的动作,例如点击按钮,加载页面或播放视频,我们可以调用代码来响应。侦听事件发生的构造方法称为事件监听器,响应事件触发而运行的代码块被称为事件处理器

注意,当函数作为事件监听方法的参数时,函数名后不应带括号。

In JavaScript, everything is an object. An object is a collection of related functionality stored in a single grouping. You can create your own objects, but that is quite advanced. The built-in objects that your browser contains allow you to do lots of useful things.

For example, we first created a guessField variable that stores a reference to the text input form field in our HTML(To get this reference, we used the querySelector() method of the document object).

Because guessField now contains a reference to an <input> element, it will now have access to a number of properties (basically variables stored inside objects, some of which can't have their values changed) and methods (basically functions stored inside objects).

页面上的每个元素都有一个style属性,它本身包含一个对象,其属性包含应用于该元素的所有内联CSS样式。 这允许我们使用JavaScript在元素上动态设置新的CSS样式。

什么地方出了错?

浏览器的控制台可以检查JavaScript是否有语法错误并提示错误信息。有的错误要和网页交互后控制台才能提示,比如错误在函数内部发生,相对于函数外部的代码,函数内部的代码运行在一个独立的范围中,在这种情况下,页面加载时函数内部的代码不会被运行也不会抛出异常。

console.log() is a really useful debugging function that prints a value to the console. log是日志的意思。

如何存储你需要的信息变量

变量是用来存储数值的,那么有一个重要的概念需要区分。变量不是数值本身,它们仅仅是一个用于存储数值的容器。你可以把变量想象成一个个用来装东西的纸箱子。

在JavaScript中,所有代码指令都会以分号结尾 (;) — 如果忘记加分号,虽然浏览器的JS引擎会帮你加上,但不一定可靠,所以最好是养成主动以分号作为代码结尾的习惯。

变量名不要以下划线开头—— 以下划线开头的被某些JavaScript设计为特殊的含义,因此可能让人迷惑。

一个可靠的命名约定叫做 "小写驼峰命名法",用来将多个单词组在一起,小写整个命名的第一个字母然后大写剩下单词的首字符。

与其他编程语言不同,在 JavaScript 中你不需要声明一个变量的类型,因为JavaScript是一种“松散类型语言”。

字符串是文本的一部分。当你给一个变量赋值为字符串时,你需要用单引号或者双引号把值给包起来,两者之间几乎没有什么区别,根据个人偏好来使用。但是,您应该选择一个并坚持使用它。

数组是一个单个对象,其中包含很多值,方括号括起来,并用逗号分隔。

In programming, an object is a structure of code that models a real life object. You can have a simple object that represents a car park and contains information about its width and length, or you could have an object that represents a person, and contains data about their name, height, weight, what language they speak, how to say hello to them, and more.

可用对象字面量创建对象,比如var dog = { name : 'Spot', breed : 'Dalmatian' };。

JavaScript中的基础数学数字和操作符

Unlike some other programming languages, JavaScript only has one data type for numbers, you guessed it, Number. 这意味着,你在JavaScript中处理的任何类型的数字,都以完全相同的方式处理它们。所以整数除以整数的结果可以是浮点数。

A control that swaps between two states is generally referred to as a toggle. It toggles between one state and another — light on, light off, etc.

运算符typeof:参数可以是变量,返回数据类型。注意,是运算符。格式,typeof myInt;。吐槽:我无语了,这个运算符的字母o是小写的,但是方法indexOf()的字母O却是大写的。

文本处理 JavaScript中的字符串

想在字符串中包含单引号(双引号),那包裹字符串的就应该用双引号(单引号),或者用转义字符——反斜杠\。

字符串和数字也能用加号相连(浏览器会自动把数字转换为字符串)。

函数Number()能把字符串转换为数字。

方法toString()能把数字转换为字符串。

有用的字符串方法

我们曾经说过,现在我们重申一遍—在javascript中,一切东西都可以被当做对象。

When you create a string, your variable becomes a string object instance, and as a result has a large number of properties(即.XXX and methods(即.XXX() available to it.

您可以使用方括号符号返回字符串中的字符。

属性length:获取字符串或数组的长度。

注意:数组也有indexOf()和slice()方法。

方法indexOf():在字符串中查找子字符串,参数是要查找的子字符串,返回子字符串的第一个字符的下标。找不到则返回-1。吐槽:我无语了,这个方法的字母O是大写的,但是运算符typeof的字母o却是小写的。

方法slice():提取子字符串,参数是字符的下标,返回子字符串。slice()的第二个参数是可选的(表示要提取的子字符串的最后一个字符的下一个下标),如果你没有传入第二个参数,这个分片的结束位置会在原始字符串的末尾。

方法toLowerCase()和toUpperCase():大小写转换(所有字符),不需要参数,返回转换后的字符串。

方法replace():将字符串中的一个子字符串替换为另一个子字符串,需要两个参数 - 要被替换下的子字符串和要被替换上的子字符串,返回替换后的字符串。注意,想要真正更新变量的值,您需要设置变量的值等于返回的结果,它不会自动更新变量的值。——这样只能替换匹配到的第一个子字符串,要想替换所有子字符串,唯一的办法就是提供一个正则表达式。

函数和方法直观的区别是,方法前面有“XXX.”;内在的区别是函数是通用的,而方法是属于某一个对象的函数。

数组

Bear in mind that you can store any item in an array — string, number, object, another variable, even another array. You can also mix and match item types — they don't all have to be numbers, strings, etc, just like this: var random = ['tree', 795, [0, 1, 2]];.

字符串的方法split():在其最简单的形式中,需要一个参数——您要将字符串分隔的字符——并返回分隔符之间的子串,作为数组中的项。这在技术上是一个字符串的方法,而不是一个数组的方法,但是我们把它放在数组这里来讲,是因为它在这里很好。

方法join():这个是数组的方法,进行与split()相反的操作,可以指定一个参数(不指定则默认是逗号)作为分隔符。而如果用方法toString(),则不能指定参数,只能是逗号作为分隔符。

方法push()和方法pop():在数组末尾添加或删除项目。push()的参数可以有多个,即一次添加多个数组项,返回数组的新长度;pop()不需要参数,返回已删除的项目。unshift()和shift()(shift意思是“去掉”)以完全相同的方式工作,只是它们在数组的开始处,而不是结尾。

函数Math.round():四舍五入填入括号内的参数。

 

JavaScript 基础要件

在代码中做决定 - 条件语句

有时候你可能会看到 if…else 语句没有写花括号(但要写在同一行),这是完全有效的代码,但不建议这样使用——因为如果有花括号进行代码切割的话,整体代码被切割为多行代码,更易读和易用。即使只有一句代码,也最好加上花括号。

Any value that is not false, undefined, null, 0, NaN, or an empty string ('') actually returns true when tested as a conditional statement. 因此您甚至可以使用变量是不是未定义的(即有没有被赋值)来作为条件。

&& — 逻辑与

|| — 逻辑或

! — 逻辑非

Note: switch语句的default 部分(不需要break语句)不是必须的 - 如果表达式不可能存在未知值,则可以安全地省略它。 如果有机会,您需要包括它来处理未知的情况。

JS也有三元运算符,即XXX?XXX:XXX。

如果写成if (x === 5 || 7),则很可能写错了,本意应该是if (x === 5 || x === 7)。

循环语句

如果要在所有迭代完成之前退出循环,可以使用break语句。

JS也有C++有的continue语句。

除了for语句,也有while语句和do ... while语句(后两者能做的,for语句一般也能做)。我们建议使用for,因为它可能能最简单地帮你记住一切 - 初始化程序,退出条件和最终表达式都必须整齐地放入括号,所以很容易看到他们在哪里并检查你没有丢失他们。

无限循环的结果是要么浏览器强制终止它,要么它自己崩溃。

函数-可复用的代码块

JavaScript的函数的定义位置随便在哪,在使用前或使用后都行(前提是在一个js文件中而且不能是用函数表达式定义,即要用函数声明)。

In fact, some of the code you are calling when you invoke (a fancy word for run, or execute) a built in browser function couldn't be written in JavaScript — many of these functions are calling parts of the background browser code, which is written largely in low-level system languages like C++, not web languages like JavaScript. Bear in mind that some built-in browser functions are not part of the core JavaScript language — some are defined as part of browser APIs, which build on top of the default language to provide even more functionality.

Technically speaking, built-in browser functions are not functions — they are methods. The distinction is that methods are functions defined inside objects. Built-in browser functions (methods) and variables (which are called properties) are stored inside structured objects, to make the code more efficient and easier to handle.

匿名函数:You generally use an anonymous function along with an event handler. 你还可以将匿名函数分配为变量的值,但这只会令人费解,所以不要这样做!

主要使用匿名函数来运行负载的代码以响应事件触发(如点击按钮)。

Note:当您需要指定多个参数时,它们以逗号分隔(指JS。而CSS有点奇葩)。

如果重复定义一个变量或函数,结果当然是后定义的。

注意:函数作用域的规则不适用于循环(for(){...})和条件块(if(){...} - 它们看起来非常相似,但它们不一样!也就是说,forif外的代码也可以用forif里面的东西。

注意:ReferenceError: "x" is not defined错误是您遇到的最常见的错误。如果您收到此错误,并且确定您已经定义了该问题的变量,就请检查它的作用域范围。

创建您自己的函数

document.querySelector()(参数是CSS中的选择器):a DOM API function,用来选择元素。然后可以把它存放在一个变量中, 这样方便我们接下来使用这个元素。例子:var html = document.querySelector('html');,变量名可以和元素名相同。注:document都可换成element,。

document.createElement()(参数是元素名):a DOM API function,用来创建元素。然后可以把该新建元素的引用(实际上是新建对象的地址)放在一个变量中。例子:var panel = document.createElement('div');。

Element.setAttribute()(Element指引用了HTML中的元素的JS变量;第一参数是属性,第二个参数是值):a DOM API function,给元素添加属性和值,如果属性已经存在,则更新值。它可以方便我们给元素添加样式。例子:panel.setAttribute('class', 'msgBox');。

Node.textContent:a property(属性),  represents the text content of an element — 可以用来改变元素的文本内容。例子:var msg = document.createElement('p');msg.textContent = 'This is a message box';。和innerHTML的效果差不多。两者都为完全替换元素内容提供了一个更加便捷的方式。举个例子,可以通过如下代码完全删除文档内body的内容:document.body.innerHTML = "";或document.body. textContent = "";

Node.appendChild()(Node指引用了HTML中的元素的JS变量):a DOM function,给变量(我们之前定义好的)追加元素 。该方法追加了元素的同时也把元素指定为Node的子元素 。这样做是因为我们创建了一个元素之后这个元素并不会莫名其妙地出现在我们的页面上(浏览器只知道我们创建了一个元素,但是不知道把这个元素怎么呈现出来) — 因此,我们给这个元素一个定位,就是显示在Node引用的HTML中的元素里面!例子:html.appendChild(panel);,这里的html是在JS里定义的变量。

onclick:a property that can be set to a function to specify what code to run when the button is clicked. 可以给 onclick 事件处理器绑定一个匿名函数, 函数中的代码就会在元素被点击的时候运行。onclick就像其它属性一样(比如textContent),只不过有一个特别的地方——当您将一些代码赋给它的时候,只要事触发,代码就会运行。

Node.removeChild():a DOM API function, 指定我们想要移除的HTML中的子元素。至少,你要拥有要删除的节点和其父节点的引用。例子(panel.parentNode即panel的父节点):panel.parentNode.removeChild(panel);。另外,The ChildNode.remove() method removes the object from the tree it belongs to.

不一定要在函数声明后面才调用函数,在C语言中确实是要先定义后使用,但是我们现在用的是JavaScript,它很强大,不管你是先定义后调用还是先调用后定义都行,但是别忘了定义。

btn.onclick = displayMessage;:You might be wondering why we haven't included the parentheses(括号) after the function name. This is because we don't want to call the function immediately — only after the button has been clicked. 如果加了括号,you'll see that the message box appears without the button being clicked! The parentheses in this context are sometimes called the "function invocation(调用) operator". You only use them when you want to run the function immediately in the current scope. In the same respect, the code inside the anonymous function(匿名函数) is not run immediately, as it is inside the function scope.

一个定义了两个参数的函数,可以只使用一个参数进行调用。

Node.style.backgroundImage、Node.style.backgroundColor、Node.style.paddingLeft(这些属性的值都有加引号)

函数返回值

Node.value

onchange: runs whenever the change event fires.

isNaN():判断参数的值是不是数字。如果不是,就返回true。

事件介绍

Events are actions or occurrences that happen in the system you are programming, which the system tells you about so you can respond to them in some way if desired.

Each available event has an event handler(事件处理器), which is a block of code (usually a user-defined JavaScript function) that will be run when the event fires. When such a block of code is defined to be run in response to an event firing, we say we are registering an event handler. Note that event handlers are sometimes called event listeners(事件监听器)——从我们的用意来看这两个名字是相同的,尽管严格地说来这块代码既监听也处理事件。监听器留意事件是否发生,然后处理器就是对事件发生做出的回应。

注: web events不是核心 JavaScript 语言的一部分——它们是作为浏览器内置的JavaScript APIs的一部分被定义的。

document.body.style.backgroundColor

理解JavaScript在不同环境下使用不同的事件模型很重要——从Web api到其他领域,如浏览器WebExtensions(用于开发跨浏览器的插件)和Node.js(服务器端JavaScript)。

The event model in JavaScript for web pages differs from the event model for JavaScript as it is used in other environments. For example, Node.js is a very popular JavaScript runtime that enables developers to use JavaScript to build network and server-side applications. The Node.js event model relies on listeners to listen for events and emitters(发射器) to emit events periodically ——虽然听起来好像差不多,但是实现两者的代码是非常不同的,Node.js 使用 on ( ) 这样的函数来注册一个事件监听器,使用 once ( ) 这样函数来注册一个在运行一次之后注销的监听器。

也可以将一个有名字的函数的名字赋值给事件处理器。

有许多不同的事件处理器属性(properties)可选:

btn.onfocus和btn.onblur — 代码将于按钮被置于焦点或解除焦点时执行。btn可换成别的。

btn.ondblclick — 代码将仅于按钮被双击时执行(不要使用dblclick执行重要的操作,因为键盘无法触发这个事件)。btn可换成别的。

window.onkeypress, window.onkeydown, window.onkeyup — 代码将于按一下键、按下键或松开键时执行(可以把window换成别的)。

btn.onmouseover 和 btn.onmouseout — 代码将会在鼠标移入按钮上方时执行, 或者当它从按钮移出时。btn可换成别的。

不要使用内联的事件处理器。

将您的编程逻辑与内容分离也会使您的站点对搜索引擎更加友好。

addEventListener()和removeEventListener():addEventListener()这个函数和事件处理器属性(properties)是类似的,但是语法略有不同。例子:btn.onclick = bgChange;和btn.addEventListener('click', bgChange);是等效的。如果需要,可以使用removeEventListener()删除事件处理器代码,而且如果需要,您可以向同一类型的元素添加多个监听器。例如,您可以在一个元素上多次调用addEventListener('click', function() { ... }),而第二个参数中指定不同的函数。对于事件处理器属性来说,这是不可能的,因为后面设置的属性会覆盖较早的属性。

只要可能,应该用DOM Level 2 Events (addEventListener(), etc.)。

事件对象(event objects, 即参数e):It is automatically passed to event handlers to provide extra features and information.

事件对象 e target属性始终是刚刚发生的事件所在的元素的引用。您可以使用任何您喜欢的名称作为事件对象。开发人员最常使用 e / evt / event,因为它们很简单易记。坚持标准总是很好。当您要在多个元素上设置相同的事件处理程序时,e.target非常有用(this不也一样吗,要写的代码还更少事件委托的情况下不一样,只能用e.target——不过注意,即使是其余情况,this也只能代替e.target,e的别的功能代替不了)。例如,你可能有一组16块方格,当它们被点击时就会消失。用e.target总是能准确选择当前操作的东西(方格)并执行操作让它消失,而不是必须以更困难的方式选择它。

一些浏览器支持自动的表单数据验证功能,但由于许多浏览器不支持,因此建议你不要依赖这些功能,并实现自己的验证检查。

onsubmit

document.getElementById()

e.preventDefault():阻止默认行为,比如表单的提交。

如何控制一个元素的显示和隐藏?想隐藏可以把元素放到屏幕外或者用display: none或者用visibility: none。

当一个事件发生在具有父元素的元素上时,现代浏览器运行两个不同的阶段 - 捕获阶段和冒泡阶段。

在捕获阶段:

  • 浏览器检查元素的最外层祖先<html>,是否在捕获阶段中注册了一个onclick事件处理程序,如果是,则运行它。
  • 然后,它移动到<html>中的下一个元素,并执行相同的操作,然后是下一个元素,依此类推,直到到达实际点击的元素。

在冒泡阶段,恰恰相反:

  • 浏览器检查实际点击的元素是否在冒泡阶段中注册了一个onclick事件处理程序,如果是,则运行它
  • 然后它移动到下一个直接的祖先元素,并做同样的事情,然后是下一个,等等,直到它到达<html>元素。

在现代浏览器中,默认情况下,所有事件处理程序都在冒泡阶段进行注册。这在大多数情况下更有意义。如果您真的想在捕获阶段注册一个事件,那么您可以通过使用addEventListener()注册您的处理程序,并将可选的第三个属性设置为true。

标准事件对象具有可用的名为 stopPropagation()(Propagation意为传播)的函数, 当在事件对象上调用该函数时,它只会让当前事件处理程序运行,但事件不会在冒泡链上进一步扩大,因此将不会有更多事件处理器被运行(不会向上冒泡)。

事件委托(Event delegation):冒泡还允许我们实现事件委托——这个概念依赖于这样一个事实,如果你想要在大量子元素中单击任何一个都可以运行一段代码,您可以将事件监听器设置在其父节点上,并将事件监听器气泡的影响设置为每个子节点,而不是每个子节点单独设置事件监听器。

一个很好的例子是一系列列表项,如果你想让每个列表点击时弹出一条信息,您可以将click单击事件监听器设置在父元素<ul>上,它将会冒泡到列表项上。

getAttribute():参数为某个Attribute,返回该Attribute的value。

 

JavaScript 对象介绍

在 JavaScript 中,大多数事物都是对象, 从作为核心功能的字符串和数组,到建立在 JavaScript 之上的浏览器 API。

对象基础

An object is a collection of related data and/or functionality (which usually consists of several variables and functions — which are called properties and methods when they are inside objects.)

一个对于初学者很常见的错误是在最后一个成员后面多了一个逗号,这会引发错误。

一个对象由许多的成员组成,每一个成员都拥有一个名字(如name、age),和一个值(如['Bob', 'Smith']、32)。每一个名字/值(name/value)对被逗号分隔开,并且名字和值之间由冒号(:)分隔。成员的值可以是函数(function)。值不是函数的成员叫属性(property),值是函数的成员叫方法(method)。

object literal(对象的字面量) — we've literally written out the object contents as we've come to create it.

当你想要传输一些有结构和关联的资料时常见的方式是使用字面量来创建一个对象,举例来说,发起一个请求到服务器以存储一些数据到数据库,发送一个对象要比分别发送这些数据更有效率,而且比起数组更为易用,因为你使用名字(name)来标识这些资料。

The object name (如person) acts as the namespace.

除了用dot notation来访问对象的属性和方法,还能用bracket notation。比如,person['name']['first']和person.name.first是等价的。这看起来很像访问一个数组的元素,从根本上来说是一回事儿,你使用了关联了值的名字,而不是索引去选择元素。难怪对象有时被称之为关联数组(associative array)了——对象做了字符串到值的映射,而数组做的是数字到值的映射。你用dot notation和bracket notation不仅更新已经存在的成员的值,还可创建新的成员。bracket notation一个有用的地方是它不仅可以动态地设置成员的值,还可以动态地设置成员的名字,如下:

var myDataName = 'height';

var myDataValue = '1.75m';

person[myDataName] = myDataValue;

Adding a property to an object using the method above isn't possible with dot notation, which can only accept a literal member name, not a variable value pointing to a name.

For each webpage loaded, an instance of Document is created, called document, which represents the entire page's structure, content, and other features such as its URL.

built-in API 等于 built-in object

It is useful to think about the way objects communicate as message passing — when an object needs another object to perform some kind of action often it will send a message to another object via one of its methods, and wait for a response, which we know as a return value.

你应该清楚对象有利于存储一些相关联的数据和函数,如果你尝试以分开的方式去保存person对象包含的所有的属性和方法,这是令人沮丧且效率低下的,而且会有很多的变量和函数之间同名的风险。对象使我们将一些信息安全地锁在了它们自己的包内,防止它们被损坏。

适合初学者的JavaScript面向对象

注:本节内容非常难懂,做好心理准备(可能还不如看https://www.cnblogs.com/shuiyi/p/5305435.html

基本的 OOP 思想就是使用对象来模仿我们想要在我们的程序中表现的现实世界的事物, 同时提供一种简单的方式来访问这些事物的功能。(The basic idea of OOP is that we use objects to model real world things that we want to represent inside our programs, and/or provide a simple way to access functionality that would otherwise be hard or impossible to make use of.)

Object data (and often, functions too) can be stored neatly (the official word is encapsulated(封装)) inside an object package (which can be given a specific name to refer to, which is sometimes called a namespace), making it easy to structure and access; objects are also commonly used as data stores that can be easily sent across the network.

abstraction(抽象) — creating a simple model of a more complex thing, which represents its most important aspects in a way that is easy to work with for our program's purposes.

在一些面向对象的语言中,我们用类(class)的概念去描述一个对象(您在下面就能看到JavaScript使用了一个完全不同的术语)-类并不完全是一个对象,它更像是一个定义对象特质的模板。注:红宝书说JS没有类。

When an object instance is created from a class, the class's constructor function(构造函数,used to define objects and their features. is run to create it. This process of creating an object instance from a class is called instantiation(实例化) — the object instance is instantiated from the class.

The fancy word for the ability of multiple object types to implement the same functionality is polymorphism(多态).

The constructor function below is JavaScript's version of a class, 它只定义了对象的属性和方法,没有明确创建一个对象和返回任何值(构造函数模式):

function Person(name) {

  this.name = name;

  this.greeting = function() {

    alert('Hi! I\'m ' + this.name + '.');

  };

}    

如果不用this,就要写成这样(工厂模式。注意,这不是构造函数):

function createNewPerson(name) {

  var obj = {};

  obj.name = name;

  obj.greeting = function () {

    alert('Hi! I\'m ' + this.name + '.');

  }

  return obj;

}

所以,this能简化构造函数的编写。

Note: A constructor function name usually starts with a 大写字母 — this convention(惯例) is used to make constructor functions easier to recognize in code.

那如何调用构造函数创建新的实例呢?答:var person1 = new Person('Bob'); 。the new keyword is used to tell the browser we want to create a new object instance.

When we are calling our constructor function, we are defining greeting() every time(因为方法直接定义在了构造器函数里而不是prototype属性里), which isn't ideal. To avoid this, we can define functions on the prototype(原型) instead, which we will look at later.

同一个构造函数创建出的不同实例被存储在不同的命名空间里。

Sub-namespaces: It is possible to make the value of an object member another object(即对象中的对象).

So far we've seen two different ways to create an object instance— declaring an object literal, and using a constructor function(上面还提到第三种,工厂模式). These make sense, but there are other ways — we want to make you familiar with these in case you come across them in your travels around the Web.

The Object() constructor: You can use the Object() constructor to create a new object. Yes, even generic objects have a constructor, which generates an empty object. 例子:var person1 = new Object();

Using the create() method: Some people prefer to create object instances without first creating constructors, especially if they are creating only a few instances of an object. JavaScript has a built-in method called create() that allows you to do that. With it, you can create a new object based on any existing object. 例子: var person2 = Object.create(person1);

Object prototypes

Prototypes are the mechanism(机制) by which JavaScript objects inherit features from one another. The prototype property can be used to add methods to existing constructors.

JavaScript is often described as a prototype-based language — each object has a prototype object, which acts as a template object that it inherits methods and properties from. An object's prototype object may also have a prototype object, which it inherits methods and properties from, and so on. This is often referred to as a prototype chain(原型链).

To be exact, the properties and methods are defined on the prototype property on the Objects' constructor functions, not the object instances themselves.

It's important to understand that there is a distinction between an object's prototype and the prototype property on constructor functions. The former is the property on each instance, and the latter is the property on the constructor. That is, Object.getPrototypeOf(new Foobar()) refers to the same object as Foobar.prototype.

举个栗子:person1's prototype object is the Person() (Person() is the constructor). person1中除了有在原型对象Person()中定义的成员外,还有一些其它成员,they are defined on the Person() 's prototype object, which is Object. 就像下图所示:

 

 

What happens if you call a method on person1, which is actually defined on Object? For example:

person1.valueOf()

This method simply returns the value of the object it is called on — try it and see! In this case, what happens is(当js引擎查找对象的属性或方法时,先在对象本身上找(但不会在对象的prototype属性中找),找不到就顺着原型链、在原型链上的对象的prototype属性中找):

  • The browser initially checks to see if the person1 object has a valueOf() method available on it.
  • It doesn't, so the browser then checks to see if the person1 object's prototype object (Person() constructor's prototype) has a valueOf() method available on it.
  • It doesn't either, so the browser then checks to see if the Person() constructor's prototype object's prototype object (Object() constructor's prototype) has a valueOf() method available on it. It does, so it is called, and all is good!

Note: 必须重申,原型链中的方法和属性没有被复制到其他对象 — they are accessed by walking up the chain as described above.

The inherited ones are the ones defined on the prototype property (you could call it a sub-namespace) — that is, the ones that begin with Object.prototype., and not the ones that begin with just Object.

Person.prototype和Object.prototype之类的是指Person、Object的prototype属性,要指Person、Object的原型对象,则要用.__proto__

重要:prototype 属性大概是 JavaScript 中最容易混淆的名称之一。你可能会认为,这个属性指向当前对象的原型对象,其实不是(还记得么?原型对象是一个内部对象,应当使用 __proto__ 访问)。prototype 属性包含(指向)一个对象,你在这个对象中定义需要被继承的成员。

var person2 = Object.create(person1);

create() 实际做的是从指定原型对象创建一个新的对象。这里以 person1 为原型对象创建了 person2 对象。在控制台输入:person2.__proto__结果返回 person1 对象。

每个对象实例都具有 constructor 属性,它指向创建该实例的构造器函数。

person1.constructor和person2.constructor都将返回 Person() 构造器,因为该构造器包含这些实例的原始定义。一个小技巧是,你可以在 constructor 属性的末尾添加一对圆括号(括号中包含所需的参数),从而用这个构造器创建另一个对象实例。毕竟构造器是一个函数,故可以通过圆括号调用;只需在前面添加 new 关键字,便能将此函数作为构造器使用。通常你不会去用这种方法创建新的实例;但如果你刚好因为某些原因没有原始构造器的引用,那么这种方法就很有用了。此外,constructor 属性还有其他用途。比如,想要获得某个对象实例的构造器的名字,可以这么用:instanceName.constructor.name。具体地,像这样:person1.constructor.name。

为构造器的 prototype 属性添加一个新的方法,则整条继承链动态地更新了,任何由此构造器创建的对象实例都自动获得了这个方法。旧有对象实例的可用功能被自动更新了。这证明了先前描述的原型链模型。这种继承模型下,上游对象的方法不会复制到下游的对象实例中;下游对象本身虽然没有定义这些方法,但浏览器会通过上溯原型链、从上游对象中找到它们。这种继承模型提供了一个强大而可扩展的功能系统。

你很少看到属性定义在 prototype 属性中,因为如此定义不够灵活。Person.prototype.fullName = this.name.first + ' ' + this.name.last;这么做的话,this 引用的是全局范围,而非函数范围。访问这个属性只会得到 undefined undefined(除非全局真有name这个对象和相应的属性)。但这个语句若放在prototype属性的方法中则不会发生这种情况,因为此时语句位于函数范围内,从而能够成功地转换为对象实例范围。你可能会在 prototype属性上定义常属性 (constant property) (指那些你永远无需改变的属性),但一般来说,在构造器内定义属性更好。

一种极其常见的对象定义模式是,在构造函数(constructor)中定义属性(properties)、在 prototype 属性上定义方法(methods)。如此,构造函数只包含属性定义,而方法则分装在不同的代码块,代码更具可读性。例如:

// 构造函数及其属性定义

function Test(a,b,c,d) {

  // 属性定义

};

// 定义第一个方法

Test.prototype.x = function () { ... }

// 定义第二个方法

Test.prototype.y = function () { ... }

// 等等……

JavaScript 中的继承

栗子:

function Teacher(first, last, age, gender, interests, subject) {

  Person.call(this, first, last, age, gender, interests);

 

  this.subject = subject;

}

Teacher.prototype = Object.create(Person.prototype) //或者 new Person();

Teacher.prototype.constructor = Teacher;

每一个函数对象(Function)都有一个prototype属性,并且只有函数对象有prototype属性,因为prototype本身就是定义在Function对象下的属性。当我们输入类似var person1=new Person(...)来构造对象时,JavaScript实际上参考的是Person.prototype指向的对象来生成person1。另一方面,Person()函数是Person.prototype的构造函数,也就是说Person===Person.prototype.constructor(不信的话可以试试)。

在定义新的构造函数Teacher时,我们通过function.call来调用父类的构造函数。然后我们利用Object.create()方法将Person.prototype作为Teacher.prototype的原型对象,并改变其构造器指向,使之与Teacher关联。

任何您想要被继承的方法都应该定义在构造函数的prototype对象里,并且永远使用父类的prototype来创造子类的prototype,这样才不会打乱类继承结构。

就在自己代码中使用继承而言,您可能不会使用得非常频繁,特别是在小型项目中或者刚开始学习时 - 因为当您不需要对象和继承的时候,仅仅为了使用而使用它们只是在浪费时间而已。但是随着您的代码量的增大,您会越来越发现它的必要性。如果您开始创建一系列拥有相似特性的对象时,那么创建一个包含所有共有功能的通用对象,然后在更特殊的对象类型中继承这些特性,将会变得更加方便有用。

Because of the way JavaScript works, with the prototype chain, etc., the sharing of functionality between objects is often called delegation.

在使用继承时,建议您不要使用过多层次的继承,并仔细追踪定义方法和属性的位置。很有可能您的代码会临时修改了浏览器内置对象的原型,但您不应该这么做,除非您有足够充分的理由。过多的继承会在调试代码时给您带来无尽的混乱和痛苦。

 

Ultimately(根本上), objects are just another form of code reuse(重用), like functions or loops, with their own specific roles and advantages. If you find yourself creating a bunch of related variables and functions and want to track them all together and package them neatly, an object is a good idea. Objects are also very useful when you want to pass a collection of data from one place to another. Both of these things can be achieved without use of constructors or inheritance. If you only need a single instance of an object, then you are probably better off just using an object literal, and you certainly don't need inheritance.(总之,对象是另一种形式的代码重用,就像函数和循环一样,有他们特定的角色和优点。如果您发现自己创建了一堆相关的变量和函数,还想一起追踪它们并将其灵活打包的话,对象是个不错的主意。对象在您打算把一个数据集合从一个地方传递到另一个地方的时候非常有用。这两种情况都可以在不使用构造器和继承的情况下完成。如果您只是需要一个单一的对象实例,也许使用对象常量会好些,您当然不需要使用继承。)

Working with JSON

JavaScript Object Notation (JSON) is a standard text-based format for representing structured data based on JavaScript object syntax(JSON是一种基于文本的格式,代表结构化的数据,基于JS对象语法).

JSON exists as a string — useful when you want to transmit data across a network. It needs to be converted to a native JavaScript object when you want to access the data. This is not a big issue —  JavaScript provides a global JSON object that has methods available for converting between the two.

Note: Converting a string to a native object is called parsing(解析), while converting a native object to a string so it can be transmitted across the network is called stringificationstring化).

A JSON object can be stored in its own file, which is basically just a text file with an extension of .json, and a MIME type of application/json.

A JSON is a string whose format very much resembles JavaScript object literal format. You can include the same data types inside JSON as you can in a standard JavaScript object — strings, numbers, arrays, booleans, and other object literals.

我们使用 . 或 [] 访问对象内的数据。

”我们已经可以推测出 JSON 对象就是基于JavaScript 对象,而且这几乎是正确的“——我们说几乎正确的原因是数组也是一种合法的 JSON 对象(其实数组也是JavaScript 对象)。

JSON 是一种纯数据格式,它只包含属性,没有方法。

JSON 要求有两头的 { } 来使其合法。

甚至一个错位的逗号或分号就可以导致  JSON 文件出错。您应该小心的检查您想使用的数据(虽然计算机生成的 JSON 很少出错,只要生成程序正常工作)。您可以通过像 JSONLint 的应用程序来检验 JSON。

为了载入 JSON 到页面中,我们将使用 一个名为XMLHTTPRequest的API(常称为XHR)。这是一个非常有用的 JavaScript 对象,使我们能够通过代码来向服务器请求资源文件(如:图片,文本,JSON,甚至HTML片段),意味着我们可以更新小段内容而不用重新加载整个页面。

举个栗子:

var requestURL = 'https://mdn.github.io/learning-area/javascript/oojs/json/superheroes.json';

var request = new XMLHttpRequest();:为了创建一个HTTP请求,我们需要创建一个HTTP请求对象。

request.open('GET', requestURL);:使用 open() 函数打开一个新的请求。这个函数至少含有两个参数,其它的是可选参数。

request.responseType = 'json'; request.send();:设定 responseType 为 JSON,所以服务器将知道我们想要返回一个 JSON 对象,然后发送请求。这样做的话,就访问 JSON 而言是简单的,因为我们设置了 XHR 来访问 JSON 格式数据

request.onload = function() {

  var superHeroes = request.response;

  populateHeader(superHeroes);

  showHeroes(superHeroes);

}:这儿我们保存了相应我们请求的数据(访问 response 属性) 于变量 superHeroes ;这个变量现在含有 JSON!我们现在把superHeroes传给两个函数,第一个函数将会用正确的数据填充<header>,同时第二个函数将创建一个信息卡片,然后把它插入<section>中。我们把代码包在事件处理函数中,当请求对象load事件触发时执行代码,这是因为请求对象load事件只有在接收到完整的响应数据时触发;这种方式可以保证事件触发时request.response 是绝对可以访问的。注:populateHeader()和showHeroes()是自定义的函数。

有时候,我们接收到一些 字符串作为 JSON 数据,然后我们想要将它转换为对象。当我们想要发送 JSON 数据作为信息,我们将需要转换它为字符串,我们经常需要正确的转换数据,幸运的是,这两个问题在web环境中是那么普遍以至于浏览器拥有一个内建的 JSON,包含以下两个方法

parse(): 以文本字符串形式接受JSON对象作为参数,并返回相应的对象。。

stringify(): 接收一个对象作为参数,返回一个对应的JSON字符串。

实践对象构造

打开浏览器中的 JavaScript 控制台后,刷新页面,可更新F12中的盒模型数据(前提是盒模型的尺寸确实变了)。

 

客户端网页 API

Web API简介

  • JavaScript — A high-level scripting language built into browsers that allows you to implement functionality on web pages/apps. Note that JavaScript is also available in other programming environments, such as Node.
  • Browser APIs — constructs built into the browser that sit on top of the JavaScript language and allow you to implement functionality more easily(比如DOM、BOM).
  • Third party APIs — constructs built into third-party platforms (e.g. Twitter, Facebook) that allow you to use some of those platform's functionality in your own web pages (for example, display your latest Tweets on your web page).
  • JavaScript libraries — Usually one or more JavaScript files containing custom functions that you can attach to your web page to speed up or enable writing common functionality. Examples include jQuery, Mootools and React.
  • JavaScript frameworks — The next step up from libraries, JavaScript frameworks (e.g. Angular and Ember) tend to be packages of HTML, CSS, JavaScript, and other technologies that you install and then use to write an entire web application from scratch. The key difference between a library and a framework is “Inversion(倒置) of Control”. When calling a method from a library, the developer is in control. With a framework, the control is inverted: the framework calls the developer's code.

匿名函数的括号们的放置可以像这样:

navigator.geolocation.getCurrentPosition(function(position) {

  ……

});

仅在操作完成时调用函数的模式在JavaScript API中非常常见 - 确保一个操作已经完成,然后在另一个操作中尝试使用该操作返回的数据。这些被称为 asynchronous  “异步”操作。由于获取设备的当前位置依赖于外部组件(设备的GPS或其他地理定位硬件), we can't guarantee that it will be done in time to just immediately use the data it returns. 因此,这样子是行不通的:

var position = navigator.geolocation.getCurrentPosition();

var myLatitude = position.coords.latitude;

如果第一行还没有返回结果(第一行是异步的),则第二行将会出现错误,因为位置数据还不可用。 出于这个原因,涉及异步操作的API被设计为使用 callback functions “回调函数”,或更现代的 Promises 系统,这些系统在ECMAScript 6中可用,并被广泛用于较新的API。

API使用一个或多个 JavaScript objects 在您的代码中进行交互,这些对象用作API使用的数据(包含在对象属性中)的容器以及API提供的功能(包含在对象方法中)。

您将在许多API中看到两种常见模式:首先,API对象通常包含构造函数,可以调用这些构造函数来创建用于编写程序的对象的实例。 其次,API对象通常有几个可用的options,可以调整以获得您的程序所需的确切环境(根据不同的环境,编写不同的Options对象)。 API构造函数通常接受options对象作为参数,这是您设置这些options的地方。

使用API时,应确保知道API入口点的位置。 在Geolocation API中,这非常简单 - 它是 Navigator.geolocation 属性, 它返回浏览器的 Geolocation 对象,所有有用的地理定位方法都可用。文档对象模型 (DOM) API有一个更简单的入口点 —它的功能往往被发现挂在 Document 对象, 或任何你想影响的HTML元素的实例。

一些Web API不包含事件,但有些包含一些事件。

WebAPI功能受到与JavaScript和其他Web技术(例如同源政策)相同的安全考虑,但是他们有时会有额外的安全机制。

Manipulating(操纵) documents

直接出现在web页面视图中的浏览器的主要部分:

  • window是载入浏览器的标签,使用这个对象的可用方法,你可以返回窗口的大小(参见window.innerWidthwindow.innerHeight),操作载入窗口的文档,存储客户端上文档的特殊数据(例如使用本地数据库或其他存储设备),为当前窗口绑定event handler,等等。
  • navigator表示浏览器(即用户代理)的状态和身份。你可以用这个对象获取一些信息,比如来自用户摄像头的地理信息、用户偏爱的语言、多媒体流等等。
  • document(在浏览器中用DOM表示)是载入窗口的实际页面,你可以用这个对象来返回和操作文档中HTML和CSS上的信息。例如获取DOM中一个元素的引用,修改其文本内容,并应用新的样式,创建新的元素并添加为当前元素的子元素,甚至把他们一起删除。

在浏览器标签中当前载入的文档用文档对象模型来表示。这是一个由浏览器生成的“树结构”,使编程语言可以很容易地访问HTML结构 — 例如浏览器自己在呈现页面时,使用它将样式和其他信息应用于正确的元素,而页面呈现完成以后,开发人员可以用JavaScript操作DOM。文档中每个元素和文本在树中都有它们自己的入口 — 称之为节点(node)(即节点包括元素和文本)

要操作DOM内的元素,首先需要选择它,并将它的引用存储在一个变量中,栗子:var link = document.querySelector('a');——Now we have the element reference stored in a variable, we can start to manipulate it using properties and methods available to it (these are defined on interfaces like HTMLAnchorElement in the case of <a> element, its more general parent interface HTMLElement, and Node — which represents all nodes in a DOM).

注意,有很多方法可以选择一个元素,并在一个变量中存储一个引用。Document.querySelector()是推荐的主流方法,它允许你使用CSS选择器选择元素,使用很方便。上面的querySelector()调用会匹配它在文档中遇到的第一个<a>元素。如果想对多个元素进行匹配和操作,你可以使用Document.querySelectorAll(),这个方法匹配文档中每个匹配选择器的元素,并把它们的引用存储在一个假的array(NodeList)中。querySelectorAll的结果不会动态更新。

Document.getElementById()是旧的方法,没那么方便,而Document.querySelector()可以实现相同的功能。

Document.createTextNode():创建文本节点。栗子:var text = document.createTextNode('Hi');

如果我们想移动 the paragraph with the link inside it to the bottom of the section, we could simply do this: sect.appendChild(linkPara);This moves the paragraph down to the bottom of the section. 你可能会以为这会创建那个段落的副本,但是并没有 — linkPara 是那个段落的唯一引用。 If you wanted to make a copy and add that as well, you'd need to use Node.cloneNode() instead.

操纵样式:可用HTMLElement.style属性添加内联样式。另一种方法,添加的不是内联样式:在CSS里写好样式,然后在JavaScript里用Element.setAttribute()匹配样式。两种方式各有优缺点,选择哪种取决于你自己。第一种方式简单,第二种方式更加纯粹(没有CSS和JavaScript的混合,没有内联样式这些被认为是不好的实践)。当你开始构建更大更复杂的应用时,你可能会更多地使用第二种方法,但这完全取决于你自己。

注意: CSS样式的JavaSript属性版本以小写驼峰式命名法书写,而CSS样式的CSS版本用连接符号(比如,backgroundColor 对 background-color)。确保你不会混淆,否则就不能工作。

目前为止,我们还没有做任何有用的事!使用JavaScript创建静态内容是毫无意义的你也能用HTML实现它,而不用JavaScript用JavaScript实现还更复杂,而且还有其它问题,比如不会被搜索引擎获取。

window.innerWidth和window.innerHeight是the width and height of the viewport。

window.onresize事件 : The window object has an event available on it called resize, which is fired every time the window is resized. 可以用来实现不管视口的大小是多少,应用程序都和它所在的视口一样大。

使用focus()方法可以在进入页面时自动聚焦。

posted @ 2018-06-10 23:41  刘胡粤  阅读(786)  评论(0编辑  收藏  举报