目录
一、编程语言
1.1 编程
1.2 计算机语言
1.3 编程语言
1.4 翻译器
1.5 编程语言和标记语言区别
总结
二、计算机基础
2.1 计算机组成
2.2.数据存储
2.3 数据存储单位
2.4 程序运行
三、HTML中的JavaScript
1.元素
1.1 标签的位置
1.2 延迟脚本--defer
1.3 异步脚本--async
1.4 XHML中的变化
2.嵌入代码和外部文件
3.元素
4.小结
四、初始JavaScript
1.1 Javascript是什么
1.2JavaScript的作用
1.3 HTML/CSS/JS的关系
1.4 浏览器执行JS简介
1.5 JS组成
编辑 1.6 JS初体验
1.6.1 行内式JS
1.6.2 内嵌JS
1.6.3 外部JS文件
四、JavaScript注释
1.单行注释
2.多行注释
五、Javascript输入输出语句
六、变量
1.变量的概述
1.1 什么是变量
1.2 变量在内存中的存储
2.变量的使用
2.1 声明变量
2.2.赋值
2.3 变量的初始化
2.4 【案例】变量的使用
3.变量语法扩展
3.1 更新变量
3.2 同时声明多个变量
3.3 声明变量特殊情况
4.变量命名规范
5.标识符
6.var 、 let、 const
6.1 var关键字--声明的是函数作用域
6.2 let关键字--声明的是块作用域
6.3 const声明
7.交换变量案例
七、数据类型
1.数据类型简介
1.1 为什么需要数据类型
1.2 变量的数据类型
1.3 数据类型的分类
2.简单数据类型(Number,String,Boolean,Undefined,Null)
2.1 数字型--Number
编辑 2.2 字符串类型--String
2.3 布尔值--Boolean
2.4 Undefined和Null
3.获取变量数据类型(Object)
3.1 获取检测变量的数据类型--typeof
3.2 字面量
4.数据类型转换
4.1 什么是数据类型转换
4.2 转换为字符串
4.3 转换为数字型(重点)
编辑
【案例】计算年龄
【简单加法器】
4.4转换为布尔值
八、标识符,关键字,保留字
1.标识符
2.关键字
3.保留字
九、JavaScript 运算符
1.运算符
2.算数运算符
2.1 算术运算符概述
2.2 浮点数的精度问题
2.3 表达式和返回值
3.递增和递减运算符(一元运算符)
3.1 递增和递减运算符概述
3.2 递增运算符
3.3 前置递增和后置递增小结
4.比较运算符
4.1 比较运算符概述
4.2 小结
5.逻辑运算符
5.1 逻辑运算符概述
5.2 逻辑与 &&
5.3 逻辑或 ||
5.4 逻辑非 !
5.5 短路运算(逻辑中断)
6.赋值运算符
7.运算符优先级
8.练习
十、JavaScript 流程控制--分支
1.流程控制
2.顺序流程控制
3.分支流程控制if语句
3.1 分支结构
3.2 if语句
3.3 if else语句(双分支语句)
3.4 if else if语句(多分支语句)
4.三元表达式
4.1 语法结构
4.2 执行思路
5.分支流程控制switch语句
5.1 语法结构
5.2 switch 语句和 if else if 语句的区别
十一、JavaScript 流程控制--循环
1.循环
2.for循环
2.1 语法结构
2.2 for循环重复相同的代码
2.3 for循环重复不相同的代码
3.双重for循环
3.1 双重for循环概述
3.2 双重for循环语法
3.5 for循环小结
4.while循环
5.do while 循环
6.continue break
6.1 continue关键字
6.2 break关键字
十二、数组
1.数组的概念
2.创建数组
2.1 利用new创建数组--new Array()
2.2 利用数组字面量创建数组
2.4 数组元素的类型
3.获取数组中的元素
3.1 数组的索引
4.遍历数组
4.1 数组的长度
编辑
5.数组中新增元素
5.1 通过修改length长度新增数组元素
5.2 通过修改数组索引新增数组元素
【案例-数组新增元素】
【案例-筛选数组】
6.数组案例
十二、JavaScript 函数
1.函数的概念
2.函数的使用
2.1 声明函数
2.2 调用函数
2.3 函数的封装
3.函数的参数
3.1形参和实参
3.2 函数参数的传递过程
3.3 函数形参和实参个数不匹配问题
3.4 小结
4.函数的返回值
4.1 return 语句
4.2 return终止函数
编辑 4.3 return 的返回值
4.4 函数没有return 返回 undefined
4.5 break,continue,return 的区别
4.6 return 注意事项
5.arguments(伪数组)的使用
6.函数案例
【案例--利用函数封装方法,翻转任意一个数组】
【案例--利用函数封装方法,队数组排序--冒泡排序】
【案例--判断闰年】
函数可以调用另外一个函数
【案例-用户输入年份,输出当前年份2月份的天数】
7.函数的两种声明方式
7.1 自定义函数方式(命名函数)
7.2 函数表达式方式(匿名函数)
十三、Javascript 作用域
1.作用域
2.变量的作用域
2.1 全局变量
2.2 局部变量
2.3 Javascript没有块级作用域
3.作用域链
编辑
【案例】
十四、预解析
1.预解析
2.变量预解析和函数预解析
3.预解析案例
十五、Javascript 对象
1.对象
1.1 什么是对象
1.2 为什么需要对象
2.创建对象的三种方式
2.1 利用字面量创建对象
编辑
2.2 利用new Object 创建对象
2.3 利用构造函数创建对象
编辑
2.4 构造函数和对象
3.new关键字
4.遍历对象属性(for...in)--for( var k in obj)
十六、JavaScript 内置对象
1.内置对象
编辑
2.查文档
2.1 MDN
2.2 如何学习对象中的方法
3.Math对象
3.1 Math概述
3.2 随机数方法random()--[0,1)
4.日期对象
4.1 Date概述
4.2 Date()方法的使用
4.3 日期格式化
4.4 获取日期的总的毫秒形式
【案例:倒计时效果】
5.数组对象
5.1 数组对象的创建
5.2 检测是否为数组----instanceof、Array.isArray()
5.3 添加删除数组元素的方法
5.4 数组排序
5.5 数组索引方法
5.6 数组转换为字符串
5.7 其他
6.字符串对象
6.1 基本包装类型
6.2 字符串的不可变
6.3 根据字符返回位置
6.4 根据位置返回字符
6.5 字符串操作方法
6.6replace()方法
6.7 split()方法
6.8 其他
十七、JavaScript 简单类型与复杂类型
1.简单类型和复杂类型
编辑
2.堆和栈
3.简单类型的内存分配
编辑
4.复杂类型的内存分配
编辑
5.简单类型传参
6.复杂类型传参
十八、Web APIs
1. Web APIs 和 JS 基础关联性
1.1 JS的组成
1.2 JS基础阶段以及Web APIs阶段
2.API(接口)和Web API(浏览器接口)
2.3 API和Web API总结
2.4 什么是DOM
2.5 DOM树
2.6 DOM对象
十九、DOM元素的获取
1.根据CSS选择器来获取DOM元素(必须是字符串,也就是必须加引号;如果是类选择器前面加“.";如果是id选择器前面加"#")
1.1 选择匹配的第一个元素--document.querySelector('CSS选择器')
1.2 选择匹配的多个元素(得到的是一个伪数组)--document.querySelectorAll('CSS选择器')
2.其他获取DOM元素方法
根据标签获取一类元素 获取页面 所有div(返回的是伪数组) ---->document.getElementsByTagName('div')
根据类名获取元素 获取页面 所有类名为w的 --->document.getElementByClassName('w')
获取某一个元素(父元素)内部所有指定标签的子元素--element(父元素).getElementsByTagName('标签名')
3. 获取HTML和Body标签
二十、事件基础
1. 事件基础
2.事件三要素
1. 事件源 (谁)2. 事件类型 (什么事件)3. 事件处理程序 (做啥)
3.执行事件的步骤
1. 获取事件源2. 注册事件(绑定事件)3. 添加事件处理程序(采取函数赋值形式)
4.常见的鼠标事件
二十一、设置/修改DOM元素内容
1. document.write()方法
2.对象.innerText属性
3.对象.innerHTML属性
4.三种方法的总结和区别
编辑
5.常见元素的属性操作
6.案例
【分时显示不同图片,显示不同问候语】
7.表单元素的属性操作
【案例-- 仿京东显示密码】
8. 样式属性操作
【 案例: 淘宝点击关闭二维码】
【案例: 循环精灵图背景】
【案例:显示隐藏文本框内容】
【案例: 密码框格式提示错误信息】
9.操作元素总结
10.排他思想
【案例:百度换肤】
【案例:表格隔行变色】
【案例:表单全选取消全选案例】
11.自定义属性的操作
1. 获取属性值
2.设置属性值
3.移除属性
12.H5自定义属性--只能通过getAttriubute
12.1 设置H5自定义属性----data-index="2"/div.setAttribute('data-time', 20)
12.2 获取H5自定义属性 ---element.getAttrubute('data-index')/element.dataset.index/element.dataset['index']
二十二、节点操作
1.为什么学节点操作
2.节点概述
3.节点层级
3.1 父级节点--node.parentNode
3.2 子节点(总结:无论用什么都是“父节点.children【】”)
3.3 兄弟节点
3.4 创建节点
4.4 添加节点
4.5 删除节点
4.6 复制节点(克隆节点)--node.cloneNode(false)-->不复制内容/node.cloneNode(true)-->复制内容
4.7 三种动态创建元素区别
二十二、DOM重点核心
1.创建
1. document.write2. innerHTML3. createElement
2.增
1. appendChild2. insertBefore
3.删
1.. removeChild
4.改
1. 修改元素属性: src、href、title等2. 修改普通元素内容: innerHTML 、innerText3. 修改表单元素: value、type、disabled等4. 修改元素样式: style、className
5.查
6.属性操作
7.事件操作
7.1 注册事件两种方式
二十三、PC端网页特效
1. 元素偏移量offset系列
1.1 offset概述
编辑
1.2 offset 与 style 区别
2.元素可视区client系列
3.元素滚动scroll系列
3.1 元素scroll系列属性
3.2 页面被卷去的头部
3.3 页面被卷去的头部兼容性解决方案
4.offset、client、scroll总结
5.mouseenter 和mouseover的区别
6.动画函数封装
6.1 动画实现原理
6.2 动画函数简单封装
6.3 动画函数给不同元素记录不同定时器
6.4 缓动效果原理
6.5 动画函数多个目标值之间移动
6.6 动画函数添加回调函数
6.7 动画函数封装到单独JS文件里面
6.常见网页特效案例
【案例:网页轮播图】
6.1 节流阈
二十四、事件高级
1.注册事件(绑定事件)
1.1 注册事件概述:传统方式 VS 方法监听注册事件
1.2 addEventListener事件监听方式
1.3 attachEvent 注册事件 事件监听方式
注意点:
1.4 注册事件兼容性解决方案
2删除事件(解绑事件)
2.1 删除事件的方式
2.2 删除事件兼容性解决方案
3.DOM事件流
4.事件对象
4.1 什么是事件对象
4.2 事件对象的使用语法
4.3 事件对象的兼容性方案
4.4 事件对象的常见属性和方法
5.阻止事件冒泡
5.1 阻止事件冒泡的两种方式
5.2 阻止事件冒泡的兼容性解决方案
6.事件委托(代理,委派)
7.常用的鼠标事件
7.1 常用的鼠标事件
7.2 鼠标事件对象
8.常用的键盘事件
8.1 常用键盘事件
8.2 键盘事件对象
8.3 ASCII 表
立即下载,但是先将整个页面解析完,才开始运行。
在XHTML文档中,要把defer属性设置为defer="defer"
在XHTML文档中,要把async属性设置为async="async"
XHTML中使用JavaScript必须指定type属性且值为text/javascript
这个元素可以包含能够出现在文档中的任何HTML元素--->script>元素除外
var 在 ECMAScript 的所有版本中都可以使用,而 const 和 let 只能在 ECMAScript 6 及更晚的版本中使用。
(1) var声明作用域
(2)var声明提升
块作用域是函数作用域的子集
let 也不允许同一个块作用域中出现冗余声明
(1)暂时性死区
let 与 var 的另一个重要的区别,就是 let 声明的变量不会在作用域中被提升
// name 会被提升
console.log(name); // undefined
var name = 'Matt';
// age 不会被提升
console.log(age); // ReferenceError:age 没有定义
let age = 26;
在解析代码时,JavaScript 引擎也会注意出现在块后面的 let 声明,只不过在此之前不能以任何方 式来引用未声明的变量。在 let 声明之前的执行瞬间被称为“暂时性死区”(temporal dead zone),在此 阶段引用任何后面才声明的变量都会抛出 ReferenceError。
(2)全局声明
与 var 关键字不同,使用 let 在全局作用域中声明的变量不会成为 window 对象的属性(var 声 明的变量则会)。
var name = 'Matt';
console.log(window.name); // 'Matt'
let age = 26;
console.log(window.age); // undefined
(3)条件声明
在使用 var 声明变量时,由于声明会被提升,JavaScript 引擎会自动将多余的声明在作用域顶部合 并为一个声明。因为 let 的作用域是块,所以不可能检查前面是否已经使用 let 声明过同名变量,同 时也就不可能在没有声明的情况下声明它。
使用 try/catch 语句或 typeof 操作符也不能解决,因为条件块中 let 声明的作用域仅限于该块。
(4)for 循环中的 let 声明
这种每次迭代声明一个独立变量实例的行为适用于所有风格的 for 循环,包括 for-in 和 for-of 循环。
const 的行为与 let 基本相同,唯一一个重要的区别是用它声明变量时必须同时初始化变量,且 尝试修改 const 声明的变量会导致运行时错误。
const 声明的限制只适用于它指向的变量的引用。换句话说,如果 const 变量引用的是一个对象, 那么修改这个对象内部的属性并不违反 const 的限制。
const person = {};
person.name = 'Matt'; // ok
JavaScript 引擎会为 for 循环中的 let 声明分别创建独立的变量实例,虽然 const 变量跟 let 变 量很相似,但是不能用 const 来声明迭代变量(因为迭代变量会自增):
for (const i = 0; i < 10; ++i) {} // TypeError:给常量赋值
如果你只想用 const 声明一个不会被修改的 for 循环变量,那也是可以的。也就是说,每 次迭代只是创建一个新变量。这对 for-of 和 for-in 循环特别有意义
(1)数值进制
八进制前面加0,十六进制前面加0x
如果字面量中包含的数字超出了应 有的范围,就会忽略前缀的零,后面的数字序列会被当成十进制数,
(2)数字类型范围
(3)数值类型的三个特殊值
(4)isNaN()
console.log(0/0); // NaN
console.log(-0/+0); // NaN
//如果分子是非 0 值,分母是有符号 0 或无符号 0,则会返回 Infinity 或-Infinity:
console.log(5/0); // Infinity
console.log(5/-0); // -Infinity
任何涉及 NaN 的操作始终返回 NaN(如 NaN/10)
NaN 不等于包括 NaN 在内的任何值
console.log(NaN == NaN); // false
ECMAScript 提供了 isNaN()函数。该函数接收一个参数,可以是任意数据类型,然后判断 这个参数是否“不是数值”。把一个值传给 isNaN()后,该函数会尝试把它转换为数值。某些非数值的 值可以直接转换成数值,如字符串"10"或布尔值。任何不能转换为数值的值都会导致这个函数返回 true。
console.log(isNaN(NaN)); // true
console.log(isNaN(10)); // false,10 是数值
console.log(isNaN("10")); // false,可以转换为数值 10
console.log(isNaN("blue")); // true,不可以转换为数值
console.log(isNaN(true)); // false,可以转换为数值 1
(5)浮点值
要定义浮点值,数值中必须包含小数点,而且小数点后面必须至少有一个数字。虽然小数点前面不 是必须有整数,但推荐加上。
let floatNum1 = 1.1;
let floatNum2 = 0.1;
let floatNum3 = .1; // 有效,但不推荐
如果数值本身就是整数,只是小 数点后面跟着 0(如 1.0),那它也会被转换为整数。
对于非常大或非常小的数值,浮点值可以用科学记数法来表示。科学记数法用于表示一个应该乘以 10 的给定次幂的数值。ECMAScript 中科学记数法的格式要求是一个数值(整数或浮点数)后跟一个大 写或小写的字母 e,再加上一个要乘的 10 的多少次幂。
if (a + b == 0.3) { // 别这么干!
console.log("You got 0.3.");
}
(6)数值转换
有 3 个函数可以将非数值转换为数值:Number()、parseInt()和 parseFloat()。
Number()--可以用于任何数据类型
let num1 = Number("Hello world!"); // NaN
let num2 = Number(""); // 0
let num3 = Number("000011"); // 11
let num4 = Number(true); // 1
parseInt()--字符串转换为数值
let num1 = parseInt("1234blue"); // 1234
let num2 = parseInt(""); // NaN
let num3 = parseInt("0xA"); // 10,解释为十六进制整数
let num4 = parseInt(22.5); // 22
let num5 = parseInt("70"); // 70,解释为十进制值
let num6 = parseInt("0xf"); // 15,解释为十六进制整数
不同的数值格式很容易混淆,因此 parseInt()也接收第二个参数,用于指定底数(进制数)。
let num1 = parseInt("10", 2); // 2,按二进制解析
let num2 = parseInt("10", 8); // 8,按八进制解析
let num3 = parseInt("10", 10); // 10,按十进制解析
let num4 = parseInt("10", 16); // 16,按十六进制解析
parseFloat()--字符串转换为数值
let num1 = parseFloat("1234blue"); // 1234,按整数解析
let num2 = parseFloat("0xA"); // 0
let num3 = parseFloat("22.5"); // 22.5
let num4 = parseFloat("22.34.5"); // 22.34
let num5 = parseFloat("0908.5"); // 908.5
let num6 = parseFloat("3.125e7"); // 31250000
(1)字符串引号嵌套
(2)字符串转义符
(3)字符串长度
(4)字符串拼接--只要有字符串则最后结果都是字符串
有两种方式把一个值转换为字符串。首先是使用几乎所有值都有的 toString()方法。这个方法唯 一的用途就是返回当前值的字符串等价物。toString()方法可见于数值、布尔值、对象和字符串值。(没错,字符串值也有 toString()方法, 该方法只是简单地返回自身的一个副本。)null 和 undefined 值没有 toString()方法
let age = 11;
let ageAsString = age.toString(); // 字符串"11"
let found = true;
let foundAsString = found.toString(); // 字符串"true"
多数情况下,toString()不接收任何参数。不过,在对数值调用这个方法时,toString()可以接收一个底数参数,即以什么底数来输出数值的字符串表示。默认情况下,toString()返回数值的十 进制字符串表示。而通过传入参数,可以得到数值的二进制、八进制、十六进制,或者其他任何有效基 数的字符串表示
let num = 10;
console.log(num.toString()); // "10"
console.log(num.toString(2)); // "1010"
console.log(num.toString(8)); // "12"
console.log(num.toString(10)); // "10"
console.log(num.toString(16)); // "a"
let value1 = 10;
let value2 = true;
let value3 = null;
let value4;
console.log(String(value1)); // "10"
console.log(String(value2)); // "true"
console.log(String(value3)); // "null"
console.log(String(value4)); // "undefined"
(5)字符串拼接加强
(6)字符串的特点
ECMAScript 中的字符串是不可变的(immutable),意思是一旦创建,它们的值就不能变了。要修改 某个变量中的字符串值,必须先销毁原始的字符串,然后将包含新值的另一个字符串保存到该变量
(7)模板字面量
ECMAScript 6 新增了使用模板字面量定义字符串的能力。与使用单引号或双引号不同,模板字面量 保留换行字符,可以跨行定义字符串
let myMultiLineString = 'first line\nsecond line';
let myMultiLineTemplateLiteral = `first line
second line`;
console.log(myMultiLineString);
// first line
// second line"
console.log(myMultiLineTemplateLiteral);
// first line
// second line
console.log(myMultiLineString === myMultiLinetemplateLiteral); // true
由于模板字面量会保持反引号内部的空格,因此在使用时要格外注意。格式正确的模板字符串看起 来可能会缩进不当
// 这个模板字面量在换行符之后有 25 个空格符
let myTemplateLiteral = `first line
second line`;
console.log(myTemplateLiteral.length); // 47
// 这个模板字面量以一个换行符开头
let secondTemplateLiteral = `
first line
second line`;
console.log(secondTemplateLiteral[0] === '\n'); // true
// 这个模板字面量没有意料之外的字符
let thirdTemplateLiteral = `first line
second line`;
console.log(thirdTemplateLiteral);
// first line
// second line
(8)字符串插值
模板字面量最常用的一个特性是支持字符串插值,也就是可以在一个连续定义中插入一个或多个 值。技术上讲,模板字面量不是字符串,而是一种特殊的 JavaScript 句法表达式,只不过求值后得到的 是字符串。
let value = 5;
let exponent = 'second';
// 以前,字符串插值是这样实现的:
let interpolatedString =
value + ' to the ' + exponent + ' power is ' + (value * value);
// 现在,可以用模板字面量这样实现:
let interpolatedTemplateLiteral =
`${ value } to the ${ exponent } power is ${ value * value }`;
console.log(interpolatedString); // 5 to the second power is 25
console.log(interpolatedTemplateLiteral); // 5 to the second power is 25
模板也可以插入自己之前的值
let value = '';
function append() {
value = `${value}abc`
console.log(value);
}
append(); // abc
append(); // abcabc
append(); // abcabcabc
【案例】显示年龄
默认值是false
Boolean()转型函数可以在任意类型的数据上调用,而且始终返回一个布尔值。什么值能转换为 true 或 false 的规则取决于数据类型和实际的值。
当使用 var 或 let 声明了变量但没有初始 化时,就相当于给变量赋予了 undefined 值
var variable;
console.log(variable); // undefined
console.log('你好' + variable); // 你好undefined
console.log(11 + variable); // NaN
console.log(true + variable); // Na
包含 undefined 值的变量跟未定义变量是有区别的
let message; // 这个变量被声明了,只是值为 undefined
// 确保没有声明过这个变量
// let age
console.log(message); // "undefined"
console.log(age); // 报错
无论是声明还是未声明,typeof 返回的都是字符串"undefined"。
let message; // 这个变量被声明了,只是值为 undefined
// 确保没有声明过这个变量
// let age
console.log(typeof message); // "undefined"
console.log(typeof age); // "undefined"
一个声明变量给 null 值,里面存的值为空(学习对象时,我们继续研究null)
var vari = null;
console.log('你好' + vari); // 你好null
console.log(11 + vari); // 11
console.log(true + vari); // 1
如前所述,永远不必显式地将 变量值设置为 undefined。但 null 不是这样的。任何时候,只要变量要保存对象,而当时又没有那个 对象可保存,就要用 null 来填充该变量。这样就可以保持 null 是空对象指针的语义,并进一步将其 与 undefined 区分开来
let message = null;
let age; //默认为undefined,所以不为空
if (message) {
// 这个块不会执行
}
if (!message) {
// 这个块会执行
}
if (age) {
// 这个块不会执行
}
if (!age) { //因为为undefined,所以age在这里进入
// 这个块会执行
}
符号是原始值,且符号实例是唯一、不可变的。 符号的用途是确保对象属性使用唯一标识符,不会发生属性冲突的危险。
(1)符号的基本用法
符号需要使用 Symbol()函数初始化。因为符号本身是原始类型,所以 typeof 操作符对符号返回 symbol
let sym = Symbol();
console.log(typeof sym); // symbol
调用 Symbol()函数时,也可以传入一个字符串参数作为对符号的描述(description),将来可以通 过这个字符串来调试代码。但是,这个字符串参数与符号定义或标识完全无关
let genericSymbol = Symbol();
let otherGenericSymbol = Symbol();
let fooSymbol = Symbol('foo');
let otherFooSymbol = Symbol('foo');
console.log(genericSymbol == otherGenericSymbol); // false
console.log(fooSymbol == otherFooSymbol); // false
符号没有字面量语法,这也是它们发挥作用的关键。按照规范,你只要创建 Symbol()实例并将其 用作对象的新属性,就可以保证它不会覆盖已有的对象属性,无论是符号属性还是字符串属性
let genericSymbol = Symbol();
console.log(genericSymbol); // Symbol()
let fooSymbol = Symbol('foo');
console.log(fooSymbol); // Symbol(foo);
Symbol()函数不能与 new 关键字一起作为构造函数使用
let myBoolean = new Boolean();
console.log(typeof myBoolean); // "object"
let myString = new String();
console.log(typeof myString); // "object"
let myNumber = new Number();
console.log(typeof myNumber); // "object"
let mySymbol = new Symbol(); // TypeError: Symbol is not a constructor
Symbol 不可以添加属性
let hd = Symbol();
hd.name = "后盾人";
console.log(hd.name);
(2.)Symbol.for()
根据描述获取Symbol,如果不存在则新建一个Symbol
如果运行时的不同部分需要共享和重用符号实例,那么可以用一个字符串作为键,在全局符号注册 表中创建并重用符号。 需要使用 Symbol.for()方法
let fooGlobalSymbol = Symbol.for('foo');
console.log(typeof fooGlobalSymbol); // symbol
第一次使用某个字符串调用时,它会检查全局运 行时注册表,发现不存在对应的符号,于是就会生成一个新符号实例并添加到注册表中。后续使用相同 字符串的调用同样会检查注册表,发现存在与该字符串对应的符号,然后就会返回该符号实例。
let fooGlobalSymbol = Symbol.for('foo'); // 创建新符号
let otherFooGlobalSymbol = Symbol.for('foo'); // 重用已有符号
console.log(fooGlobalSymbol === otherFooGlobalSymbol); // true
即使采用相同的符号描述,在全局注册表中定义的符号跟使用 Symbol()定义的符号也并不等同:
let localSymbol = Symbol('foo');
let globalSymbol = Symbol.for('foo');
console.log(localSymbol === globalSymbol); // false
使用description可以获取传入的描述参数
let hd = Symbol("小林");
console.log(hd.description); //小林
(3)Symbol.keyFor()
还可以使用 Symbol.keyFor()来查询全局注册表,Symbol.keyFor
根据使用Symbol.for
登记的Symbol返回描述,如果找不到返回undefined
// 创建全局符号
let s = Symbol.for('foo');
console.log(Symbol.keyFor(s)); // foo
// 创建普通符号
let s2 = Symbol('bar');
console.log(Symbol.keyFor(s2)); // undefined
如果传给 Symbol.keyFor()的不是符号,则该方法抛出 TypeError:
Symbol.keyFor(123); // TypeError: 123 is not a symbol
(4)对象属性
Symbol 是独一无二的所以可以保证对象属性的唯一。
Symbol 声明和访问使用 []
(变量)形式操作
也不能使用 .
语法因为 .
语法是操作字符串属性的。
下面写法是错误的,会将symbol 当成字符串symbol处理
let symbol = Symbol("小林");
let obj = {
symbol: "hdcms.com"
};
console.log(obj);
正确写法是以[]
变量形式声明和访问
let symbol = Symbol("小林");
let obj = {
[symbol]: "abc"
};
console.log(obj[symbol]); //abc
(5)遍历属性
Symbol 不能使用 for/in
、for/of
遍历操作
let symbol = Symbol("小林");
let obj = {
name: "abc",
[symbol]: "abc"
};
for (const key in obj) {
console.log(key); //name
}
for (const key of Object.keys(obj)) {
console.log(key); //name
}
也可以使用 Reflect.ownKeys(obj)
获取所有属性包括Symbol
for (const key of Reflect.ownKeys(obj)) {
console.log(key);
}
let o = new Object();
//如果没有参数,如上面的例子所示,那么完全可以省略括号(不推荐):
let o = new Object; // 合法,但不推荐
注意typeof在某些情况下返回的结果可能会让人费解,但技术上讲还是正确的。比如,调用typeof null 返回的是"object"。这是因为特殊值 null 被认为是一个对空对象的引用。
对象通过 new 操作符后跟对象类型的名称 来创建。开发者可以通过创建 Object 类型的实例来创建自己的对象,然后再给对象添加属性和方法
let o = new Object();
let o = new Object; // 合法,但不推
console.log(Boolean('')); // false
console.log(Boolean(0)); // false
console.log(Boolean(NaN)); // false
console.log(Boolean(null)); // false
console.log(Boolean(undefined)); // false
console.log(Boolean('小白')); // true
console.log(Boolean(12)); // true
不要直接判断两个浮点数是否相等
(1)前置递增运算符
(2)后置递增运算符
let s1 = "2";
let s2 = "z";
let b = false;
let f = 1.1;
let o = {
valueOf() {
return -1;
}
};
s1++; // 值变成数值 3
s2++; // 值变成 NaN
b++; // 值变成数值 1
f--; // 值变成 0.10000000000000009(因为浮点数不精确)
o--; // 值变成-2
如果将一元加应用到非数值,则会执行与使用 Number()转型函数一样的类型转换:布尔值 false 和 true 转换为 0 和 1,字符串根据特殊规则进行解析,对象会调用它们的 valueOf()和/或 toString() 方法以得到可以转换的值
let s1 = "01";
let s2 = "1.1";
let s3 = "z";
let b = false;
let f = 1.1;
let o = {
valueOf() {
return -1;
}
};
s1 = +s1; // 值变成数值 1
s2 = +s2; // 值变成数值 1.1
s3 = +s3; // 值变成 NaN
b = +b; // 值变成数值 0
f = +f; // 不变,还是 1.1
o = +o; // 值变成数值-1
一元减由一个减号(-)表示,放在变量前头,主要用于把数值变成负值
let s1 = "01";
let s2 = "1.1";
let s3 = "z";
let b = false;
let f = 1.1;
let o = {
valueOf() {
return -1;
}
};
s1 = -s1; // 值变成数值-1
s2 = -s2; // 值变成数值-1.1
s3 = -s3; // 值变成 NaN
b = -b; // 值变成数值 0
f = -f; // 变成-1.1
o = -o; // 值变成数值 1
只要是数值和字符串 比较,字符串就会先被转换为数值,然后进行数值比较。
//因为两个操作数都是字符串,所以会逐个比较它们的字符编码(字符"2"的编码是 50,而字符"3"的编码是 51)。
let result = "23" < "3"; // true
//这次会将字符串"23"转换为数值 23,然后再跟 3 比较
let result = "23" < 3; // false
//因为字符"a"不能转换成任何有意义的数值,所以只能转换为 NaN
let result = "a" < 3; // 因为"a"会转换为 NaN,所以结果是 false
let result1 = NaN < 3; // false
let result2 = NaN >= 3; // false
//在大多数比较的场景中,如果一个值不小于另一个值,那就一定大于或等于它。但在比较 NaN 时,
无论是小于还是大于等于,比较的结果都会返回 false
两边都是true才返回true,否则返回false
两边都为 false 才返回 false,否则都为true
当有多个表达式(值)时,左边的表达式值可以确定结果时,就不再继续运算右边的表达式的值
(1)逻辑与--表达式1 && 表达式2
(2)逻辑或--表达式1 || 表达式2
(3)逻辑中断(短路操作)
用来把数据赋值给变量的运算符。
var age = 10;
age += 5; // 相当于 age = age + 5;
age -= 5; // 相当于 age = age - 5;
age *= 10; // 相当于 age = age * 10;
let num1 = 25; // 二进制 00000000000000000000000000011001
let num2 = ~num1; // 二进制 11111111111111111111111111100110
console.log(num2); // -26
按位与操作在两个位都是 1 时返回 1,在任何一位是 0 时返回 0
按位或操作在至少一位是 1 时返回 1,两位都是 0 时返回 0。
按位异或与按位或的区别是,它只在一位上是 1 的时候返回 1(两位都是 1 或 0,则返回 0)。
let oldValue = 2; // 等于二进制 10
let newValue = oldValue << 5; // 等于二进制 1000000,即十进制 64
let oldValue = 64; // 等于二进制 1000000
let newValue = oldValue >> 5; // 等于二进制 10,即十进制 2
对于正数,无符号右移与 有符号右移结果相同。
let oldValue = 64; // 等于二进制 1000000
let newValue = oldValue >>> 5; // 等于二进制 10,即十进制 2
无符号右移操作符将负数的二进制表示当成正数的二进制表示来处理
let oldValue = -64; // 等于二进制 11111111111111111111111111000000
let newValue = oldValue >>> 5; // 等于十进制 134217726
逻辑非操作符首先将操作数转换为布尔值,然后再对其取反。
console.log(!false); // true
console.log(!"blue"); // false
console.log(!0); // true
console.log(!NaN); // true
console.log(!""); // true
console.log(!12345); // false
逻辑非操作符也可以用于把任意值转换为布尔值。同时使用两个叹号(!!),相当于调用了转型函 数 Boolean()。无论操作数是什么类型,第一个叹号总会返回布尔值。第二个叹号对该布尔值取反, 从而给出变量真正对应的布尔值。结果与对同一个值使用 Boolean()函数是一样的
console.log(!!"blue"); // true
console.log(!!0); // false
console.log(!!NaN); // false
console.log(!!""); // false
console.log(!!12345); // true
逻辑与操作符是一种短路操作符,意思就是如果第一个操作数决定了结果,那么永远不会对第二个 操作数求值。对逻辑与操作符来说,如果第一个操作数是 false,那么无论第二个操作数是什么值,结 果也不可能等于 true。
第一个操作数求值为 true,第二个操作数就不会再被求值了
let found = true;
let result = (found || someUndeclaredVariable); // 不会出错
console.log(result); // 会执行
跟前面的例子一样,变量 someUndeclaredVariable 也没有定义。但是,因为变量 found 的值
为 true,所以逻辑或操作符不会对变量 someUndeclaredVariable 求值,而直接返回 true。假如把
found 的值改为 false,那就会报错了:
let found = false;
let result = (found || someUndeclaredVariable); // 这里会出错
console.log(result); // 不会执行这一行
ECMAScript 7 新增了指数操作符,Math.pow()现在有了自己的操作符**
console.log(Math.pow(3, 2); // 9
console.log(3 ** 2); // 9
console.log(Math.pow(16, 0.5); // 4
console.log(16** 0.5); // 4
指数操作符也有自己的指数赋值操作符**=
let squared = 3;
squared **= 2;
console.log(squared); // 9
let sqrt = 16;
sqrt **= 0.5;
console.log(sqrt); // 4
let result1 = 5 + 5; // 两个数值
console.log(result1); // 10
let result2 = 5 + "5"; // 一个数值和一个字符串
console.log(result2); // "55"
let num1 = 5;
let num2 = 10;
let message = "The sum of 5 and 10 is " + num1 + num2;
console.log(message); // "The sum of 5 and 10 is 510"
如果想真正执行数学计算,然后把结果追加到字符串末尾,只要使用一对括号即可
let num1 = 5;
let num2 = 10;
let message = "The sum of 5 and 10 is " + (num1 + num2);
console.log(message); // "The sum of 5 and 10 is 15"
let result1 = 5 - true; // true 被转换为 1,所以结果是 4
let result2 = NaN - 1; // NaN
let result3 = 5 - 3; // 2
let result4 = 5 - ""; // ""被转换为 0,所以结果是 5
let result5 = 5 - "2"; // "2"被转换为 2,所以结果是 3
let result6 = 5 - null; // null 被转换为 0,所以结果是 5
let result1 = ("55" == 55); // true,转换后相等
let result2 = ("55" === 55); // false,不相等,因为数据类型不同
let result1 = ("55" != 55); // false,转换后相等
let result2 = ("55" !== 55); // true,不相等,因为数据类型不同
null===undefined(false)
variable = boolean_expression ? true_value : false_value;
上面的代码执行了条件赋值操作,即根据条件表达式 boolean_expression 的值决定将哪个值赋 给变量 variable 。如果 boolean_expression 是 true ,则赋值 true_value ;如果 boolean_expression 是 false,则赋值 false_value。
在一条语句中同时声明多个变量是逗号操作符最常用的场景。不过,也可以使用逗号操作符来辅助 赋值。在赋值时使用逗号操作符分隔值,最终会返回表达式中最后一个值
let num = (5, 1, 4, 8, 0); // num 的值为 0
(1)语法结构
(2)执行流程
【案例】
var usrAge = prompt('请输入您的年龄:');
if(usrAge >= 18){
alert('您的年龄合法,欢迎来天际网吧享受学习的乐趣!');
}
(1)语法结构
(2)执行流程
【案例】
if (year % 4 == 0 && year % 100 != 0 || year % 400 == 0) {
alert("这个年份是闰年");
} else { // 剩下的是平年
alert("这个年份是平年");
}
(1)语法结构
(2)执行流程
【案例】
var score = prompt('请您输入分数:');
if (score >= 90) {
alert('宝贝,你是我的骄傲');
} else if (score >= 80) {
alert('宝贝,你已经很出色了');
} else if (score >= 70) {
alert('你要继续加油喽');
} else if (score >= 60) {
alert('孩子,你很危险');
} else {
alert('熊孩子,我不想和你说话,我只想用鞭子和你说话');
【案例】
var time = prompt('请您输入一个 0 ~ 59 之间的一个数字');
// 三元表达式 表达式 ? 表达式1 :表达式2
var result = time < 10 ? '0' + time : time; // 把返回值赋值给一个变量
alert(result);
【案例】
var fruit = prompt('请您输入查询的水果:');
switch (fruit) {
case '苹果':
alert('苹果的价格是 3.5/斤');
break;
case '榴莲':
alert('榴莲的价格是 35/斤');
break;
default:
alert('没有此水果');
}
【案例-ATM取款机】
不过,初始化定义的迭代器变 量在循环执行完成后几乎不可能再用到了。因此,最清晰的写法是使用 let 声明迭代器变量,这样就可 以将这个变量的作用域限定在循环中。
let count = 10;
for (let i = 0; i < count; i++) {
console.log(i);
}
//以上代码在循环开始前定义了变量 i 的初始值为 0。然后求值条件表达式,如果求值结果
//为 true(i < count),则执行循环体。因此循环体也可能不会被执行。如果循环体被执
//行了,则循环后表达式也会执行,以便递增变量 i。for 循环跟下面的 while 循环是一样的:
let count = 10;
let i = 0;
while (i < count) {
console.log(i);
i++
var sum = 0;
for(var i = 1;i <= 100; i++){
sumNum += i;
}
console.log('1-100之间整数的和 = ' + sum);
【案例-求学生成绩】
var num = prompt('请输入班级总的人数:'); // num 班级总的人数
var sum = 0; // 总成绩
var average = 0; // 平均成绩
for (var i = 1; i <= num; i++) {
var score = prompt('请输入第' + i + '个学生的成绩');
sum = sum + parseFloat(score);
}
average = sum / num;
alert('班级总的成绩是:' + sum);
alert('班级总的平均成绩是:' + average);
【案例-一行打印五个星星】
var star = '';
for (var i = 1; i <= 5; i++) {
star += '☆'
}
console.log(star);
【案例--打印五行五列星星】
var star = '';
for (var j = 1; j <= 5; j++) {
for (var i = 1; i <= 5; i++) {
star += '☆'
}
// 每次满 5个星星 就 加一次换行
star += '\n'
}
console.log(star);
【案例--打印n行n列星星】
var row = prompt('请输入您打印几行星星:');
var col = prompt('请输入您打印几列星星:');
var str = '';
for (var i = 1; i <= row; i++) {
for (j = 1; j <= col; j++) {
str += '☆';
}
str += '\n';
}
console.log(str);
【案例--打印倒三角】
var row = prompt('请输入您打印几行星星:');
var col = prompt('请输入您打印几列星星:');
var str = '';
for (var i = 1; i <= row; i++) {
for (j = 1; j <= col; j++) {
str += '☆';
}
str += '\n';
}
console.log(str);
【案例--九九乘法表】
for-in 语句是一种严格的迭代语句,用于枚举对象中的非符号键属性
for (const propName in window) {
document.write(propName);
}
这个例子使用 for-in 循环显示了 BOM 对象 window 的所有属性。每次执行循环,都会给变量 propName 赋予一个 window 对象的属性作为值,直到 window 的所有属性都被枚举一遍。与 for 循环 一样,这里控制语句中的 const 也不是必需的。但为了确保这个局部变量不被修改,推荐使用 const。
1.所有可枚举的属性都会返回一次,但返回的顺序可能会因浏览器而异。
2.如果 for-in 循环要迭代的变量是 null 或 undefined,则不执行循环体。
var obj = {a:1, b:2, c:3};
for (var prop in obj) {
console.log("obj." + prop + " = " + obj[prop]);
}
// Output:
// "obj.a = 1"
// "obj.b = 2"
// "obj.c = 3"
for-of 语句是一种严格的迭代语句,用于遍历可迭代对象的元素
for (const el of [2,4,6,8]) {
document.write(el);
}
与 for 循环一样,这里控制语句中的 const 也不是必需的。但为了确保 这个局部变量不被修改,推荐使用 const。
1.for-in只是获取数组的索引;而for-of会获取数组的值
2.for-in会遍历对象的整个原型链,性能差;而for-of只遍历当前对象,不会遍历原型链
3.对于数组的遍历,for-in会返回数组中所有可枚举的属性(包括原型链上可枚举的属性);for-of只返回数组的下标对应的属性值
4.for-of适用遍历数组/字符串/map/set等有迭代器对象的集合,但是不能遍历普通对象(obj is not iterable)
for-in
let arr = [1, 2, 3, 4, 5]
Array.prototype.id = 123
arr.name = 'Lisa'
for (let index in arr) {
if (index == 2) {
}
console.log(index, arr[index]);//遍历[1,2,3,4,5,Lisa,123]
}
for-of
let arr = [1, 2, 3, 4, 5]
Array.prototype.id = 321
arr.name = 'Lisa'
for (let value of arr) {
console.log(value);//只能拿到[1,2,3,4,5]
}
【案例】
do {
var love = prompt('你爱我吗?');
} while (love != '我爱你')
alert('登录成功');
跳出本次循环,继续下一次循环
跳出整个循环结构
break 语句用于立即退 出循环,强制执行循环后的下一条语句。(退出当前循环)
continue 语句也用于立即退出循环,但会再次从循环顶部 开始执行。
let num = 0;
for (let i = 1; i < 10; i++) {
if (i % 5 == 0) {
break;
}
num++;
}
console.log(num); // 4
而在循环体内,有一个 if 语句用于检查 i 能否被 5 整除(使用取模操作符)。如果是,则执行 break 语句,退出循环。变量 num 的初始值为 0, 表示循环在退出前执行了多少次。当 break 语句执行后,下一行执行的代码是 console.log(num), 显示 4。之所以循环执行了 4 次,是因为当 i 等于 5 时,break 语句会导致循环退出,该次循环不会执 行递增 num 的代码。
let num = 0;
for (let i = 1; i < 10; i++) {
if (i % 5 == 0) {
continue;
}
num++;
}
console.log(num); // 8
with 语句的用途是将代码作用域设置为特定的对象
with 语句的原本用意是为逐级的对象访问提供命名空间式的速写方式. 也就是在指定的代码区域, 直接通过节点名称调用对象。
with 通常被当做重复引用同一个对象中的多个属性的快捷方式,可以不需要重复引用对象本身。
比如,目前现在有一个这样的对象:
var obj = {
a: 1,
b: 2,
c: 3
};
如果想要改变 obj 中每一项的值,一般写法可能会是这样:
// 重复写了3次的“obj”
obj.a = 2;
obj.b = 3;
obj.c = 4;
而用了 with 的写法,会有一个简单的快捷方式
with (obj) {
a = 3;
b = 4;
c = 5;
}
switch (expression) {
case value1:
statement
break;
case value2:
statement
break;
case value3:
statement
break;
case value4:
statement
break;
default:
statement
}
这里的每个 case(条件/分支)相当于:“如果表达式等于后面的值,则执行下面的语句。”break 关键字会导致代码执行跳出 switch 语句。如果没有 break,则代码会继续匹配下一个条件。default 关键字用于在任何条件都没有满足时指定默认执行的语句(相当于 else 语句)。
1.switch 语句可以用于所有数据类型(在很多语言中,它只能用于数值),因此可以使用字符串甚至对象。
2.条件的值不需要是常量,也可以是变量或表达式。
switch ("hello world") {
case "hello" + " world":
console.log("Greeting was found.");
break;
case "goodbye":
console.log("Closing was found.");
break;
default:
console.log("Unexpected message was found.");
}
switch 语句在比较每个条件的值时会使用全等操作符,因此不会强制转换数据类 型(比如,字符串"10"不等于数值 10)
【案例-数组求和及平均值】
【案例-数组的最大值】
【案例-数组转换为分割字符串】
// 1. 新增数组元素 修改length长度
var arr = ['red', 'green', 'blue'];
console.log(arr.length);
arr.length = 5; // 把我们数组的长度修改为了 5 里面应该有5个元素
console.log(arr);
console.log(arr[3]); // undefined
console.log(arr[4]); // undefined
// 2. 新增数组元素 修改索引号 追加数组元素
var arr1 = ['red', 'green', 'blue'];
arr1[3] = 'pink';
console.log(arr1);
arr1[4] = 'hotpink';
console.log(arr1);
arr1[0] = 'yellow'; // 这里是替换原来的数组元素
console.log(arr1);
arr1 = '有点意思';
console.log(arr1); // 不要直接给 数组名赋值 否则里面的数组元素都没有了
【案例-删除指定数组元素】
【案例-翻转数组】
【复习交换两个变量】
【案例--冒泡排序】
【案例--利用函数计算1-100之间累加和】
【案例--利用函数求任意两个数的和】
【案例--利用函数求任意一个数组中的最大值】
【案例--创建一个函数,实现两个数之间的加减乘除运算,并将结果返回】
1.return是将要返回的东西进行返回,return后面的句子不会执行
2.return只能返回一个值,只能返回最后一个
3.我们的函数如果有return 则返回的是 return 后面的值,如果函数么有 return 则返回undefined
当不确定传入多少个参数的时候,就使用arguments
只有函数才可以使用arguments,而且是每个函数都内置好了这个arguments
【案例--利用函数求任意个数的最大值】
调用函数的代码和声明函数的代码顺序无所谓
1.注意 如果在函数内部 没有声明直接赋值的变量也属于全局变量
2.函数的形参也可以看做是局部变量
3. 从执行效率来看全局变量和局部变量
(1) 全局变量只有浏览器关闭的时候才会销毁,比较占内存资源
(2) 局部变量 当我们程序执行完毕就会销毁, 比较节约内存资源
1. 我们js引擎运行js 分为两步: 预解析 代码执行
// (1). 预解析 js引擎会把js 里面所有的 var 还有 function 提升到当前作用域的最前面
// (2). 代码执行 按照代码书写的顺序从上往下执行
2. 预解析分为 变量预解析(变量提升) 和 函数预解析(函数提升)
// (1) 变量提升 就是把所有的变量声明提升到当前的作用域最前面 不提升赋值操作
// (2) 函数提升 就是把所有的函数声明提升到当前作用域的最前面 不调用函数
变量、属性、函数、方法总结
MDN Web Docs (mozilla.org)
【案例-封装自己的数学对象】
【案例--猜数字游戏】
使用时需要先实例化(先new 一个对象才可以使用)
创建的对象将保存当前日期和时间:ECMAScript 为此提供了两个辅助方法:Date.parse()和 Date.UTC()
//比如,要创建一个表示“2019 年 5 月 23 日”的日期对象,可以使用以下代码:
let someDate = new Date(Date.parse("May 23, 2019"));
//如果直接把表示日期的字
//符串传给 Date 构造函数,那么 Date 会在后台调用 Date.parse()。
//与上面是等价的:
let someDate = new Date("May 23, 2019");
ECMAScript 还提供了 Date.now()方法,返回表示方法执行时日期和时间的毫秒数。
// 起始时间
let start = Date.now();
// 调用函数
doSomething();
// 结束时间
let stop = Date.now(),
result = stop - start;
Date 类型重写了 toLocaleString()、toString()和 valueOf()方法。
Date 类型的 valueOf()方法根本就不返回字符串,这个方法被重写后返回的是日期的毫秒表示。
let date1 = new Date(2019, 0, 1); // 2019 年 1 月 1 日
let date2 = new Date(2019, 1, 1); // 2019 年 2 月 1 日
console.log(date1 < date2); // true
console.log(date1 > date2); // false
添加元素--push()、unshift()
删除元素--pop()、shift()
【案例: 筛选数组】
【案例: 数组去重】
【案例:返回字符位置】
【案例-统计出现最大的字符和次数】
// 1. 替换字符 replace('被替换的字符', '替换为的字符') 它只会替换第一个字符
var str = 'andyandy';
console.log(str.replace('a', 'b'));
// 有一个字符串 'abcoefoxyozzopp' 要求把里面所有的 o 替换为 *
var str1 = 'abcoefoxyozzopp';
while (str1.indexOf('o') !== -1) {
str1 = str1.replace('o', '*');
}
console.log(str1);
通过 RegExp 类型支持正则表达式:let expression = /pattern/flags;
g:全局模式,表示查找字符串的全部内容,而不是找到第一个匹配的内容就结束。
i:不区分大小写,表示在查找匹配时忽略 pattern 和字符串的大小写。
m:多行模式,表示查找到一行文本末尾时会继续查找。
y:粘附模式,表示只查找从 lastIndex 开始及之后的字符串。
u:Unicode 模式,启用 Unicode 匹配。
s:dotAll 模式,表示元字符.匹配任何字符(包括\n 或\r)。
let text = "this has been a short summer";
let pattern = /(.)hort/g;
if (pattern.test(text)) {
console.log(RegExp.input); // this has been a short summer
console.log(RegExp.leftContext); // this has been a
console.log(RegExp.rightContext); // summer
console.log(RegExp.lastMatch); // short
console.log(RegExp.lastParen); // s
}
函数的形参也可以看做是一个变量,当我们把一个值类型变量作为参数传给函数的形参时,其实是把比哪里在栈空间里的值复制了一份给形参,在方法内部对形参做任何改变,都不会影响到外部变量。
函数的形参可以看作是一个变量。当我们把引用类型变量传给形参时,其实把变量在栈空间里保存的堆地址复制给形参,形参和实参其实保存的是同一个堆地址,所以操作的是同一个对象。
ECMAScript 变量可以包含两种不同类型的数据:原始值和引用值。
原始值(primitive value)就是 最简单的数据
----->保存原始值的变量是按值(by value)访问的,因为我们操作的就是存储在变量中的实际值。
引用值(reference value)则是由多个值构成的对象
--->引用值是保存在内存中的对象。与其他语言不同,JavaScript 不允许直接访问内存位置,因此也就 不能直接操作对象所在的内存空间。在操作对象时,实际上操作的是对该对象的引用(reference)而非 实际的对象本身。为此,保存引用值的变量是按引用(by reference)访问的。
对于引用值而言,可以随时添加、修改和删除其属性 和方法。
let person = new Object();
person.name = "Nicholas";
console.log(person.name); // "Nicholas"
原始值不能有属性,尽管尝试给原始值添加属性不会报错。
let name = "Nicholas";
name.age = 27;
console.log(name.age); // undefined
原始值:两个变量可以独立使用,互不干扰
在通过变量把一个原始值赋值 到另一个变量时,原始值会被复制到新变量的位置。
let num1 = 5;
let num2 = num1;
//这个值跟存储在num1 中的 5 是完全独立的,因为它是那个值的副本。
引用值:两个变量实际 上指向同一个对象
在把引用值从一个变量赋给另一个变量时,存储在变量中的值也会被复制到新变量所在的位置。区 别在于,这里复制的值实际上是一个指针,它指向存储在堆内存中的对象。
let obj1 = new Object();
let obj2 = obj1;
obj1.name = "Nicholas";
console.log(obj2.name); // "Nicholas"
变量 obj1 保存了一个新对象的实例。然后,这个值被复制到 obj2,此时两个变 量都指向了同一个对象。在给 obj1 创建属性 name 并赋值后,通过 obj2 也可以访问这个属性,因为 它们都指向同一个对象。
函数外的值会被复制到函数内部的参数 中,就像从一个变量复制到另一个变量一样。如果是原始值,那么就跟原始值变量的复制一样,如果是 引用值,那么就跟引用值变量的复制一样。
在按值传递参数时,值会被复制到一个局部变量(即一个命名参数,或者用 ECMAScript 的话说, 就是 arguments 对象中的一个槽位)。
function addTen(num) {
num += 10;
return num;
}
let count = 20;
let result = addTen(count);
console.log(count); // 20,没有变化
console.log(result); // 30
在按引用传递参数时,值在内存中的位置会被保存在一个局部变 量,这意味着对本地变量的修改会反映到函数外部。(这在 ECMAScript 中是不可能的。)
function setName(obj) {
obj.name = "Nicholas";
}
let person = new Object();
setName(person);
console.log(person.name); // "Nicholas"
对象并把它保存在变量 person 中。然后,这个对象被传给 setName() 方法,并被复制到参数 obj 中。在函数内部,obj 和 person 都指向同一个对象。结果就是,即使对象 是按值传进函数的,obj 也会通过引用访问对象。当函数内部给 obj 设置了 name 属性时,函数外部的 对象也会反映这个变化,因为 obj 指向的对象保存在全局作用域的堆内存上。
function setName(obj) {
obj.name = "Nicholas";
obj = new Object();
obj.name = "Greg";
}
let person = new Object();
setName(person);
console.log(person.name); // "Nicholas"
如果值是对象或 null,那么 typeof 返回"object",
let s = "Nicholas";
let b = true;
let i = 22;
let u;
let n = null;
let o = new Object();
console.log(typeof s); // string
console.log(typeof i); // number
console.log(typeof b); // boolean
console.log(typeof u); // undefined
console.log(typeof n); // object
console.log(typeof o); // object
所有引用值都是 Object 的实例,因此通过 instanceof 操作符检测任何引用值和 Object 构造函数都会返回 true。类似地,如果用 instanceof 检测原始值,则始终会返回 false, 因为原始值不是对象。
在浏览器中,全局上下文就是我们常说的 window 对象,因此所有通过 var 定 义的全局变量和函数都会成为 window 对象的属性和方法。使用 let 和 const 的顶级声明不会定义在全变 局上下文中,但在作用域链解析上效果是一样的。
var color = "blue";
function changeColor() {
let anotherColor = "red";
function swapColors() {
let tempColor = anotherColor;
anotherColor = color;
color = tempColor;
// 这里可以访问 color、anotherColor 和 tempColor
}
// 这里可以访问 color 和 anotherColor,但访问不到 tempColor
swapColors();
}
// 这里只能访问 color
changeColor();
以上代码涉及 3 个上下文:全局上下文、changeColor()的局部上下文和 swapColors()的局部 上下文。全局上下文中有一个变量 color 和一个函数 changeColor()。changeColor()的局部上下文中 有一个变量 anotherColor 和一个函数 swapColors(),但在这里可以访问全局上下文中的变量 color。 swapColors()的局部上下文中有一个变量 tempColor,只能在这个上下文中访问到。全局上下文和 changeColor()的局部上下文都无法访问到 tempColor。而在 swapColors()中则可以访问另外两个 上下文中的变量,因为它们都是父上下文。
1.使用var的函数作用域声明
function add(num1, num2) {
var sum = num1 + num2;
return sum;
}
let result = add(10, 20); // 30
console.log(sum); // 报错:sum 在这里不是有效变量
如果变量未经声明就被初始化了, 那么它就会自动被添加到全局上下文
function add(num1, num2) {
sum = num1 + num2;
return sum;
}
let result = add(10, 20); // 30
console.log(sum); // 30
var 声明会被拿到函数或全局作用域的顶部,位于作用域中所有代码之前。这个现象叫作“提升” (hoisting)。
var name = "Jake";
// 等价于:
name = 'Jake';
var name;
下面是两个等价的函数:
function fn1() {
var name = 'Jake';
}
// 等价于:
function fn2() {
var name;
name = 'Jake';
}
通过在声明之前打印变量,可以验证变量会被提升。声明的提升意味着会输出 undefined 而不是 Reference Error:
console.log(name); // undefined
var name = 'Jake';
function() {
console.log(name); // undefined
var name = 'Jake';
}
2. 使用 let 的块级作用域声明
块 级作用域由最近的一对包含花括号{}界定。换句话说,if 块、while 块、function 块,甚至连单独 的块也是 let 声明变量的作用域
if (true) {
let a;
}
console.log(a); // ReferenceError: a 没有定义
while (true) {
let b;
}
console.log(b); // ReferenceError: b 没有定义
function foo() {
let c;
}
console.log(c); // ReferenceError: c 没有定义
// 这没什么可奇怪的
// var 声明也会导致报错
// 这不是对象字面量,而是一个独立的块
// JavaScript 解释器会根据其中内容识别出它来
{
let d;
}
console.log(d); // ReferenceError: d 没有定义
let 与 var 的另一个不同之处是在同一作用域内不能声明两次。重复的 var 声明会被忽略,而重 复的 let 声明会抛出 SyntaxError。
var a;
var a;
// 不会报错
{
let b;
let b;
}
// SyntaxError: 标识符 b 已经声明过了
let 的行为非常适合在循环中声明迭代变量。使用 var 声明的迭代变量会泄漏到循环外部,这种情 况应该避免。
for (var i = 0; i < 10; ++i) {}
console.log(i); // 10
for (let j = 0; j < 10; ++j) {}
console.log(j); // ReferenceError: j 没有定义
3. 使用 const 的常量声明
使用 const 声明的变量必须同时初始化为某个值。 一经声明,在其生命周期的任何时候都不能再重新赋予新值。
const a; // SyntaxError: 常量声明时没有初始化
const b = 3;
console.log(b); // 3
b = 4; // TypeError: 给常量赋值
const 除了要遵循以上规则,其他方面与 let 声明是一样的:
if (true) {
const a = 0;
}
console.log(a); // ReferenceError: a 没有定义
while (true) {
const b = 1;
}
console.log(b); // ReferenceError: b 没有定义
function foo() {
const c = 2;
}
console.log(c); // ReferenceError: c 没有定义
{
const d = 3;
}
console.log(d); // ReferenceError: d 没有定义
const 声明只应用到顶级原语或者对象。换句话说,赋值为对象的 const 变量不能再被重新赋值 为其他引用值,但对象的键则不受限制。
const o1 = {};
o1 = {}; // TypeError: 给常量赋值
const o2 = {};
o2.name = 'Jake';
console.log(o2.name); // 'Jake'
盒子1
盒子2
2019-9-9
- 知否知否,应是等你好久11
- 知否知否,应是等你好久11
- 知否知否,应是等你好久11
- 知否知否,应是等你好久11
- 生僻字
- 生僻字
- 生僻字
- 生僻字
盒子1
盒子2
- 生僻字
- 生僻字
- 生僻字
- 生僻字
123
【案例: 点击按钮弹出警示框】
var btn = document.getElementById('btn');
btn.onclick = function() {
alert('你好吗');
};
某个时间
1123
前面的位置
//永远都只能追加操作,且只能位置前
document.write('Hello World')
document.write('你好
')
//innerHTML属性
box.innerHTML='前端程序员
'
我是文字
123
上午好
我们可以通过 JS 修改元素的大小、颜色、位置等样式。
文本
淘宝二维码
×




代码
名称
最新公布净值
累计净值
前单位净值
净值增长率
003526
农银金穗3个月定期开放债券
1.075
1.079
1.074
+0.047%
003526
农银金穗3个月定期开放债券
1.075
1.079
1.074
+0.047%
003526
农银金穗3个月定期开放债券
1.075
1.079
1.074
+0.047%
003526
农银金穗3个月定期开放债券
1.075
1.079
1.074
+0.047%
003526
农银金穗3个月定期开放债券
1.075
1.079
1.074
+0.047%
003526
农银金穗3个月定期开放债券
1.075
1.079
1.074
+0.047%
商品
价钱
iPhone8
8000
iPad Pro
5000
iPad Air
2000
Apple Watch
2000
【 案例:tab 栏切换(重点案例)】
- 商品介绍
- 规格与包装
- 售后保障
- 商品评价(50000)
- 手机社区
商品介绍模块内容
规格与包装模块内容
售后保障模块内容
商品评价(50000)模块内容
手机社区模块内容
我是div
我是span
- 我是li
- 我是li
- 我是li
- 我是li
×
我是div
我是span
- 我是li
- 我是li
- 我是li
- 我是li
×
(1)parentNode.childNodes(标准)--一般不用这个(因为包括其他元素)
(2)parentNode.children(非标准)--主要用这个(因为直接获得相要的元素)
我是div
我是span
- 我是li
- 我是li
- 我是li
- 我是li
- 我是li
- 我是li
- 我是li
- 我是li
×
(3)parentNode.firstChild--一般不用这个(因为包括其他元素)
firstChild 返回第一个子节点,找不到则返回null。同样,也是包含所有的节点。
(4)parentNode.lastChild--一般不用这个(因为包括其他元素)
lastChild 返回最后一个子节点,找不到则返回null。同样,也是包含所有的节点。
(5). parentNode.firstElementChild--一般不用(因为i9才支持)
firstElementChild 返回第一个子元素节点,找不到则返回null。
(6). parentNode.lastElementChild--一般不用(因为i9才支持)
lastElementChild 返回最后一个子元素节点,找不到则返回null。
(7) 实际开发中, 既没有兼容性问题又返回第一个子元素
console.log(ol.children[0]);
console.log(ol.children[ol.children.length - 1]);
- 我是li1
- 我是li2
- 我是li3
- 我是li4
- 我是li5
【案例:下拉菜单】
1. node.nextSibling--一般不用这个(因为包括其他元素)
nextSibling 返回当前元素的下一个兄弟元素节点,找不到则返回null。同样,也是包含所有的节点。
2. node.previousSibling--一般不用这个(因为包括其他元素)
previousSibling 返回当前元素上一个兄弟元素节点,找不到则返回null。同样,也是包含所有的节点
3. node.nextElementSibling--主要用这个(因为直接获得相要的元素)
nextElementSibling 返回当前元素下一个兄弟元素节点,找不到则返回null。
4. node.previousElementSibling--主要用这个(因为直接获得相要的元素)
previousElementSibling 返回当前元素上一个兄弟节点,找不到则返回null
我是div
我是span
document.createElement('tagName')
document.createElement() 方法创建由 tagName 指定的 HTML 元素。因为这些元素原先不存在,
是根据我们的需求动态生成的,所以我们也称为动态创建元素节点。
1. node(父亲).appendChild(child)
node.appendChild() 方法将一个节点添加到指定父节点的子节点列表末尾。类似于 CSS 里面的
after 伪元素。
2. node.insertBefore(child, 指定元素)
node.insertBefore() 方法将一个节点添加到父节点的指定子节点前面。类似于 CSS 里面的 before
伪元素
- 123
【案例:简单版发布留言案例】
node.removeChild(child)
node.removeChild() 方法从 DOM 中删除一个子节点,返回删除的节点。
- 熊大
- 熊二
- 光头强
【案例:删除留言案例】
阻止链接跳转:删除
node.cloneNode()
node.cloneNode() 方法返回调用该方法的节点的一个副本。 也称为克隆节点/拷贝节点
5.6 复制节点(克隆节点)
注意:
1. 如果括号参数为空或者为 false ,则是浅拷贝,即只克隆复制节点本身,不克隆里面的子节点(不复制内容)。
2. 如果括号参数为 true ,则是深度拷贝,会复制节点本身以及里面所有的子节点。
- 1111
- 2
- 3
【案例:动态生成表格】
姓名
科目
成绩
操作
document.write()--如果页面文档流加载完毕,再调用这句话会导致页面重绘
1. document.write() 创建元素 如果页面文档流加载完毕,再调用这句话会导致页面重绘
var btn = document.querySelector('button');
btn.onclick = function() {
document.write('123');
}
element.innerHTML
document.creatElement()
注意点:
abc
element.innerHTML 与 document.creatElement()的效率对比
效率测试
1. DOM提供的API 方法: getElementById、getElementsByTagName 古老用法 不太推荐
2. H5提供的新方法: querySelector、querySelectorAll 提倡
3. 利用节点操作获取元素: 父(parentNode)、子(children)、兄(previousElementSibling、
nextElementSibling) 提倡
1. setAttribute:设置dom的属性值
2. getAttribute:得到dom的属性值
3. removeAttribute移除属性
给元素注册事件, 采取 事件源.事件类型 = 事件处理程序
offset 翻译过来就是偏移量, 我们使用 offset 系列相关属性可以动态的得到该元素的位置(偏移)、大小等。
【案例:获取鼠标在盒子内的坐标】
【案例:模态框拖拽】