# 基本语法
看阮一峰老师的笔记。基本语法
# DOM 概述
(DOM 是操作网页的,而 BOM 是操作浏览器的)
DOM 是 JavaScript 操作网页的接口,全称为 “文档对象模型”,他的作用是将一个网页转为一个 JavaScript 对象,从而可以用脚本语言进行各种操作。(增删内容)。
DOM 的最小组成单位叫做节点(node)。文档的树形结构(DOM 树),就是由各种不同类型的节点组成。每个节点可以看作是文档树的一片叶子。
- Document:整个文档树的顶层节点
- DocumentType:doctype 标签(比如
<!DOCTYPE html>
) - Element:网页的各种 HTML 标签(比如
<body>
、<a>
等 `) - Attr:网页元素的属性(比如 class="right")
- Text:标签之间或标签包含的文本
- Comment:注释
- DocumentFragment:文档的片段
节点树
一个文档的所有节点,按照所在的层级,可以抽象成一种树状结构。这种树状结构就是 DOM 树。它有一个顶层节点,下一层都是顶层节点的子节点,然后子节点又有自己的子节点,就这样层层衍生出一个金字塔结构,又像一棵树。浏览器原生提供 document 节点,代表整个文档。
document--- 整个文档树
文档的第一层有两个节点,第一个是文档类型节点(<!doctype html>),第二个是 HTML 网页的顶层容器标签
<html>
。后者构成了树结构的根节点(root node),其他 HTML 标签节点都是它的下级节点。除了根节点,其他节点都有三种层级关系。
父节点关系(parentNode):直接的上级节点
子节点关系(childNodes):直接的下级节点
同级节点关系(sibling):拥有同一个父节点的节点
DOM 提供操作接口,用来获取这三种关系的节点。比如,子节点接口包括 firstChild(第一个子节点)和 lastChild(最后一个子节点)等属性,同级节点接口包括 nextSibling(紧邻在后的那个同级节点)和 previousSibling(紧邻在前的那个同级节点)属性。
# DOM 查询
- childNodes;
表示当前节点的所有子节点。(节点,包含空格、换行) - children;
表示可以获取当前元素的所有子元素。(元素,标签,经常用) - firstChild;
表示当前节点的第一个子节点。 - lastChild;
表示当前节点的最后一个子节点。 - parentNode;
表示当前节点的父节点。 - previousSibling;
表示当前节点的前一个兄弟节点。 - nextSibling;
表示当前节点的后一个兄弟节点。
# 数据类型
JavaScript 语言的每一个值,都属于某一种数据类型。JavaScript 的数据类型,共有六种。
数值(number):整数和小数
字符串(string):文本
布尔值(boolean):true 和 false
undefined:表示未定义或不存在。
null:表示空值。
对象:(objeck)各种值组成的集合。
其中:在对象中又分为
(1)狭义的对象(object)
(2)数组(array)
(3)函数(function)
逻辑运算符
与 &&
或 ||
非 !
相等运算符
=== 绝对相等
== 等于
!= 不等于
# 对象
对象
简单来说,对象就是一组键值对。键名:属性名
键值:属性值
对象可以是一个方法例:
var obj = {
p:function (x) {
return 2 * x;
}
};
obj.p(1) //2
属性的操作
读取属性:
采用点运算符和方括号运算符来读取属性 中的值。点运算符和方括号运算符也可以用来赋值。查看一个对象本身的所有属性可以用
object.keys (对象名)delete 命令用于删除对象的属性。删除成功后会返回 true。
例:var obj = { p:1}
delete obj.p。
注:删除一个不存在的属性时,delete 不会报错。而且也是返回一个 true。
in 运算符
in 运算符是检查对象是否包含某个属性,注意(检查的是属性,不是属性值)如果包含就返回 ture。
例:var obj = { p:1 }
‘p’in obj
此时,控制台返回一个 true
for ...in 循环。
for ...in 循环用来遍历一个对象的全部属性值。
例:var obj = {a:1,b:2,c:3};
for (var i in obj){
console.log( obj[ i ] );
}
此时控制台输出 1,2,3
# 对象的继承
面向对象编程很重要的一个方面,就是对象的继承。A 对象通过继承 B 对象,就能直接拥有 B 对象的所有属性和方法。这对于代码的复用是非常有用的。大部分编程语言都是通过类(class)实现对象的继承。
js 继承不是通过(class)而是通过原型对象(prototype)实现继承的。
constructor 属性
prototype 对象有一个 constructor 属性,默认指向 prototype 对象所在的构造函数。function P() {}
P.prototype.constructor === P // true
由于 constructor 属性定义在 prototype 对象上面,意味着可以被所有实例对象继承。
# 面向对象编程
对象是什么?
- 面向对象编程。缩写为 OOP,是目前主流的编程范式。它将真实世界各种复杂的关系,抽象为一个个对象,然后由对象之间的分工与合作,完成对真实世界的模拟。
- 每一个对象都是功能中心,具有明确分工,可以完成接受信息、处理数据、发出信息等任务。对象可以复用,通过继承机制还可以定制。因此,面向对象编程具有灵活、代码可复用、高度模块化等特点,容易维护和开发,比起由一系列函数或指令组成的传统的过程式编程(procedural programming),更适合多人合作的大型软件项目。
- 对象是单个实物的抽象。一本书、一辆汽车、一个人都可以是对象,一个数据库、一张网页、一个与远程服务器的连接也可以是对象。当实物被抽象成对象,实物之间的关系就变成了对象之间的关系,从而就可以模拟现实情况,针对对象进行编程。
- 对象是一个容器,封装了属性(property)和方法(method)。属性是对象的状态,方法是对象的行为(完成某种任务)。比如,我们可以把动物抽象为 animal 对象,使用 “属性” 记录具体是那一种动物,使用 “方法” 表示动物的某种行为(奔跑、捕猎、休息等等)。
构造函数。
面向对象编程的第一步,就是要生成对象。前面说过,对象是单个实物的抽象。通常需要一个模板,表示某一类实物的共同特征,然后对象根据这个模板生成。
典型的面向对象编程语言(比如 C++ 和 Java),都有 “类”(class)这个概念。所谓 “类” 就是对象的模板,对象就是 “类” 的实例。但是,JavaScript 语言的对象体系,不是基于 “类” 的,而是基于构造函数(constructor)和原型链(prototype)。
JavaScript 语言使用构造函数(constructor)作为对象的模板。所谓” 构造函数”,就是专门用来生成实例对象的函数。它就是对象的模板,描述实例对象的基本结构。一个构造函数,可以生成多个实例对象,这些实例对象都有相同的结构造函数就是一个普通的函数,但是有自己的特征和用法。var Vehicle = function(){
this.price = 1000;
}
上面代码中,Vehicle 就是构造函数。为了与普通函数区别,构造函数名字的第一个字母通常大写。
构造函数的两个特点:
- 函数体内部使用了 this 关键字,代表了所要生成的对象的实例。
- 生成对象的时候,必须使用 new 命令。
new 命令的原理
使用 new 命令时,他后面的函数依次执行下面的步骤。
- (1)创建一个空对象,作为将要返回的对象实例。
- (2)将这个空对象的原型,指向构造函数的 prtotype 属性。
- (3)将这个空对象赋值给函数内部的 this 关键字。
- (4)开始执行构造函数内部的代码。
也就是说,构造函数内部,this 指的是一个新生成的空对象,所有针对 this 的操作,都会发生在这个空对象上。构造函数之所以叫 “构造函数”,就是说这个函数的目的,就是操作一个空对象(即 this 对象),将其 “构造” 为需要的样子。
# BOM 对象
浏览器对象模型,BOM 可以使我们通过 js 来操作浏览器,在 BOM 中提供一组对象,用来完成对浏览器的操作
window
代表的是整个浏览器的窗口,同时 window 也是网页中的全局对象。
Navigator
代表的是当前浏览器的信息,通过该对象可以来识别不同的浏览器。
Location
代表当前浏览器的地址信息,通过 Location 可以获取地址栏信息,或者操作浏览器跳转页面
History
代表浏览器的历史记录,可以通过该对象来操作浏览器的历史记录,由于隐私原因,该对象不能获取到具体的历史记录,只能操作浏览器想前或者像后。而且该操作只在档次访问时有效。(关闭在打开就没有效果了)
# Date 对象
Date 对象是 JavaScript 原生的时间库。它以国际标准时间(UTC)1970 年 1 月 1 日 00:00:00 作为时间的零点,可以表示的时间范围是前后各 1 亿天(单位为毫秒)。
用法
Date 对象可以作为普通函数直接调用,返回一个代表当前时间的字符串。Date()
// "Tue Dec 01 2015 09:34:43 GMT+0800 (CST)"
无论有没有参数,返回的总是当前时间。
实例方法
Date 的实例对象,有几十个自己的方法,除了 valueOf 和 toString,可以分为以下三类。
- to 类:从 Date 对象返回一个字符串,表示指定时间。
- get 类:获取 Date 对象的日期和时间。
- set 类:设置 Date 对象的日期和时间。
拿到当前时间打印出来,输出在页面显示。
<div id="time">
现在还不是时间
</div>
<script type="text/javascript">
window.onload=function(){
setInterval(function(){
times();
},1000);
}
function times () {
var uu = document.getElementById("time");
var today = new Date();
var year = today.getFullYear();
var yue = today.getMonth()+1;
var day = today.getDate();
var shi = today.getHours();
var fen = today.getMinutes();
var miao = today.getSeconds();
var zhou = today.getDay();
// console.log(zhou)
var arr_week = new Array("星期日","星期一","星期二","星期三","星期四","星期五","星期六")
week = arr_week[zhou];
if(yue<10){
yue="0"+yue
}
if(miao<10){
miao = "0"+miao
}
if(fen<10){
fen = "0"+fen
}
var time = "现在是"+year+"年"+yue+"月"+day+"日"+shi+"点-"+fen+"分-"+miao+"秒-"+week
uu.innerHTML=time;
}
</script>
# Math 对象
Math静态方法:
Math 对象提供以下一些静态方法。
Math.abs():绝对值
Math.ceil ():向上取整
Math.floor ():向下取整
Math.max ():最大值
Math.min ():最小值
Math.pow ():幂运算
Math.sqrt ():平方根
Math.log ():自然对数
Math.exp ():e 的指数
Math.round ():四舍五入
Math.random ():随机数Math.abs
Math.abs 方法返回参数值的绝对值。例子:
Math.abs (1) 返回: 1
Math.abs (-1) 返回: 1Math.max( ),Math.min( ):
Math.max 方法返回参数之中最大的那个值,Math.min 返回最小的那个值。如果参数为空,Math.min 返回 Infinity, Math.max 返回 - Infinity。例子:
Math.max(2, -1, 5)
返回: 5
Math.min(2, -1, 5)返回: -1
Math.min()返回:Infinity
Math.max()返回: -Infinity
Math.floor(),Math.ceil()
Math.floor 方法返回小于参数值的最大整数(地板值)。
Math.floor(3.2)
返回: 3
Math.floor(-3.2)返回: -4
Math.ceil 方法返回大于参数值的最小整数(天花板值)。
Math.ceil(3.2)
返回: 4
Math.ceil(-3.2)返回: -3
这两个方法可以结合起来,实现一个总是返回数值的整数部分的函数。function ToInteger(x) {
x = Number(x);
return x < 0 ? Math.ceil(x) : Math.floor(x);
}
上面的方法传入以下参数得到的返回值如下:
ToInteger (3.2) 返回: 3
ToInteger (3.5) 返回: 3
ToInteger (3.8) 返回: 3
ToInteger (-3.2) 返回:-3
ToInteger (-3.5) 返回: -3
ToInteger (-3.8) 返回: -3上面代码中,不管正数或负数,ToInteger 函数总是返回一个数值的整数部分。
Math.round()
Math.round()方法用于四舍五入。例子:
Math.round (0.1) 返回:0
Math.round (0.5) 返回: 1
Math.round (0.6) 返回: 1等同于
Math.floor (x + 0.5)
注意,它对负数的处理(主要是对 0.5 的处理)。Math.round (-1.1) 返回: -1
Math.round (-1.5) 返回: -1
Math.round (-1.6) 返回: -2Math.sqrt()
Math.sqrt 方法返回参数值的平方根。如果参数是一个负值,则返回 NaN。Math.sqrt (4) 返回: 2
Math.sqrt (-4) 返回:NaNMath.random()
Math.random()返回 0 到 1 之间的一个伪随机数,可能等于 0,但是一定小于 1。
Math.random()返回: 0.7151307314634323
- 任意范围内的随机数生成函数如下。
function getRandomArbitrary(min, max) {
return Math.random() * (max - min) + min;
}
getRandomArbitrary (1.5, 6.5) 返回:2.4942810038223864
- 任意范围的随机整数生成函数如下。
function getRandomInt(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
getRandomInt (1, 6) 返回: 5
- 返回随机字符的例子如下:
function random_str(length) {
var ALPHABET = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
ALPHABET += 'abcdefghijklmnopqrstuvwxyz';
ALPHABET += '0123456789-_';
var str = '';
for (var i = 0; i < length; ++i) {
var rand = Math.floor(Math.random() * ALPHABET.length);
str += ALPHABET.substring(rand, rand + 1);
}
return str;
}
random_str (6) 返回:"NdQKOr"
上面代码中,random_str 函数接受一个整数作为参数,返回变量 ALPHABET 内的随机字符所组成的指定长度的字符串。
# Object 对象
**Object 的实例方法:** 所谓的实例方法就是在定义 Object 原型对象 Object.prototype 上的方法。他可以被 Object 实例直接使用。
instanceof 运算符用来验证,一个对象是否为指定的构造函数的实例。
Object ( ) 本身是一个函数,可以当作工具方法使用,将任意值转为对象。这个方法常用于保证某个值一定是对象。如果参数为空,(或者为 undefined 和 null),Object()返回一个空对象。
属性的描述对象。
{
valeu:123,
writable:false,
enumerable:true,
configurable:false,
get:undefined,
set:undefined
}
属性描述对象提供 6 个属性;
value
value 是该属性的属性值,默认为 undefined。writable
writable 是一个布尔值,表示属性值(value)是否可以改变(即是否可以写),默认是 true。enumerable
是一个布尔值,表示该属性是否可遍历,默认为 true。如果设为 false,会使得某些操作(比如 for...in 循环、Object.keys ())跳过该属性。configurable
是一个布尔值,表示可配置性,默认为 true。如果设为 false,将阻止某些操作改写该属性,比如无法删除该属性,也不得改变该属性的属性描述对象(value 属性除外)。
也就是说,configurable 属性控制了属性描述对象的可写性。get
get 是一个函数,表示该属性的取值函数(getter),默认为 undefined。set
set 是一个函数,表示该属性的存值函数(setter),默认为 undefined。
# Promise 对象
什么是 Promise。
Promise 对象是 JavaScript 的异步操作解决方案,为异步操作提供统一接口。它起到代理作用(proxy),充当异步操作与回调函数之间的中介,使得异步操作具备同步操作的接口。Promise 可以让异步操作写起来,就像在写同步操作的流程,而不必一层层地嵌套回调函数。总的来说,Promise 就是解决异步操作的解决方法。首先,Promise 是一个对象,也是一个构造函数。
function f1(resolve, reject) {
// 异步代码...
}
var p1 = new Promise(f1)
上面代码中,Promise 构造函数接受一个回调函数 f1 作为参数,f1 里面是异步操作的代码。然后,返回的 p1 就是一个 Promise 实例。Promise 的设计思想是,所有异步任务都返回一个 Promise 实例。Promise 实例有一个 then 方法,用来指定下一步的回调函数。
var p1 = new Promise(f1);
p1.then(f2);
上面代码中,f1 的异步操作执行完成,就会执行 f2。
Promise 对象的状态
Promise 对象通过自身的状态,来控制异步操作。Promise 实例具有三种状态。
异步操作未完成(pending)
异步操作成功(fulfilled)
异步操作失败(rejected)
上面三种状态里面,fulfilled 和 rejected 合在一起称为 resolved(已定型)。这三种状态的变化途径只有两种。
- 从 “未完成” 到 “成功”
- 从 “未完成” 到 “失败” 所以,异步操作,要嘛就是成功,要嘛就是失败。
如果成功:Promise 实例传回一个值(value),状态为 fulfilled。
如果失败:Promise 实例抛出一个错误(error),状态为 rejected。
Promise 构造函数
JavaScript 提供原生的 Promise 构造函数,用来生成 Promise 实例。
var promise = new Promise(function (resolve, reject) {
// ...
if (/* 异步操作成功 */){
resolve(value);
} else { /* 异步操作失败 */
reject(new Error());
}
});
上面代码中,Promise 构造函数接受一个函数作为参数,该函数的两个参数分别是 resolve 和 reject。它们是两个函数,由 JavaScript 引擎提供,不用自己实现。
resolve 函数的作用是,将 Promise 实例的状态从 “未完成” 变为 “成功”(即从 pending 变为 fulfilled),在异步操作成功时调用,并将异步操作的结果,作为参数传递出去。
reject 函数的作用是,将 Promise 实例的状态从 “未完成” 变为 “失败”(即从 pending 变为 rejected),在异步操作失败时调用,并将异步操作报出的错误,作为参数传递出去。Promise.protoytype.then()
下面的p2中reject为什么要加new关键字?????搞懂以后删除此
Promise 实例的 then 方法,用来添加回调函数。
then 方法可以接受两个回调函数,第一个是异步操作成功时(变为 fulfilled 状态)的回调函数,第二个是异步操作失败(变为 rejected)时的回调函数(该参数可以省略)。一旦状态改变,就调用相应的回调函数。var p1 = new Promise(function (resolve, reject) {
resolve('成功');
});
p1.then(console.log, console.error);
// "成功",如果 p1 返回的是成功,那么 then 调用成功的方法。
var p2 = new Promise(function (resolve, reject) {
reject(new Error('失败')); // ????
});
p2.then(console.log, console.error);
// Error: 失败,如果 p2 返回的是失败,则调用失败的方法。
# this 关键字
this 可以用在构造函数之中,表示实例对象。除此之外,this 还可以用在别的场合。但是不管事什么场合,this 都有一个共同点:他总是返回一个对象。
涵义
简单来说:this 就是属性或方法 “当前” 所在的对象。
var person = {
name: '张三',
describe: function () {
return '姓名:'+ this.name;
}
};
person.describe()
// "姓名:张三"
<input type="text" name="age" size=3 onChange="validate(this, 18, 99);">
function validate(obj, lowval, hival){
if ((obj.value < lowval) || (obj.value > hival))
console.log('Invalid Value!');
}
上面代码中,this.name 表示 name 属性所在的那个对象。由于 this.name 是在 describe 方法中调用,而 describe 方法所在的当前对象是 person,因此 this 指向 person,this.name 就是 person.name。
总结一下,JavaScript 语言之中,一切皆对象,运行环境也是对象,所以函数都是在某个对象之中运行,this 就是函数运行时所在的对象(环境)。这本来并不会让用户糊涂,但是 JavaScript 支持运行环境动态切换,也就是说,this 的指向是动态的,没有办法事先确定到底指向哪个对象,这才是最让初学者感到困惑的地方。实质
this 的设计目的就是在函数体内部,指代函数当前的运行环境。
var f = function () {
console.log(this.x);
}
上面代码中,函数体里面的 this.x 就是指当前运行环境的 x。
使用场合
- 全局环境使用 this,他指的就是顶层对象 window。
- 构造函数,构造函数中的 this,指的是实例对象。
避免多层 this
var o = {
f1: function() {
console.log(this);
var that = this;
var f2 = function() {
console.log(that);
}();
}
}
o.f1()
// Object
// Object
上面代码定义了变量 that,固定指向外层的 this,然后在内层使用 that,就不会发生 this 指向的改变。事实上,使用一个变量固定 this 的值,然后内层函数调用这个变量,是非常常见的做法,请务必掌握。内层的 this 不能指向外层的对象。而是指向定层的对象。解决方法就是上面的例子。使用一个变量接受 this,把当前的 this 赋值给声明的这个变量。就可以在下层运用这个变量来获取外层的对象了。
绑定 this 的方法
javascript 提供了 call、apply、bind 这三种方法,来切换固定 this 的指向。
- call()
函数实例的 call 方法,可以指定函数内部 this 的指向(即函数执行时所在的作用域),然后在所指定的作用域中,调用该函数。call 方法的参数,应该是一个对象。如果参数为空、null 和 undefined,则默认传入全局对象。
var n = 123;
var obj = { n: 456 };
function a() {
console.log(this.n);
}
a.call() // 123
a.call(null) // 123
a.call(undefined) // 123
a.call(window) // 123
a.call(obj) // 456
上面代码中,a 函数中的 this 关键字,如果指向全局对象,返回结果为 123。如果使用 call 方法将 this 关键字指向 obj 对象,返回结果为 456。可以看到,如果 call 方法没有参数,或者参数为 null 或 undefined,则等同于指向全局对象。
如果 call 方法的参数是一个原始值,那么这个原始值会自动转成对应的包装对象,然后传入 call 方法。
var f = function () {
return this;
};
f.call(5)
// Number {[[PrimitiveValue]]: 5}
上面代码中,call 的参数为 5,不是对象,会被自动转成包装对象(Number 的实例),绑定 f 内部的 this。
call 的第一个参数就是 this 所要指向的那个对象,后面的参数则是函数调用时所需的参数。function add(a, b) {
return a + b;
}
add.call(this, 1, 2) // 3
上面代码中,call 方法指定函数 add 内部的 this 绑定当前环境(对象),并且参数为 1 和 2,因此函数 add 运行后得到 3。
总的来说:call 方法就是让 this 绑定到当前的方法中去。
apply()
apply 方法的第一个参数也是 this 所要指向的那个对象,如果设为 null 或 undefined,则等同于指定全局对象。第二个参数则是一个数组,该数组的所有成员依次作为参数,传入原函数。原函数的参数,在 call 方法中必须一个个添加,但是在 apply 方法中,必须以数组形式添加。
例:找出数组中最大的元素
JavaScript 不提供找出数组最大元素的函数。结合使用 apply 方法和 Math.max 方法,就可以返回数组的最大元素。var a = [10, 2, 4, 15, 9];
Math.max.apply(null, a) // 15
bind()
bind () 方法用于将函数体内的 this 绑定到某个对象,然后返回一个新函数。
var d = new Date();
d.getTime()
// 1481869925657
var print = d.getTime;
print()
// Uncaught TypeError: this is not a Date object.
上面代码中,我们将 d.getTime () 方法赋给变量 print,然后调用 print () 就报错了。这是因为 getTime () 方法内部的 this,绑定 Date 对象的实例,赋给变量 print 以后,内部的 this 已经不指向 Date 对象的实例了。
bind () 方法可以解决这个问题。
var print = d.getTime.bind(d);
print()
// 1481869925657
上面代码中,bind () 方法将 getTime () 方法内部的 this 绑定到 d 对象,这时就可以安全地将这个方法赋值给其他变量了。
bind 方法的参数就是所要绑定 this 的对象,下面是一个更清晰的例子。
var counter = {
count: 0,
inc: function () {
this.count++;
}
};
var func = counter.inc.bind(counter);
func();
counter.count // 1
上面代码中,counter.inc () 方法被赋值给变量 func。这时必须用 bind () 方法将 inc () 内部的 this,绑定到 counter,否则就会出错。
# 定时器
JavaScript 提供定时执行代码的功能,叫做定时器(timer),主要由 setTimeout () 和 setInterval () 这两个函数来完成。它们向任务队列添加定时任务。
setTimeout()
setTimeout 函数用来指定某个函数或某段代码,在多少毫秒之后执行。它返回一个整数,表示定时器的编号,以后可以用来取消这个定时器。var timerId = setTimeout(func|code, delay);
上面代码中,setTimeout 函数接受两个参数,第一个参数 func|code 是将要推迟执行的函数名或者一段代码,第二个参数 delay 是推迟执行的毫秒数。
setInterval()
setInterval 函数的用法与 setTimeout 完全一致,区别仅仅在于 setInterval 指定某个任务每隔一段时间就执行一次,也就是无限次的定时执行。
var i = 1
var timer = setInterval(function() {
console.log(2);
}, 1000)
上面代码中,每隔 1000 毫秒就输出一个 2,会无限运行下去,直到关闭当前窗口。
clearTimeout (),clearInterval () 关闭定时器
setTimeout 和 setInterval 函数,都返回一个整数值,表示计数器编号。将该整数传入 clearTimeout 和 clearInterval 函数,就可以取消对应的定时器。
var id1 = setTimeout(f, 1000);
var id2 = setInterval(f, 1000);
clearTimeout(id1);
clearInterval(id2);
上面代码中,回调函数 f 不会再执行了,因为两个定时器都被取消了。
debounce 函数。(防止抖动)
防止抖动,意思就是在多少时间内,发生重复的事情可以不触发。比如用户点击键盘,如果用户一直点击,就会造成事件的重复发生。可以让他多少时间,(就是多少秒之后再继续执行一次)
# 函数
概述
- javascript 有三种方法声明函数。
function 命令声明的代码区块,就是一个函数。function 命令后面是函数名,函数名后面是一对圆括号,里面是传入函数的参数。函数体放在大括号里面。
function print(s){
console.log(s);
}
调用函数:print()。函数名加上();
变量赋值的写法声明
var print = funtion(s){
console.log(s);
}
采用函数表达式声明函数时,function 命令后面不带有函数名。如果加上函数名,该函数名只在函数体内部有效,在函数体外部无效。
注:这种表达式声明的函数必须在语句的结尾加上分号,表示语句结束。而上面一种不需要在结尾加分号。构造函数
var add = function(
‘x’,
'y',
'return x+y'
);
因为这种声明方法不直观,所以用得很少。
如果一个函数被多次声明,后面的声明会覆盖前面的声明。
调用函数时,要使用圆括号。里面可以放置参数。函数的属性和方法
name 属性:返回函数的名字。
如果是通过变量赋值定义的函数,那么,name 属性返回的是变量名。注:只有在变量的值是一个匿名函数的时候才会如此。在函数中,参数
.name
。就能在控制台打印出当前函数的 name。匿名函数:例:
var f2 = function (){
f2.name // name = f2
}
具名函数:例:注意:下面这个函数真正的函数名还是 f2,Myname 名字只能在函数内部可以用。
var f2 = function Myname(){
f2.name // name=Myname
}
length 属性
函数的 length 属性返回函数预期传入的参数个数,即函数定义之中的参数个数。不管调用时候传入了多少个参数,length 属性值返回创建时小括号中的个数。
toString()
toString()方法,返回一个字符串。
例:
var a = 123:此时的 a 是 number 数字类型。
toString(a);返回一个 “123”函数的作用域
在函数内部声明的变量叫局部变量,在函数外部声明的变量叫全局变量。函数的作用域是在 函数定义时的作用域,而不是在调用时的作用域。
参数
函数运行的时候,有时候需要提供外部的数据,不同的外部数据会得到不同的结果。这种外部数据就叫做参数。
例:
function square (x){
return x*x;
}
square(2);在调用函数时,传入一个 2 作为参数,返回的结果就是 2*2=4
square(3);返回的结果是 9.arguments
var f = function(a,b){
arguments[ 0 ] = 3;
arguments[ 1 ] = 2;
return a + a;
}
f( 1,1 )
上面的代码中,函数 f()调用时传入的参数,在函数内部被修改成 3 和 2
闭包
定义在一个函数内部的函数。特点:就是它可以记住诞生的环境。在本质上,闭包就是将函数别不核函数外部连接起来的一座桥梁。
# 事件的冒泡
事件的冒泡就是点击一个最上面的(z-index 最大)的 div。触发事件以后,在他之后的 div(z-index 第二个)的事件也会触发。还有最大的一个 div(z-index 最小的)事件也会触发
冒泡:事件的向上传导
例:一个 span 标签上的 onclick,触发一个 p 标签上的 onclick,触发一个 div 上的 onclick。。。。。。
切触发的是相同的时间。如,鼠标点击事件,就只冒泡点击事件。如鼠标移动事件就只触发移动事件。
取消冒泡:
属性.cancelBubble = true;
# 数组
数组时按次序排列的一组值。每个值的位置都有编号。编号从 0 开始。整个数组用方括号表示 :[ ]。
var arr = [ 'a', 'b,' 'c' ]; |
这就是一个简单数组,数组的 a 的下标是 0。第一位是 0,第二位是 1,第三位是 2. 以此类推。所以数组的下标总是比数组的长度小一。数组也是可以先定义、再赋值的。
var arr = [ ]; | |
arr [ 0 ] = 'a'; | |
arr [ 1 ] = 'b'; | |
arr [ 2 ] = 'c'; |
任何类型的数据,都可以放入数组中。比如。函数、对象、方法、数值、字符串、数组里面也能嵌套数组。这时候叫多维数组......
数组的长度
使用 length 属性可以返回数组的长度。清空数组可以将 length 属性设置为 0。如果人为设置 length 大于当前元素个数,则数组的成员数量会增加到这个值,新增的位置都是空位。使用 undefined 站位。表示空,未定义。
数组的遍历
数组的遍历可以用 for 循环、while 循环、不建议用 for...in 循环。常用的是 forEach 循环。
//for 循环
var a = [ 1, 2, 3 ];
for ( var i = 0; i < a.length; i ++) {
console.log( a[ i ] );
// 打印出 a 数组的每一项
}
//while 循环:
var i = 0;
while (i < a.length) {
console.log(a[i]);
i++;
}
//forEeach 循环:
var colors = ['red', 'green', 'blue'];
colors.forEach(function (color) {
console.log(color);
})
// 打印出 colors 的每一项。
delete 删除
如果使用 delete 命令删除数组中的某一项。
var a = [ 1, 2, 3 ];
delete a[ 1 ]; // 删除 a 数组的第二个数。
此时:a [1] 打印出来的值 = undefined。
此时:a.length=3
数组的某个位置是空位、与某个位置是 undefined 是不一样的,如果是空位,但是对 length 属性没有影响。所以用 length 遍历时要小心。如果是空位,使用数组的 forEach 方法、for...in 结构、以及 Object.keys 方法进行遍历,空位都会被跳过。
var q = ["1","2","3"]
q.forEach(function(i,x){
console.log(i+"."+x)
})
i 代表每一项的值,x 代表每一项的下标。
# 高级数组
Array.isArray()方法
返回一个布尔值。表示参数是否为数组。他可以弥补 typeof 运算符的不足。说白了,就是用来判断一个参数,或者一个变量是不是数组。
valueOf 方法
valueOf 方法是一个所有对象都拥有的方法,表示对该对象求值。不同对象的 valueOf 方法不尽一致,数组的 valueOf 方法返回数组的本身。var arr = [ 1, 2, 3 ];
arr.valueOf() // 控制台输出 [1, 2, 3]
返回数组的本身。
toString 方法
toString 方法也是对象通用的方法,数组的 toString 方法返回数组的字符串形势。
例:var arr = [ 1, 2, 3 ]
arr.toString() // 控制台输出 “1,2,3”;
就是把数组里面的值都变成一串长的字符串。即使是数组里面有嵌套也是一样的。
数组中的方法
push()
push 方法用于在数组的末端添加一个或多个元素,并返回添加新元素后的数组长度。注意,该方法会改变原数组。
例var arr = [ ];
arr.push( 1 )
arr.push( 'a' )
arr.push( true,{} )
此时 arr 数组里面的值为。【1,‘a’,true,{ }】上面的代码使用 push 方法,往数组中添加的四个成员。
pop()
pop 方法用于删除数组的最后一个元素,并返回该元素。注意,该方法会改变原数组。
var arr = ['a', 'b', 'c'];
arr.pop( ) // 'c'
arr // ['a', 'b']
此时在控制台打印输出 arr 的值为 ['a', 'b'], 因为最后一个元素被删除了。注意,对空数字使用 pop()不会报错,而是返回一个 undefined。
shift()
shift ( ) 方法用于删除数组的第一个元素,并返回该元素。注意,该方法会改变原数组。
var a = ['a', 'b', 'c'];
a.shift() // 删除 a 中的 'a'
a // 此时 a 数组只剩下 ['b', 'c']
只能数组名.shift。然后删除该数组中的第一项。
shift()可以遍历清空一个数组。前提是数组的元素不能是 0 或者任何布尔值等于 false 的元素,所以,用这个遍历数组不是很可靠。unshift()
unshift ( ) 方法用于在数组的第一个位置添加元素,并返回添加新元素后的数组长度。注意,该方法会改变原数组。unshift()方法可以接受多个参数,这些参数都会加到目标数组的头部。也就是前面。
join()
join ( ) 方法以指定参数作为分隔符,将所有数组成员连接为一个字符串返回。如果不提供参数,默认用逗号分隔。
var a = [1, 2, 3, 4];
a.join(' ') // '1 2 3 4'
a.join(' | ') // "1 | 2 | 3 | 4"
a.join() // "1,2,3,4"
传入的参数是什么,就会在返回的数组中间加什么。用双引号引起来。如果元素是 undefined 和 null。或者空位,会被转成空字符串。“ ” 就是一个空格的样子。
concat()
concat 方法用于多个数组的合并。它将新数组的成员,添加到原数组成员的后部,然后返回一个新数组,原数组不变。
['hello'].concat(['world'])
// ["hello", "world"]
['hello'].concat(['world'], ['!'])
// ["hello", "world", "!"]
[].concat({a: 1}, {b: 2})
// [{ a: 1 }, { b: 2 }]
[2].concat({a: 1})
// [2, {a: 1}]
reverse()
reverse 方法用于颠倒排列数组元素,返回改变后的数组。注意,该方法将改变原数组
var a = ['a', 'b', 'c'];
a.reverse( ) // ["c", "b", "a"]
a // ["c", "b", "a"]
就是第一个在最后一个,最后一个在第一个。颠倒过来了。
slice()
sliec()方法用于提取目标数组的一部分,返回一个新数组,原数组不变。它的第一个参数为起始位置(从 0 开始,会包括在返回的新数组之中),第二个参数为终止位置(但该位置的元素本身不包括在内)
如果省略第二个参数,则一直返回到原数组的最后一个成员。var a = ['a', 'b', 'c'];
a.slice(0) // ["a", "b", "c"]
a.slice(1) // ["b", "c"]
a.slice(1, 2) // ["b"]
a.slice(2, 6) // ["c"]
a.slice() // ["a", "b", "c"]。
截取一个数组中的某元素到某元素的那一段,组成一个新的数组。新的数组包含第一个元素,不包含最后一个元素。且原数组不会改变。如果没有参数。如上面的最后一个例子:则就是拷贝一个与原数组相同的新数组出来。如果给的参数是负数。则表示从后面开始计算。
var a = ['a', 'b', 'c'];
a.slice(-2) // ["b", "c"]
a.slice(-2, -1) // ["b"]
上面代码中,-2 表示倒数计算的第二个位置,-1 表示倒数计算的第一个位置。如果第一个参数大于等于数组长度,或者第二个参数小于第一个参数,则返回空数组
splice()
splice 的第一个参数是删除的起始位置(从 0 开始)第二个参数是被删除的元素个数。如果后面还有更多参数,则表示这些就是要被插入数组的新元素。注意,该方法会改变原数组。
var a = ['a', 'b', 'c', 'd', 'e', 'f'];
a.splice(4, 2) // ["e", "f"]
a // ["a", "b", "c", "d"]
就是删除一个数组里面的元素。第一个参数是下标的位置,第二个参数是删除的个数。从下标是第几个开始删除。
var a = ['a', 'b', 'c', 'd', 'e', 'f'];
a.splice(4, 2, 1, 2) // ["e", "f"]
a // ["a", "b", "c", "d", 1, 2]
删除以后又加进来两个新元素。如果起始位置是负数,就表示从倒数位置开始删除。
var a = ['a', 'b', 'c', 'd', 'e', 'f'];
a.splice(-4, 2) // ["c", "d"]
倒数第四个开始删除,删除开始以后的前两个元素。所以删除的是【“c”,“d”】
如果是单纯的插入元素,也可以使用 splice()将第二个参数设置为 0,就可以了。这时候,第一个参数表示插入的位置,第三个或者第三个以后的参数就是需要插入的新元素。如果只提供一个参数。就等同于将原数组才拆分为两个数组。从第一个参数的位置起开始拆分。例:
var a = [1, 2, 3, 4];
a.splice(2) // [3, 4]
a // [1, 2]
sort()
sort 方法对数组成员进行排序,默认是按照字典顺序排序。排序后,原数组将被改变。例:
['d', 'c', 'b', 'a'].sort()
// ['a', 'b', 'c', 'd']
[4, 3, 2, 1].sort()
// [1, 2, 3, 4]
[11, 101].sort()
// [101, 11]
[10111, 1101, 111].sort()
// [10111, 1101, 111]
上面代码的最后两个例子,需要特殊注意。sort () 方法不是按照大小排序,而是按照字典顺序。也就是说,数值会被先转成字符串,再按照字典顺序进行比较,所以 101 排在 11 的前面。
map()
map 方法将数组的所有成员依次传入参数函数,然后把每一次的执行结果组成一个新数组返回。
var numbers = [1, 2, 3];
numbers.map(function (n) {
return n + 1;
});
// [2, 3, 4]
numbers
// [1, 2, 3]
上面代码中,numbers 数组的所有成员依次执行参数函数,运行结果组成一个新数组返回,原数组没有变化。
map 方法接受一个函数作为参数。该函数调用时,map 方法向它传入三个参数:当前成员、当前位置和数组本身。
[1, 2, 3].map(function(elem, index, arr) {
return elem * index;
});
// [0, 2, 6]
上面代码中,map 方法的回调函数有三个参数,elem 为当前成员的值,index 为当前成员的位置,arr 为原数组([1, 2, 3])。
foreach()
forEach 的用法与 map 方法一致,参数是一个函数,该函数同样接受三个参数:当前值、当前位置、整个数组。
function log(element, index, array) {
console.log('[' + index + '] = ' + element);
}
[2, 5, 9].forEach(log);
// [0] = 2
// [1] = 5
// [2] = 9
上面代码中,forEach 遍历数组不是为了得到返回值,而是为了在屏幕输出内容,所以不必使用 map 方法。注意:forEach()参数是一个方法,方法中的第一个参数是当前数组中的值,第一个值就是第一个值打印出来,第二个参数是当前数组的当前值的下标。第三个参数是整个数组。且记住,大写 Each 的首字母。
forEach 方法也可以接受第二个参数,绑定参数函数的 this 变量。
var out = [];
[1, 2, 3].forEach(function(elem) {
this.push(elem * elem);
}, out );
out // [1, 4, 9]
上面代码中,空数组 out 是 forEach 方法的第二个参数,结果,回调函数内部的 this 关键字就指向 out。
注意,forEach 方法无法中断执行,总是会将所有成员遍历完,forEach 方法也会跳过数组的空位。
filter()
filter 方法用于过滤数组成员,满足条件的成员组成一个新数组返回。它的参数是一个函数,所有数组成员依次执行该函数,返回结果为 true 的成员组成一个新数组返回。该方法不会改变原数组。
[1, 2, 3, 4, 5].filter(function (elem) {
return (elem > 3);
})
// [4, 5]
上面代码将大于 3 的数组成员,作为一个新数组返回。
var arr = [0, 1, 'a', false];
arr.filter(Boolean)
// [1, "a"]
上面代码中,filter 方法返回数组 arr 里面所有布尔值为 true 的成员。filter 方法的参数函数可以接受三个参数:当前成员,当前位置和整个数组。
[1, 2, 3, 4, 5].filter(function (elem, index, arr) {
return index % 2 === 0;
});
// [1, 3, 5]
上面代码返回偶数位置的成员组成的新数组。
filter 方法还可以接受第二个参数,用来绑定参数函数内部的 this 变量。
var obj = { MAX: 3 };
var myFilter = function (item) {
if (item > this.MAX) return true;
};
var arr = [2, 8, 3, 4, 1, 3, 2, 9];
arr.filter(myFilter, obj) // [8, 4, 9]
上面代码中,过滤器 myFilter 内部有 this 变量,它可以被 filter 方法的第二个参数 obj 绑定,返回大于 3 的成员。
some(),every()
他们和 forEach 一样都接受一个函数作为参数。分别是当前成员,当前成员的下标。整个数组。不同是,some(),every()返回一个布尔值。some 方法是只要一个成员的返回值是 true,则整个 some 方法的返回值就是 true,否则返回 false。
var arr = [1, 2, 3, 4, 5];
arr.some(function (elem, index, arr) {
return elem >= 3;
});
// true
some 方法是只要一个成员的返回值是 true,则整个 some 方法的返回值就是 true,否则返回 false。
var arr = [1, 2, 3, 4, 5];
arr.every(function (elem, index, arr) {
return elem >= 3;
});
// false
indexOf(),lastIndexOf()
indexOf 方法返回给定元素在数组中第一次出现的位置,如果没有出现则返回 - 1。
var a = ['a', 'b', 'c'];
a.indexOf('b') // 1
a.indexOf('y') // -1
indexOf 方法还可以接受第二个参数,表示搜索的开始位置。
['a', 'b', 'c'].indexOf('a', 1) // -1
上面代码从 1 号位置开始搜索字符 a,结果为 - 1,表示没有搜索到。lastIndexOf 方法返回给定元素在数组中最后一次出现的位置,如果没有出现则返回 - 1。
var a = [2, 5, 9, 2];
a.lastIndexOf(2) // 3
a.lastIndexOf(7) // -1
注意,这两个方法不能用来搜索 NaN 的位置,即它们无法确定数组成员是否包含 NaN。
# 异步操作的概述
回调函数。
下面是两个函数 f1 和 f2,编程的意图是 f2 必须等到 f1 执行完成,才能执行。
function f1() {
// ...
}
function f2() {
// ...
}
f1();
f2();
上面代码的问题在于,如果 f1 是异步操作,f2 会立即执行,不会等到 f1 结束再执行。这时,可以考虑改写 f1,把 f2 写成 f1 的回调函数。
function f1(callback) {
// ...
callback();
}
function f2() {
// ...
}
f1(f2);
回调函数的优点是简单、容易理解和实现,缺点是不利于代码的阅读和维护,各个部分之间高度耦合(coupling),使得程序结构混乱、流程难以追踪(尤其是多个回调函数嵌套的情况),而且每个任务只能指定一个回调函数。
# 元素的其他属性
clientWidth(获取元素的宽度)
clientHeight(获取元素的高度)
这两个属性可以获取元素的可见宽度。获取的值不带 px,可以直接计算,包含 padding。属性只读,不能修改。offsetWidth 和 offsetHeigth
获取元素的整个高度,包括 boder,padding。内容。offsetLeft
当前元素相对于其定位父元素的水平偏移量offsetTop
当前元素相对于其定位父元素的垂直偏移量scrollLeft
可以获取水平滚动条滚动的距离
scrollTop
可以获取垂直滚动条滚动的距离
scrollHeight元素的滚动高度
事件对象,enent 获取鼠标当前位置
# 字符串的方法
charAt()
获取输入字符串指定位置的字符。下标从 0 开始。
charCodeAt()
获取指定位置的字符编码。
indexof()
该方法可以检索一个字符串中是否含有指定的内容。返回,如果字符串中有含有该内容的,则会返回其第一次出现的索引位置。如果没有找到指定的内容,则返回 - 1,可以指定开始查找的位置。
result = str.indexOf("h",1)
lastIndexOf()
方法和 indexOf 基本一样,一个从前 一个从后。
slice()
可以从字符串中截取指定的内容,不会影响原来的字符串。而是将截取的字符串返回。参数,第一个,开始位置的索引(包括开始位置)第二个,结束位置的索引(不包括结束位置)第二个参数可以省略,则从第一个开始截取到最后的字符串。
str= “abcdefkjak”
result = str.slice(1,2)
result = bc。
substr()
从第几个开始截取,截取后面的几个字符。
# 正则表达式
正则表达式(regular expression)是一种表达文本模式(即字符串结构)的方法,有点像字符串的模板,常常用来按照 “给定模式” 匹配文本。比如,正则表达式给出一个 Email 地址的模式,然后用它来确定一个字符串是否为 Email 地址。
新建一个正则表达式:
var regex = /xyz/;
以斜杠表示开始和结束。
以斜杠表示开始和结束。
test()
正则实例 test()方法返回一个布尔值,表示当前模式是否能匹配参数字符串。如果能匹配,返回一个 true。index:
模式匹配成功的开始位置。下标从 0 开始。input:
整个原字符串。(3、4) 例:var r = /a(b+)a/;
var arr = r.exec('_abbba_aba_');
arr // ["abbba", "bbb"]
arr.index // 1
arr.input // "_abbba_aba_"
上面代码中的 index 属性等于 1,是因为从原字符串的第二个位置开始匹配成功。
String.prototype.search( )
字符串对象的 search 方法,返回第一个满足条件的匹配结果在整个字符串中的位置。如果没有任何匹配,则返回 - 1。
位置字符
^:表示字符串的开始位置。
$:表示字符串的结束位置。
例://test 必须出现在开始位置
/^test/.test('test123') // true
//test 必须出现在结束位置
/test$/.test('new test') // true
// 从开始位置到结束位置只有 test
/^test$/.test('test') // true
/^test$/.test('test test') // false
选择符( | )
竖线符号(|)在正则表达式中表示 “或关系”(OR),即 cat|dog 表示匹配 cat 或 dog。
/11|22/.test('911') // true
上面代码中,正则表达式指定必须匹配 11 或 22。多个选择符可以联合使用。
// 匹配 fred、barney、betty 之中的一个
/fred|barney|betty/
连字符
某些情况下,对于连续序列的字符,连字符(-)用来提供简写形式,表示字符的连续范围。比如,[abc] 可以写成 [a-c],[0123456789] 可以写成 [0-9],同理 [A-Z] 表示 26 个大写字母。
/a-z/.test('b') // false
/[a-z]/.test('b') // true
上面代码中,当连字号(dash)不出现在方括号之中,就不具备简写的作用,只代表字面的含义,所以不匹配字符 b。只有当连字号用在方括号之中,才表示连续的字符序列。
以下都是合法的字符类简写形式。
[0-9.,]
[0-9a-fA-F]
[a-zA-Z0-9-]
[1-31]
上面代码中最后一个字符类 [1-31],不代表 1 到 31,只代表 1 到 3。
连字符还可以用来指定 Unicode 字符的范围。
预定义模式
预定义模式指的是某些常见模式的简写方式。\d
匹配 0-9 之间的任一数字,相当于[0-9]
。\D
匹配所有 0-9 以外的字符,相当于 [^0-9]。\w
匹配任意的字母、数字和下划线,相当于[A-Za-z0-9_]
。\W
除所有字母、数字和下划线以外的字符,相当于[^A-Za-z0-9]
。\s
匹配空格(包括换行符、制表符、空格符等),相等于[ \t\r\n\v\f]
。\S
匹配非空格的字符,相当于[^ \t\r\n\v\f]
。\b
匹配词的边界。\B
匹配非词边界,即在词的内部。
下面是一些例子。// \s 的例子
/\s\w*/.exec('hello world') // [" world"]
// \b 的例子
/\bworld/.test('hello world') // true
/\bworld/.test('hello-world') // true
/\bworld/.test('helloworld') // false
// \B 的例子
/\Bworld/.test('hello-world') // false
/\Bworld/.test('helloworld') // true
上面代码中,\s 表示空格,所以匹配结果会包括空格。\b 表示词的边界,所以 world 的词首必须独立(词尾是否独立未指定),才会匹配。同理,\B 表示非词的边界,只有 world 的词首不独立,才会匹配。
重复类型
模式的精确匹配次数,使用大括号({})表示。{n} 表示恰好重复 n 次,{n,} 表示至少重复 n 次,{n,m} 表示重复不少于 n 次,不多于 m 次。/lo{2}k/.test('look') // true
/lo{2,5}k/.test('looook') // true
上面代码中,第一个模式指定 o 连续出现 2 次,第二个模式指定 o 连续出现 2 次到 5 次之间。
量词符
?:问号表示某个模式出现 0 次或者 1 次,等同于 {0,1}
*:星好表示某个模式出现 0 次或者多次,等同于 {0,}
+:加号表示某个模式出现 1 次或者多次,等同于量词:
reg = /(ab){3}/ 表示 ab 出现 3 次
reg = /b {3}/ 表示 b 出现 3 次
reg = /ab {1,3} c/ 表示 a 和 c 中间的 b 出现至少一次或 3 次。
reg = /ab {3,} c/ 表示 a 和 c 中间的 b 出现 3 次,或 3 次以上。
# js 后半部部分
学习地址