【JavaScript】 一万字 JavaScript 笔记(详细讲解 + 代码演示 + 图解)
文章目录
- 变量
- 变量声明的提升
- 数据类型
- Typeof运算符
- 数据类型转换
- 表达式与运算符
- 隐式类型转换
- toFixed(a)方法保留a位小数
- 关系运算符
- 短路求值
- 流程控制语句
- 数组
- 函数
- DOM
- BOM
- 面向对象
变量
- 一个变量只定义但没有赋初值,默认值是 undefined
- 定义变量时必须写var(不用var定义,而直接将值赋给它,随不引发报错,但会产生作用域问题)
变量声明的提升
你可以提前使用一个稍后才声明的变量,而不会引发异常
再执行所有代码前,js有预解析阶段,会预读所有变量的定义
注意:变量声明提升只提升定义不提升值
console.log(a); // 先使用变量
var a = 12; // 后定义变量
数据类型
基本数据类型
Number
- 所有数字部分大小、不分整浮、不分正负,都是数字类型
- 较大或较小数(绝对值较小)可以写成科学计数法
3e8
就是3^8
- 二进制数值以
0b
开头,八进制以0
开头,十六进制以0x
开头 NaN
,not a number,即“不是一个数”,但它是一个数字类型的值(数学运算中,若结果不能得到数字,结果往往都是NaN,NaN == NaN结果为false)- Infinity无穷大或无穷小
String
- 字符串常用方法
方法
功能
charAt()
得到指定位置字符(越界为空串)
substring()
提取子串
substr()
提取字串
slice()
提取子串
toUpperCase()
将字符串变为大写
toLowerCase()
将字符串变为小写
indexOf()
检索字符串(模式匹配)
- substring(a, b) 从a开始到b结束的子串,不包括b处;如果省略第二个参数,返回的子串会一直到字符串的结尾,若a > b,会自动调整为小数在前
- substr(a, b) 从a开始长度为b的子串;如果省略第二个参数,返回的子串会一直到字符串的结尾;a可以是负数,表示倒数位置
- slice(a, b) 从a开始到b结束的子串,不包括b处;两个参数都可以是负数;a必须小于b,否则没有结果(空串)
Boolean
Undefined
- undefined既是值又是一种类型,这种类型只有它自己一个值
Null
- 当我们需要将对象销毁、数组销毁或者删除事件监听时、通常将他们设置为null
复杂数据类型
- Object
- Array
- Function
- RegExp
- Date
- Map
- Set
- ……
Typeof运算符
可以用来检测值或变量的类型
typeof 5; // number
typeof 'niubi'; // string
类型名
typeof 检测结果
值举例
数字类型
number
5
字符串类型
string
‘niubi’
布尔类型
boolean
true
undefined
undefined
undefined
null类型
object
null
数据类型转换
使用**Number()**函数
// 字符串 --> 数字
Number('123'); // 123
Number('123.4'); // 123.4
Number('123年'); // NaN
Number('2e3'); // 2000
Number(''); // 0
Number('1 + 1'); // NaN// 布尔值 --> 数字
Number(true); // 1
Number(false); // 0// undefined 和 null --> 数字
Number(undefined); // NaN
Number(null); // 0
**parseInt()**函数将字符串转为整数
将自动截掉第一个非数字字符之后的所有字符
parseInt('3.14'); // 3
parseInt('3.14是圆周率'); // 3
parseInt('圆周率是3.14'); // NaN
parseInt('3.99'); // 3
**parseFloat()**函数将字符串转为浮点数
自动截掉第一个非数字字符、非小数点之后的所有字符
parseFloat('3.14'); // 3.14
parseFloat('3.14是圆周率'); // 3.14
parseFloat('圆周率是3.14'); // NaN
parseFloat('3.99'); // 3.99
// 会自动将true和false转为字符串,结果为NaN
**String()**函数
变成“长得相同”的字符串。科学计数法和非10进制数字会转为10进制的值
String(123); // '123'
String(123.4); // '123.4'
String(2e3); // '2000'
String(NaN); // 'NaN'
String(Infinity); // 'Infinity'
String(0xf); // '15'String(true); // 'true'
String(false); // 'false'String(undefined); // 'undefined'
String(null); // 'null'
**Boolean()**函数
// 数字 --> 布尔值 0和NaN转为false,其他转为true
Boolean(123); // true
Boolean(0); // false
Boolean(NaN); // false
Boolean(Infinity); // true
Boolean(-Infinity); // true// 布尔值 --> 布尔值 空串转为false,其他转为true;
Boolean(''); // false
Boolean('abc'); // true
Boolean('false'); // true// undefined 和 null --> 布尔值 转为false
Boolean(undefined); // false
Boolean(null); // false
**prompt()**函数函数弹出输入框
var num = prompt('请输入第一个数字'); // 返回值为string
表达式与运算符
隐式类型转换
如果参与数学运算的某操作数不是数字型,那么JavaScript会自动将此操作数转换位数字型
隐式转换的本质是内部调用Number()函数
3 * '4' // 12
true + true // 2
false + 2 // 2
3 * '2天' // NaN
toFixed(a)方法保留a位小数
Math.pow(2, 3) // 2^3
Math.sqrt(81) // 9
Math.ceil() // 向上取整
Math.floor() // 向下取整
关系运算符
=== // 全等于
!== // 不全等于
// 两个等号 == 运算符不比较值的类型,它会进行隐式转换后比较值是否相等1 == true // true
1===true // false0 == false // true
0 === false // false0 == undefined // false
0 === undefined // falseundefined == null // true
undefined === null // false
**isNaN()**函数判断变量值是否为NaN
但isNaN()也不好用,它的机理是:只要该变量传入Number()的执行结果是NaN,则isNaN()函数都会得到true
短路求值
a && b a真,值为b;a假,值为a
a||b a真,值为a,a假,值为b
逻辑运算优先级:非 --> 与 --> 或
综合运算运算顺序:非 --> 数学运算 --> 关系运算 --> 逻辑运算
流程控制语句
随机数函数Math.random()
得到[a, b]区间的整数,公式为 parseInt(Math.random() * (b - a + 1)) + a;
数组
var arr = ['A', 'B', 'C', 'D'];
var arr = new Array('A', 'B', 'C', 'D');
var arr = new Array(4); 长度为4的数组,每一项都是undefined
下标访问越界时返回undefined
var arr = [2, 6, 7, 3]; arr[6] = 4; console.log(arr); 此时下标越界,不会报错,而是会将数组扩展,下标6处为4,中间为empty
Array.isArray()方法可以用来检测数组
函数
函数定义
// 常规
function fun() {// 函数体语句
}// 匿名函数
var fun = function () {// 函数体语句
}
函数声明的提升
fun();
function fun() { // 在预解析阶段会被提升alert("函数被执行");
}// 如果函数时用函数表达式的写法定义的,则没有提升特性
fun(); // 引发错误
var fun = function () {alert("函数被执行");
}
函数优先提升
// 函数优先提升
// 函数表达式后提升; 变量声明提升,无法覆盖提升的函数
fun(); // 弹出Bvar fun = function () {alert('A');
}function fun() {alert('B');
}fun(); // 弹出A
实参与形参个数不同
- 实参个数多于形参,没有形参接收它
- 实参个数少于形参,没有接收到实参的形参值为
undefined
arguments 类数组对象
- 函数内arguments表示它接收到的实参列表,它是一个类数组对象
- 类数组对象:所有属性均从0开始的自然数序列,并且有length属性,和数组类似可以用方括号书写下标访问对象的某个属性值,但不能调用数组的方法
var声明与省略
在函数外,用var声明的变量为全局变量,不用var声明的变量为全局变量
在函数中,用var声明的变量为局部变量,不用var声明的变量为全局变量
同为全局变量,同为window对象的其中一个属性,用var声明的变量不可以删除,不用var声明的变量可以删除!
返回值
function sum(a, b) {return a + b;
}
var result = sum(3, 5); // 返回值可被变量接收
若函数没有返回值,则对它打印的结果是undefined
sort(a, b)方法
这个函数中的a、b分别表示数组中靠前和靠后的项,如果需要将它们交换位置,则返回任意正数;否则就返回负数
var arr = [33, 22, 11, 55];
arr.sort(function (a, b) {if (a > b) {return 1;}return -1;
});
变量赋值
举例
当var a = b变量传值时
当用 == 比较时
基本类型值
数字型、字符串型、布尔型、undefined型
内存中产生新的副本
比较值是否相等
引用类型值
对象、数组
内存中不产生新的副本,而是让新变量指向同一个对象
比较内存地址是否相同,即比较是否是同一个对象
数组深度克隆
var arr1 = [1, 2, 3, [4, 5]];
function deepClone(arr) {var result = [];for (var i = 0; i < arr.length; i++) {if (Array.isArray(arr[i])) {result.push(deepClone(arr[i]));} else {result.push(arr[i]);}}return result;
}
局部函数
定义在一个函数内部的函数是局部函数
只能在函数内部调用
function fun() {function inner() {console.log('你好');}inner(); // 调用inner函数
}
fun();
作用域链
在函数嵌套中,变量会从内到外逐层寻找它的定义
var a = 10;
var b = 20;
function fun() {var c = 30;function inner() {var a = 40;var d = 50;console.log(a, b, c, d); // 使用变量时,js会从当前层开始,逐层向外寻找定义}inner();
}
fun();
闭包
闭包是函数本身和该函数声明时所处的环境状态的组合
函数能够”记忆住“其定义时所处的环境,即使函数不在其定义的环境中被调用,也能访问定义时所处环境的变量
在js中,每次创建函数时都会创建闭包,但是闭包特性往往需要将函数”换一个地方“执行,才能被观察出来
闭包的功能:
记忆性:当闭包产生时,函数所处环境的状态会始终保持在内存中,不会在外层函数调用后被自动清除。
function fun() {var name = 'niubi';function innerFun() {alert(name);}return innerFun; } var inn = fun(); inn(); // 内部函数被移动到了外部执行
模拟私有变量
function fun() {var a = 0;return function() {alert(a);} } var getA = fun(); getA();
function fun() {
var a = 0;
return {
getA: function () {
return a;
},
add: function () {
a++;
},
pow: function () {
a *= 2;
}
};
}
var obj = fun();
console.log(obj.getA());
obj.add();注意:不能滥用闭包,否则会造成网页的性能问题,严重时可能导致内存泄漏。
立即调用函数IIFE
特殊写法,一旦被定义,就立即被调用
函数必须转为函数表达式才能被调用
(function () { // 通过圆括号将函数变为表达式// statements
})();+function() {alert(1);
}();-function() {alert(1);
}();
可以用来给变量赋值
var age = 12; var sex = '男'; var title = (function () {if (age < 18) {return '小朋友';} else {if (sex == '男') {return '先生';} else {return '女士';}} })();
在一些场合(如for循环中)将全局变量变为局部变量,语法更紧凑
var arr = [];
for (var i = 0; i < 5; i++) {
arr.push(function () {
alert(i);
});
}
arr2; // 弹出5
解决方法:
var arr = [];
for (var i = 0; i < 5; i++) {(function (i) {arr.push(function() {alert(i);});})(i);
}
arr[2](); // 弹出2
DOM
nodeType常用属性值
节点的nodeType属性可以显示这个节点具体的类型
nodeType值
节点类型
1
元素节点,例如
和
3
文字节点
8
注释节点
9
document节点
10
DTD节点
document对象
访问元素节点主要依靠document对象
几乎所有DOM的功能都被封装到了document对象中
document对象也表示整个HTML文档,它是DOM节点树的根
访问元素节点的常用方法
方法
功能
document.getElementById()
通过id得到元素
document.getElementsByTagName()
通过标签名得到元素数组
document.getElementsByClassName()
通过类名得到元素数组
document.querySelector()
通过选择器得到元素
document.querySelectorAll()
通过选择器得到元素数组
document.getElementById()
如果页面上有相同id的元素,则只能得到第一个
<div id = "box">我是一个盒子</div>
<p id = "para">我是一个段落</p>var box = document.getElementById('box');
var para = document.getElementById('para');
getElementsByTagName()
数组方便遍历,从而可以批量操控元素节点
即使页面上只有一个指定标签名的节点,也将得到长度为1的数组
任何一个节点元素也可以调用getElementsByTagName()方法,从而的到其内部的某种类的元素节点
<p>段落</p>
<p>段落</p>
<p>段落</p>
<p>段落</p>var ps = document.getElementsByTagName('p');
getElementsByClassName()
<div class = "spec">盒子</div>
<div class = "spec">盒子</div>
<div class = "spec">盒子</div>
<div class = "spec">盒子</div>var spec_divs = document.getElementsByClassName('spec');
querySelector()
该方法只能得到页面上一个元素,如果有多个元素符合条件,则只能得到第一个元素
<div id = "box1"><p>段落</p><p class = "spec">段落</p><p>段落</p><p>段落</p>
</div>var the_p = document.querySelector('#box1 .spec');
querySelectAll()
即使页面上只有一个符合选择器的节点,也将得到长度为1的数组
延迟运行
使用window.onload = function() {}事件(给window对象添加事件监听,onload表示页面都加载完毕了),使页面加载完毕后,再执行指定的代码
节点的关系
关系
考虑所有节点
只考虑元素节点
子节点
childNodes
children
父节点
parentNode
同
第一个子节点
firstChild
firstElementChild
最后一个子节点
lastChild
lastElementChild
前一个兄弟节点
previousSibling
previousElementSibling
后一个兄弟节点
nextSibling
nextElementSibling
注意:文本节点也属于节点,所以我们一般情况下会排除文本节点的干扰(用只考虑元素节点)
书写常见节点关系函数
<body><div id = "box1"><p>段落</p><p class = "spec">段落</p><p>段落</p><p>段落</p></div><script>var box = document.getElementById('box1');var spec = document.getElementsByClassName('spec');// 封装一个函数,返回元素的所有子元素节点,类似children的功能function getChildren(node) {var children = [];// 遍历node这个节点的所有子节点,判断每一个字节的nodeType属性是不是1// 如果是1, 就推入结果数组for (var i = 0; i < node.childNodes.length; i++) {if (node.childNodes[i] == 1) {children.push(node.childNodes[i]);}}return children;}// 封装一个函数,这个函数可以返回元素的前一个元素兄弟节点,类似previousElementSibling的功能function getElementPrevSibling(node) {var o = node;while (o.previousSibling != null) {if (o.prebiousSibling.nodeType == 1) {// 结束循环,找到了return o.previousSibling;}o = o.previousSibling;}return null;}// 封装一个函数,该函数可以返回元素的所有元素兄弟节点function getAllElementSibling(node) {var prevs = [];var nexts = [];var o = node;while (o.previousSibling != null) {if (o.previousSibling.nodeType == 1) {prevs.unshift(o.previousSibling);}o = o.previousSibling;}o = node;while (o.nextSibling != null) {if (o.nextSibling.nodeType == 1) {nexts.push(o.nextSibling);}o = o.nextSibling;}return prevs.concat(nexts);}</script>
</body>
改变元素节点中的内容
改变元素节点中的内容可以使用两个相关属性
innerHTML
能以HTML语法设置节点中的内容
innerText
只能以纯文本的形式设置节点中的内容
改变元素节点的CSS样式
相当于在设置行内style属性
oBox.style.backgroundColor = 'red'; // CSS 属性要写成驼峰形式
oBox.style.backgroundImage = 'url(images/1.jpg)';
oBox.style.fontSize = '32px';
改变元素节点的HTML属性
标准的W3C属性,如src、href等,只需直接打点进行更改即可
oImg.src = 'images/2.jpg';
不符合W3C标准的属性,要使用setAttribute()和getAttribute()来设置、读取
<body><div id = "box"></div><script>var box = document.getElementById('box');box.setAttribute('data-n', 10); // 添加data-n属性,值为10var n = box.getAttribute('date-n');alert(n);</script>
</body>
节点的创建
document.createElement()方法用于创建一个指定tagname的HTML元素
var oDiv = document.createElement('div');
新创建出的节点是”孤儿节点“,并没有被挂载到DOM树上,无法看见他
必须继续使用appendChild() 或 insertBefore() 方法将孤儿节点插入到DOM树上
任何已经在DOM树上的节点,都可以调用appendChild() 方法,它可以将孤儿节点挂载到他的内部,成为它的最后一个子节点
父节点.appendChild(孤儿节点);
任何已经在DOM树上的节点,都可以调用insertBefore() 方法,它可以将孤儿节点挂载到它的内部,成为它的”标杆子节点“之前的节点
父节点.insertBefore(孤儿节点, 标杆节点);
移动节点
如果将已经挂载到DOM树上的节点成为appendChild()或者insertBefore()的参数,这个节点将会被移动
新父节点.appendChild(已经有父亲的节点);新父节点.insertBefore(已经有父亲的节点, 标杆子节点);
// 这意味着一个节点不能同时位于DOM树的两个位置
删除节点
removeChild() 方法从DOM中删除一个子节点
父节点.removeChild(要删除子节点);
克隆节点
cloneNode()方法可以克隆节点,克隆出的节点是”孤儿节点“
参数是boolean类型,表示是否采用深度克隆,若为true,则该节点的所有后代节点也都会被克隆,若为false,则只克隆该节点本身
var 孤儿节点 = 老节点.cloneNode();
var 孤儿节点 = 老节点.cloneNode(true);
事件
- 常见的鼠标事件监听
事件名
事件描述
onclick
当鼠标单机某个对象
ondbclick
当鼠标双击某个对象
onmousedown
当某个鼠标按键在某个对象上被按下
onmouseup
当某个鼠标按键在某个对象上被松开
onmousemove
当某个鼠标按键在某个对象上被移动
onmouseenter
当鼠标进入某个对象(相似事件onmouseover)
onmouseleave
当鼠标离开某个对象(相似事件onmouseout)
onmouseenter不冒泡,onmouseover冒泡
- 常见的键盘事件监听
事件名
事件描述
onkeypress
当某个键盘的键被按下(系统按钮如箭头键和功能键无法得到识别)
onkeydown
当某个键盘的键被按下(系统按钮可是识别,并且会优先于onkeypress发生)
onkeyup
当某个键盘的键被松开
- 常见的表单事件监听
事件名
事件描述
onchange
用户改变域的内容之后
oninput
正在修改域的内容(输入内容)
onfocus
当某元素获得焦点(比如tab键或鼠标点击)
onblur
当某元素失去焦点
onsubmit
当表单被提交
onreset
当表单被重置
- 常见的页面事件监听
事件名
事件描述
onload
当页面或图像被完成加载
onunload
当用户退出页面
当盒子嵌套时事件监听的执行顺序
<div id = "box1"><div id = "box2"><div id = "box3"></div></div>
</div>
<script>var oBox1 = document.getElementById('box1');var oBox2 = document.getElementById('box2');var oBox3 = document.getElementById('box3');oBox1.onclick = function () {console.log('box1');};oBox2.onclick = function () {console.log('box2');};oBox3.onclick = function () {console.log('box3');};// 点击最里面的盒子,传播方向是从内到外
</script>
事件传播
事件的传播是:先从外到内,然后再从内到外(最内层不是先捕获再冒泡,而是根据书写代码顺序决定。同名盒子同阶段与顺序有关。如果给元素设置相同的两个或多个同名事件,则DOM0级写法后面写的会覆盖先写的;而DOM2级会按顺序执行)
onxxxx(DOM0级事件监听)只能监听冒泡阶段,所以观察出来的结果是从内到外
addEventListener()方法(DOM2级事件监听)
oBox.addEventListener('click',function() {// 这里是事件处理函数 }, true); // 第三个参数若为true,监听捕获阶段,为false,监听冒泡阶段
事件对象
事件处理函数提供一个形式参数,它是一个对象,封装了本次事件的细节
这个参数通常用单词event或字母e来表示
oBox.onmousemove = function (e) {// 对象e就是这次事件的“事件对象” };
对象相关属性
- 鼠标位置相关属性
触发这次事件时鼠标的位置的属性
属性
属性描述
clientX
鼠标指针相对于浏览器的水平坐标
clientY
鼠标指针相对于浏览器的垂直坐标
pageX
鼠标指针相对于整张网页的水平坐标
pageY
鼠标指针相对于整张网页的垂直坐标
offsetX
鼠标指针相对于事件源元素的水平坐标
offsetY
鼠标指针相对于事件源元素的垂直坐标
- e.charCode和e.keyCode属性
e.charCode属性通常用于onkeypress事件中,表示用户输入的字符的“字符码”
字符
字符码
数字0 ~ 数字9
48 ~ 57
大写字母A ~ Z
65 ~ 90
小写字母 a ~ z
97 ~ 122
e.keyCode属性通常用于onkeydown和onkeyup事件中,表示用户按下的按键的“键码”
按键
键码
数字0 ~ 数字9
48 ~ 57
字母部分大小写 a ~ z
65 ~ 90
四个方向键 ← ↑ → ↓
37、38、39、40
回车键
13
空格键
32
阻止默认事件
e.preventDefault()方法用来阻止事件产生的“默认动作”
e.stopPropagation()方法用来阻止事件继续传播
批量添加事件监听性能问题
- 每一个事件监听注册都会消耗一定的系统内存,而批量添加事件会导致监听数量太多,内存消耗会很大
事件委托
每一个事件监听注册都会消耗一定的系统内存,而批量添加事件会导致监听数量太多,内存消耗会很大(当有大量类似元素需要批量添加事件监听时,使用事件委托可以减少内存开销)
利用事件冒泡机制,将后代元素事件委托给祖先元素
注意:不能委托不冒泡的事件给祖先元素
当有动态元素节点上树时,使用事件委托可以让新上树的元素具有事件监听
相关属性
属性
属性描述
target
触发此事件的最早元素,即”事件源元素“
currentTarget
事件处理程序附加到的元素(this)
定时器
setInterval()函数可以重复调用一个函数,在每次调用之间具有固定的时间间隔
setInterval(function () {// 这个函数将自动被以固定间隔时间调用
}, 2000); // 第二个参数为间隔时间,单位为毫秒// 该函数可以接收第3、4……个参数,他们将按顺序传入函数
setInterval(function (a, b) {// 形式参数 a 的值是88,形参b的值是66
}, 2000, 88, 66); // 从第三个参数开始,表示传入函数内的参数// 具名函数也可以传入setInterval
var a = 0;
function fun() {console.log(++a);
};setInterval(fun, 1000);
清除定时器
clearInterval() 函数可以清除一个定时器
// 设置定时器,并用timer变量接收这个定时器
var timer = setInterval(function () {}, 2000);// 点击按钮时,清除定时器
oBtn.onclick = function () {clearInterval(timer);
};
延时器
setTimeout() 函数可以设置一个延时器,当指定时间到了之后,会执行函数一次,不再重复执行
var timer = setTimeout(function () {// 这个函数会在 2 秒后执行一次
}, 2000);clearTimeout(timer); // 清除延时器
异步
异步: 不会阻塞CPU继续执行其他语句,当异步完成时,会执行 ”回调函数“(callback)
setInterval() 和 setTimeout() 是两个异步语句
setTimeout(function () {console.log('A');
}, 2000); // 异步语句console.log('B'); // 异步语句不会阻塞程序的正常执行// 运行结果
B
A
函数节流
一个函数执行一次后,只有大于设定的执行周期后才允许执行第二次
var lock = true;
function 需要节流的函数() {// 如果锁时关闭状态,则不执行if(!lock) return;// 函数核心语句// 关锁lock = false;// 指定毫秒数后将锁打开setTimeout(function () {lock = true;}, 2000);
}
BOM
BOM(Browser Object Model,浏览器对象模型)是JS与浏览器窗口交互的接口
window对象
window对象是当前 js 脚本运行所处的窗口,而这个窗口中包含DOM结构,window.document属性就是document对象
在有标签页功能的浏览器中,每个标签都拥有自己的window对象;也就是说,同一个窗口的标签页之间不会共享一个window对象
全局变量会成为window对象的属性
var a = 10; console.log(window.a == a); // true
这意味着多个js文件之间是共享全局作用域的,即js文件没有作用域隔离功能
内置函数普遍是window的方法
如setInterval()、alert()等内置函数,普遍是window的方法
窗口尺寸相关属性
属性
意义
innerHeight
浏览器窗口的内容区域的高度,包含水平滚动条(如果有的话)
innerWidth
浏览器窗口的内容区域的宽度,包含垂直滚动条(如果有的话)
outerHeight
浏览器窗口的外部高度
outerWidth
浏览器窗口的外部宽度
获得不包含滚动条的窗口宽度,要用document.documentElement.clientWidth
resize事件
在窗口大小改变之后,就会触发resize事件,可以使用window.onresize或者window.addEventListener(‘resize’)来绑定事件处理函数
已卷动高度
window.scrollY属性表示在垂直方向已滚动的像素值
document.documentElement.scrollTop属性也表示窗口卷动高度
为了更好的浏览器兼容行,通常将两个一起写
var scrollTop = window.scrollY || document.documentElement.scrollTop;
document.documentElement.scrollTop不是只读的,而window.scrollY是只读的
scroll事件
在窗口被卷动之后,就会触发scroll事件,可以使用window.onscroll或者window.addEventListener(‘scroll’)来绑定事件处理函数
Navigator对象
window.navigator属性可以检索navigator对象,它内部含有用户此次活动的浏览器的相关属性和标识
属性
意义
appName
浏览器官方名称
appVersion
浏览器版本
userAgent
浏览器的用户代理(含有内核信息和封装壳信息)
platform
用户操作系统
History对象
window.history 对象提供了操作浏览器会话历史的接口
常用的操作就是模拟浏览器回退按钮
history.back(); // 等同于点击浏览器的回退按钮
history.go(-1); // 等同于 history.back();
Location对象
window.location 标识当前所在网址,可以通过给这个属性赋值命令浏览器进行页面跳转
window.location = 'http://www.baidu.com';
window.location.href = 'http://www.baidu.com';
重新加载当前页面
可以调用location的reload方法以重新加载当前页面,参数true表示从服务器强制加载
window.location.reload(true);
GET 请求查询参数
window.location.search 属性即为当前浏览器的 GET 请求查询参数
offsetTops属性
该属性表示此元素到定位祖先元素的垂直距离
定位祖先元素:在祖先中,离自己最近的且拥有定位属性的元素
使用这个属性的时候,所有祖先元素不要有定位
面向对象
对象(object)是”键值对“的集合,表示属性和值的映射关系
var obj = {name: '小明',age: 12,sex: '男',hobbies: ['足球', '编程']
}; // js中 花括号表示对象
注意:
如果对象的属性键名不符合js标识符命名规范,则这个键名必须用引号包裹
如果属性名不符合js标识符命名规范,则必须用方括号的写法来访问
如果属性名以变量形式存储,则必须使用方括号形式
var obj = {a: 1,b: 2,c: 3 }; var key = 'b'; console.log(obj.key); // undefined console.log(obj[key]); // 2
对象的创建
var obj = {a: 10
};
obj.b = 40;
删除属性
使用delete操作符删除某个对象的属性
var obj = {a: 1,b: 2
};
delete obj.a;
对象的方法
如果某个属性值是函数,则它被称为对象的方法
var xiaoming = {name: '小明',age: 12,sex: '男',hobbys: ['足球','游泳','编程'],'favorite-book': '舒克和贝塔',sayHello: function () {console.log('hello');}
};
对象的遍历
对象的遍历需要使用for…in…循环,可是遍历对象的每个键
for (var k in obj) {console.log('属性' + k + '的值是' + obj[k]);
}
对象的深克隆
var obj1 = {a: 1, b: 2, c: [33, 44, {m: 55,n: 66,p: [77, 88]}]
};function DeepClone(o) {if (Array.isArray(o)) {var result = [];for (var i = 0; i < o.length; i++) {result.push(DeepClone(o[i]));}} else if(typeof o == 'object') {var result = {};for (var k in o) {result[k] = DeepClone(o[k]);}} else {var result = o;}return result;
}
函数的上下文
函数中可以使用this关键字,它表示函数的上下文
同一个函数,用不同的形式调用它,则函数的上下文不同
函数只有被调用,他的上下文才能被确定
相关规则
规则
上下文
对象.函数()
对象
函数()
window
数组[下标]()
数组
IIFE
window
定时器
window
DOM事件处理函数
绑定DOM的元素
call和apply
任意指定
函数.call(上下文);
函数.apply(上下文);
区别:
function sum(b1, b2) {alert(this.c + this.m + this.e + b1 + b2);
}
sum.call(xiaoming, 5, 3); // call要用逗号罗列参数
sum.apply(xiaoming, [5, 3]); // apply要把参数写到数组中
new操作符调用函数
new 函数()
js规定,使用new操作符调用函数会进行“四步走”:
函数体内会自动创建出一个空白对象
函数的上下文(this)会指向这个对象
函数体内的语句会执行
函数会自动返回上下文对象,即使函数没有return语句
function fun() { // {} this指向这个空对象
this.a = 3;
this.b = 5; // {a: 3, b: 5}
// 自动补充return this;
}
var obj = new fun();
console.log(obj);
构造函数
将之前的函数进行一小步改进
function People(name, age, sex) {this.name = name;this.age = age;this.sex = sex;
}
var xiaoming = new People('小明', 12, '男');
var xiaoming = new People('小红', 10, '女');
var xiaogang = new People('小刚', 13, '男');
- 用new调用一个函数,这个函数就被称为“构造函数”,任何函数都可以是构造函数,只需要用new调用它
- 构造函数用来“构造新对象”,它内部的语句将为新对象添加若干属性和方法,完成对象的初始化
为对象添加方法
function People(name, age, sex) {this.name = name;this.age = age;this.sex = sex;this.sayHello = function () {console.log('我是' + this.name);};
}
var xiaoming = new People('小明', 12, '男');
xiaoming.sayHello();
prototype
任何函数都有prototype属性,prototype是英语”原型“的意思,prototype属性值是个对象,它默认拥有constructor属性指回函数
构造函数的prototype是实例的原型
原型链查找
实例可以打点访问它的原型的属性和方法,这被成为”原型链查找“
function People(name, age, sex) {this.name = name;this.age = age;this.sex = sex;
}
People.prototype.nationality = '中国'; // 在构造函数的prototype上添加nationality属性
var xiaoming = new People('小明', 12, '男');
console.log(xiaoming.nationality);
hasOwnProperty()
该方法可以检查对象是否真正”自己拥有“某属性或者方法
xiaoming.hasOwnProperty('name'); // true
xiaoming.hasOwnProperty('age'); // true
xiaoming.hasOwnProperty('sex'); // true
xiaoming.hasOwnProperty('nationality'); // false
in
in运算符只能检查某个属性或方法是否可以被对象访问,不能检查是否是自己的属性或方法
'name' in xiaoming // true
'age' in xiaoming // true
'sex' in xiaoming // true
'nationality' in xiaoming // true
在prototype上添加方法
将方法直接添加到实例身上的缺点:每个实例和每个实例的方法函数都是内存中不同的函数,造成了内存的浪费,可以通过将方法写道prototype上来解决。
function People(name, age, sex) {this.name = name;this.age = age;this.sex = sex;
}
People.prototype.sayHello = function () {console.log('我是' + this.name);
};
var xiaoming = new People('小明', 12, '男');
xiaoming.sayHello();
原型链的终点
数组的原型链
继承
- 借助原型链实现继承
让Student的prototype属性指向父类的实例,然后给Student的prototype添加Student的方法
通过原型链实现继承的问题
- 如果父类的属性中有引用类型值,则这个属性会被所有子类的实例共享
- 子类的构造函数中,往往需要重复定义很多超类定义过的属性。即,子类的构造函数写的不够优雅
- 借助构造函数
为了解决原型中包含引用类型值所带来问题和子类构造函数不优雅的问题,通常使用一种叫做 “借助构造函数” 的技术,也被称为 “伪造对象” 或 “经典继承”
在子类构造函数的内部调用超类的构造函数,但要注意使用call()绑定上下文
function People(name, sex, age) {this.name = name;this.sex = sex;this.age = age;this.arr = [1, 2, 3];
}function Student(name, sex, age, school, sid) {People.call(this, name, sex, age);this.school = school';this.sid = sid;
}var xiaoming = new Student('小明', '男', 12, '学校', 123456);
- 组合继承
将借用原型链和借用构造函数的技术组合到一起,叫做组合继承,也叫做伪经典继承
缺点:
组合继承最大的问题就是无论在什么情况下,都会调用两次超类的构造函数:一次是在创建子类原型的时候,另一次是在子类构造函数的内部。
原型式继承
Object.create()方法,可以根据指定的对象为原型创建出新对象(IE9)
var obj2 = Object.create(obj1);// 写法2
var obj2 = Object.create(obj1, { // 第二个参数为一个对象,将要补充的属性写在里面d: { // 属性的值仍然是一个对象value : 99 // 值为99} // 可以遮蔽原型上的同名属性
});
在没有必要 “兴师动众” 的创建构造函数,而只是想让新对象与现有对象 “类似” 的情况下,使用Object.create() 即可胜任,称为原型式继承
Object.create() 的兼容性写法
在低版本浏览器中实现Object.create()
// 道格拉斯·克罗克福德写的一个函数
// 函数功能就是以 o 为原型,创建新对象
function object(o) {// 创建一个临时构造函数function F() {}// 让这个临时构造函数的prototype指向o, 这样它new出来的对象,__proto__指向了oF.prototype = o;return new F();
}
寄生式继承
编写一个函数,它可以 “增强对象”,只要把对象传入这个函数,这个函数将以此对象为 “基础” 创建出新对象,并为新对象赋予新的预置方法
function f(o) {var p = Object.create(o);p.display = function () {console.log(111);}return p;
}
缺点:
由于不能做到函数复用而降低效率(方法没有写到prototype上)
寄生组合式继承
通过借用构造函数来继承属性,通过原型链的混成形式来继承方法
function inheritPrototype(subType, superType) {var prototype = Object.create(superType.prototype);subType.prototype = prototype;
}// 父类
function People(name, sex, age) {this.name = name;this.sex = sex;this.age = age;
}People.prototype.sayHello = function() {console.log("hello");
}
People.prototype.sleep = function () {console.log("sleep");
}// 子类
function Student(name, sex, age, school, sid) {People.call(this, name, sex, age);this.school = school;this.sid = sid;
}inheritPrototype(Student, People); // 让Student类的Prototype指向以People.prototype为原型的一个新对象Student.prototype.exam = function () {console.log("exam");
};var xiaoming = new Student('小明', '男', 12, '学校', 123456);
instanceof运算符
用来检测 ”某对象是不是某个类的实例“
xiaoming instanceof Student
// 底层机理:检查Student.prototype属性是否在xiaoming的原型链上(多少层都行,只要在就行)
内置构造函数
JavaScript有很多内置构造函数,比如Array就是数组类型的构造函数,Function就是函数类型的构造函数,Object就是对象类型的构造函数
内置构造函数非常有用,所有该类型的方法都是定义在它的内置构造函数的prototype上的,我们可以给这个对象添加新的方法,从而拓展某些类型的功能
内置构造函数的关系
Object.prototype是万物原型链的终点,JavaScript中函数数组皆为对象。
任何函数都可以看做是Function “new出来的”,Object是函数,所以它也是Function类的对象
包装类
包装类的目的就是为了让基本类型值可以从它们的构造函数的prototype上获得方法
Math对象
Math.pow()
Math.sqrt()
Math.ceil() // 向上取整
Math.floor() // 向下取整
Math.round() // 四舍五入
Math.max() // 参数列表的最大值
Math.min()// 计算arr数组的最大值
var arr = [3, 6, 9, 2];
var max = Math.max.apply(null, arr);
Date对象
new Date() // 得到当前时间的日期对象
newDate(2020, 11, 1) // 第二个参数从0开始算
new Date('2020-12-01')
常见方法
方法
功能
getDate()
得到日期 1 ~ 31
getDay()
得到星期 0 ~ 6
getMonth()
得到月份 0 ~ 11
getFullYear()
得到年份
getHours()
得到小时数 0 ~ 23
getMinutes()
得到分钟数 0 ~ 59
getSeconds()
得到秒数 0 ~ 59
时间戳
通过getTime()方法或者Date.parse()函数可以将日期对象变为时间戳
通过new Date(时间戳)的写法,可以将时间戳变为日期对象
var d = new Date();var timestamp1 = d.getTime();
var timestamp2 = Date.parse(d);
正则表达式
正则表达式(regular expression)描述了字符串的 “构成模式”,经常被用于检查字符串是否符合预定的格式要求
创建正则表达式
使用
/内容/
的语法形式var str = ‘123456’;
var regxp = /^d{6}$/;
if (regxp.text(str)) {
alert(‘符合规则’);
} else {
alert(‘不符合规则’);
}new RegExp(‘内容’)的形式
var regxp2 = new RegExp(‘^\d{6}$’)
元字符
元字符
功能
d
匹配一个数字
D
匹配一个非数字字符
w
匹配一个单字字符(字母、数字或下划线)
W
匹配非单字字符
s
匹配一个空白字符,包括空格、制表符和换行符
.
任意字符
^
匹配开头
$
匹配结尾
不管一个符号有没有特殊意义,都可以在其之前加上一个以确保它表达的是这个符号本身
方括号表示法
使用方括号,如[xyz],可以创建一个字符集,表示匹配方括号中的任意字符
/^[by]d{7}$/
使用短横-
来指定一个字符范围,^
表示否定
元字符
等价的方括号表示法
d
[0-9]
D
[^0-9]
w
[A-Z-z0-9_]
W
[^A-Z-z0-9_]
量词
量词
意义
*
匹配前一个表达式0次或多次。等价于{0,}
匹配前一个表达式1次或多次。等价于{1,}
匹配前面一个表达式0次或1次。等价于{0,1}
{n}
匹配了前面一个字符刚好出现了n次
{n,}
匹配前一个字符至少出现了n次
{n,m}
匹配前面的字符至少n次,最多m次
修饰符
也叫标志(flags),用于使用正则表达式实现高级搜索
修饰符
意义
i
不区分大小写搜索
g
全局搜索
var re = /m/gi;
var re = new RegExp('m', 'gi');
正则表达式相关方法
方法
简介
test()
测试某字符串是否匹配正则表达式,返回布尔值
exec()
根据正则表达式,在字符串中进行查找,返回结果数组或null
字符串的相关正则方法
方法
简介
search()
在字符串中根据正则表达式进行查找匹配,返回首次匹配到的位置索引,测试不到则返回-1
match()
在字符串中根据正则表达式进行查找匹配,返回一个数组,找不到则返回null
replace()
使用替换字符串替换掉匹配到的子字符串,可以使用正则表达式
split()
分隔字符串为数组,可以使用正则表达式
var str = 'abc123def4567ghi89';// search()方法,很像indexOf(),返回查找到的第一个下标,如果找不到就是-1
var result1 = str.search(/d+/g);
var result2 = str.search(/m/g);
console.log(result1); // 3
console.log(result2); // -1// match()方法,返回查找到的数组,找不到就是null
var result3 = str.match(/d+/g);
console.log(result3); // ["123", "4567", "89"]// replace()方法,进行替换
var result4 = str.replace(/[a-z]+/g, '*'); // 注意+表示贪婪的,尽可能多的连续匹配小写字母
console.log(result4); // *123*4567*89// split()方法,进行字符串拆为数组
var result5 = str.split(/d+/g);
console.log(result5); // ["abc", "def", "ghi", ""]
先自我介绍一下,小编13年上师交大毕业,曾经在小公司待过,去过华为OPPO等大厂,18年进入阿里,直到现在。深知大多数初中级java工程师,想要升技能,往往是需要自己摸索成长或是报班学习,但对于培训机构动则近万元的学费,着实压力不小。自己不成体系的自学效率很低又漫长,而且容易碰到天花板技术停止不前。因此我收集了一份《java开发全套学习资料》送给大家,初衷也很简单,就是希望帮助到想自学又不知道该从何学起的朋友,同时减轻大家的负担。添加下方名片,即可获取全套学习资料哦
【JavaScript】 一万字 JavaScript 笔记(详细讲解 + 代码演示 + 图解)相关推荐
- ❤️整理2万字带你走进C语言(详细讲解+代码演示+图解)❤️(强烈建议收藏!!!)
目录 一.什么是C语言? 二.第一个C语言程序 起源 代码 程序分析 程序运行 一个工程中出现两个及以上的main函数 代码 运行结果 分析 三.数据类型 数据各种类型 为什么会有这么多的数据类型? ...
- 尚硅谷vue笔记 详细讲解版(尚硅谷 天禹老师)
视频:[尚硅谷Vue2.0+Vue3.0全套教程丨vuejs从入门到精通]https://www.bilibili.com/video/BV1Zy4y1K7SH?vd_source=10e3dfac9 ...
- javascript中常用数组方法详细讲解
javascript中数组常用方法总结 1.join()方法: Array.join()方法将数组中所以元素都转化为字符串链接在一起,返回最后生成的字符串.也可以指定可选的字符串在生成的字符串中来分隔 ...
- javascript - 实现拍照功能(详细示例代码)
介绍 HTML5 的 getUserMedia API 为用户提供访问硬件设备媒体(摄像头.视频.音频.地理位置等)的接口,基于该接口,开发者可以在不依赖任何浏览器插件的条件下访问硬件媒体设备. 另外 ...
- 算法--背包九讲(详细讲解+代码)
背包九讲 目录 第一讲 01背包问题 第二讲 完全背包问题 第三讲 多重背包问题 第四讲 混合三种背包问题 第五讲 二维费用的背包问题 第六讲 分组的背包问题 第七讲 有依赖的背包问题 ...
- HMM超详细讲解+代码
文章目录 本文目标 评估描述 预测描述 #写在前面 老习惯,正文之前瞎扯一通.HMM学了很久,最初是在<统计学自然语言处理>里面就学到了相关内容,并且知道HMM CRF一直都是NLP比较底 ...
- Educational Codeforces Round 145 (E. Two Tanks 详细讲解 + 代码注释)
E. Two Tanks 链接:E. Two Tanks 推荐大佬的视频讲解:B站 yingluosanqian 大晚上琢磨jiang老师的代码看不明白,还好找到这个视频讲解,以下题解基于该视频讲解, ...
- 【C语言】深入浅出理解指针及内存与指针的关系(详细讲解+代码展示)
目录 概述 内存 内存含义 内存作用: 物理存储器和存储地址空间 物理存储器:实际存在的具体存储器芯片. 存储地址空间:对存储器编码的范围. 内存地址 指针和指针变量 指针基础知识 指针变量的定义和使 ...
- python中read函数解释_Python内置函数解释教程,readwill(非常详细的代码演示截图),详解,看,了,就,会,很...
内置函数 abs() 获取绝对值 all() 接受一个迭代器,如果迭代器的所有元素都为真,那么返回True,否则返回False any() 接受一个迭代器,如果迭代器里有一个元素为真,那么返回True ...
- Web前端:JavaScript最强总结 附详细代码 (带常用案例!)
Web前端基础: Web前端:HTML最强总结 附详细代码 Web前端:CSS最强总结 附详细代码 Web前端:JavaScript最强总结 附详细代码 Web前端工具: Web前端: JQuery最 ...
最新文章
- B 站校招面试官“炫耀资产、贬低应试者”?当事人发长文回应,北邮学子要求向学校道歉
- Android Fragment详解(二):Fragment创建及其生命周期
- 让VisualSVN Server支持匿名访问
- Win32 API 浏览目录对话框示例
- list dict 性能测试
- golden gate 错误集锦
- URL2Video:把网页自动创建为短视频
- SAP Cloud for Customer图片渲染逻辑的调试
- 打破多项世界记录 双11背后最大的力量是技术
- 机器学习中的数学(三)--牛顿法
- QTP的那些事--weblist中相关的内容获取
- 惠普打印机驱动安装找不到打印机
- python机械数据分析_记一次小机器的 Python 大数据分析
- week 5 session and cookie
- 嫡权法赋权法_客观赋权法的使用
- ELK日志分析Elasticsearch模块——语法基础CRUD
- CSS 按钮悬停效果
- 爬虫学习笔记-scrapy框架介绍
- CVX工具下载及测试
- matlab模拟薄膜振动,(数理方程)Matlab模拟琴弦振动发声并显示振动图像
热门文章
- CentOS 搭建NFS
- #pragma comment 用法
- 国家一级职业资格证书 计算机类有哪些
- Walking Robot Simulation
- 罗技craft写java怎么样_评测| 入手罗技CRAFT无线键盘后才知道什么叫奢华
- Nofollow标签的写法以及nofollow使用介绍
- Ubuntu / Debian: sudo 出现 unable to resolve host 错误解决办法
- Vulkan同步机制和图形-计算-图形转换的风险(一)
- vue-baidu-map 百度地图(定位替换图标,添加标签)
- 最近火爆全网的猫猫回收站教程,小七给你们搞来了