认识JS
表单动态验证、网页特效、服务端开发(Node.js)、桌面程序(Electron)、App(Cordova)、控制硬件-物联网(Ruff)、游戏开发(cocos2d-js)
JS是一种
程序化、 面向对象(oop)、函数式编程(FP) 的语言
特点: 动态类型、单线程(一次只能做一件事)和非阻塞事件循环并发模型(长时间运行的任务放在后台,运行完成后加入主线程)
JS引擎和运行时(工作原理)
即时编译,立即转换成机器代码 然后立即执行
浏览器执行JS
浏览器分为两部分:渲染引擎(解析HTML和CSS)和 JS 引擎(逐行解释每一句源码形成抽象语法树AST,编译后形成机器代码,之后进行优化并重新编译)。
JS组成
ECMAScript:Javascript语法 规定了JS编程语法和基础核心知识
DOM 页面文档对象模型 :
BOM浏览器对象模型
书写位置
1.行内式 js
<input type="button" value="唐伯虎" οnclick="alert('...')”>
2.内嵌式js
3.引入外部js
快捷键
单行注释 ctrl+/ ,多行注释 shift+alt+a, 多行注释 vscode中修改
输出语言
浏览器弹出警示框 alert(msg) / console.log(msg) / prompt(info)
let和const
块作用域,在相同的作用域,或在相同的块中,通过 let
重新声明一个 var
变量是不允许的;通过 let
重新声明一个 let
变量是不允许的;在相同的作用域,或在相同的块中,通过 var
重新声明一个 let
变量是不允许的;在不同的作用域或块中,通过 let
重新声明变量是允许的;
const PI=3.1415926; 后就不能更改常量原始值 但是可以更改常量对象的属性
const car={type="porsche", model="911", color="Black"}
car.color = "white";
car.owner="Bill";
JavaScript数据类型
字符串、数字、布尔、对象Object、函数
typeof | 返回变量的类型。 |
---|---|
instanceof | 返回 true,如果对象是对象类型的实例。 |
三种对象类型
对象、日期、数组
两种不能包含值的数据类型
null 、 undefined
**constructor**
属性返回所有 JavaScript 变量的构造器函数。
数字型转变字符串
1、 变量.tostring() 2、 String(变量) 3 、数字变量+’ ‘
字符型转换为数字型
1、 parseInt(变量)--输出整数、去掉单位 但是parseInt('rem120px') :NaN
2、 parseFloat() 不会去掉单位
3、利用Number(变量)转换
4、利用算数运算隐式转换 利用+ -/ * 比如 ’12‘-0
运算符
num=10 ++num +10 = 21 //先自加再返回值 num++ +10 = 20 //算完num再+1
实际开发中 用后置 单独成行
比较运算符
===:值和数据类型完全一致
console.log(18=='18') //true 默认转换数据类型 会把字符串型数据转换为数字型
逻辑运算符
&& || !
逻辑与短路中断:后面不再执行
除了0 ‘ ’ null undefined NaN 之外都为真
console.log(123 && 456) // 456 表达式1为真 返回表达式2;如果表达式1为 假则返回表达式1
console.log(0&&1+2&&456*5678) // 0 以后都不再运算
逻辑或短路
表达式1为真 返回表达式1; 表达式1为假,返回表达式2
var num=0;
console.log(123 || num++); //123
console.log(num) //0 因为中断 num++没有运行到
运算符优先级:
先*/后+- 先&&后||
流程控制
三元表达式:条件表达式?表达式1:表达式2 //表达式为真 返回值为表达式1 表达式为假 返回表达式2
switch: 适合针对特定值的多分支语句 实现多选1
数组
-
利用new创建数组
var arr = new Array();
-
利用数组字面量创建数组
var 数组名 = [1, 2, 'pink', true]
3.索引 arr[0] 是第一个元素
4.迭代
forEach()、map()、 filter()、 reduce():在每个数组元素上运行函数,以生成(减少它)单个值、
对象
对象也是变量,但包含很多值 以名称:值对方式书写
JavaScript 对象是被命名值的容器 值对被称为属性
const janas={
firstname : 'Jonas',
lastName:' Sch',
}
调用对象的属性: 对象名.属性 / 对象名['属性']
访问对象方法: 对象名.方法()
对象方法
方法是可以在对象上执行的动作。
对象属性可以是原始值、其他对象以及函数。
对象方法是包含函数定义的对象属性。
const janas={
firstname : 'Jonas',
lastName:' Sch',
calcAge: function(birthYear){
return 2037-birthYear;
}
}
调用: jonas.calcAge(1991);
jonas['calcAge'] (1991)
javascript对象是易变的
var person = {firstName:"Bill", lastName:"Gates", age:62, eyeColor:"blue"}
var x = person;
x.age = 10; // 这将同时改变 both x.age 和 person.age
显示对象属性
-
按名称显示对象属性
person.name
-
循环显示对象属性
for(let x in person){
txt += person[x]+" "
}
-
使用 Object.values() 显示对象
通过使用
Object.values()
,任何 JavaScript 对象都可以被转换为数组:
const person = {
name: "Bill",
age: 19,
city: "Seattle"
};
const myArray = Object.values(person);
document.getElementById("demo").innerHTML = myArray;//Bill,19,Seattle
· 使用 JSON.stringify() 显示对象
任何 JavaScript 对象都可以使用 JavaScript 函数 JSON.stringify()
进行字符串化(转换为字符串)
const person = {
name: "Bill",
age: 19,
city: "Seattle"
};
let myString = JSON.stringify(person);//{"name":"Bill","age":19,"city":"Seattle"}
对象访问器
get 和 set
有get 可以属性形式访问
-
它提供了更简洁的语法
-
它允许属性和方法的语法相同
-
它可以确保更好的数据质量
-
有利于后台工作
对象构造器(构造函数)
因为我们创建对象只能创建一次,那么为了不再重复代码,就使用构造函数
构造函数名首字母必须大写!!构造函数不需要return!!
在构造器函数中,this
是没有值的。它是新对象的替代物。 当一个新对象被创建时,this 的值会成为这个新对象。
function Person(first, last, age, eye) {
this.firstName = first;
this.lastName = last;
this.age = age;
this.eyeColor = eye;
}
//new创建相同类型的对象
var myFather = new Person("Bill","Gates",62,"blue");
var myMother = new Person("Steve","Jobs",56,"green");
//为新对象添加属性 只有新对象 有这个属性 但是无法为对象构造器添加新属性
myFather.nationality = "English";
//与向已有对象添加新方法不同,您无法为对象构造器添加新方法。
//必须在构造器函数内部向一个对象添加方法:
function Person(firstName, lastName, age, eyeColor) {
this.firstName = firstName;
this.lastName = lastName;
this.age = age;
this.eyeColor = eyeColor;
this.changeName = function (name) {
this.lastName = name;
};
}
Map
JavaScript 对象 vs Map
JavaScript 对象和 Map 之间的差异:
对象 | Map | |
---|---|---|
Size | 对象没有 size 属性 | Maps 有 size 属性 |
键类型 | 对象键必须是字符串(或符号) | Map 键可以是任何数据类型 |
键顺序 | 对象键没有很好地排序 | Map 键按插入排序 |
默认 | 对象有默认键 | Map 没有默认键 |
Set
Set 是唯一值的集合。
每个值在 Set 中只能出现一次。
一个 Set 可以容纳任何数据类型的任何值
函数
函数调用
1.以函数形式调用函数
function myFunction(a, b) {
return a * b;
}
myFunction(10, 2); // 将返回 20
2.作为方法调用对象
var myObject = {
firstName:"Bill",
lastName: "Gates",
fullName: function () {
return this.firstName + " " + this.lastName;
}
}
myObject.fullName();
3.通过函数构造器来调用函数
如果函数调用的前面是 new
关键字,那么这是一个构造函数调用。
它看起来像你创建一个新的函数,但由于 JavaScript 函数是对象,你实际上创建一个新对象
// 这是函数构造器:
function myFunction(arg1, arg2) {
this.firstName = arg1;
this.lastName = arg2;
}
// 创建了一个新对象:
var x = new myFunction("Bill", "Gates");
x.firstName; // 会返回 "Bill"
call()
使用 call()
方法,
var person = {
fullName: function() {
return this.firstName + " " + this.lastName;
}
}
var person1 = {
firstName:"Bill",
lastName: "Gates",
}
var person2 = {
firstName:"Steve",
lastName: "Jobs",
}
person.fullName.call(person1); // 将返回 "Bill Gates"
JS闭包
全局变量通过闭包实现局部(私有)
计数器被这个匿名函数的作用域保护,并且只能使用 add 函数来修改。
闭包指的是有权访问父作用域的函数,即使在父函数关闭之后。
var add = (function () {
var counter = 0;
return function () {return counter += 1;}
})();
add();
add();
add();
// 计数器目前是 3
JS类
类不是对象,是对象的模板
class Car {
constructor(name, year) {
this.name = name;
this.year = year;
}
}
类方法
class Car {
constructor(name, year) {
this.name = name;
this.year = year;
}
age() {
let date = new Date();
return date.getFullYear() - this.year;
}
}
let myCar = new Car("Ford", 2014);
document.getElementById("demo").innerHTML =
"My car is " + myCar.age() + " years old.";
作用域
先查找当前范围 找不到再寻找全局范围
块(ES6) 只能使用 let 和 const
变量提升:可以看JavaScript变量提升详解_大前端工程师的博客-CSDN博客_javascript 变量提升
1.var 变量声明提前 但是赋值不会提前。
2.function 是函数变量和赋值同时提升。
3.局部变量偷偷赋值:
我们在console.log(a)时候,js沿着作用域链在括号内寻找,找到了a,发现是undefined,但是js不甘心,继续沿着作用域链向上检索,终于搜寻到外面的形参声明赋值,然后输出10 也就是说作用域链向上查找不是查到声明就完的,如果js发现它是undefined的话还会继续向上找
4.箭头函数:箭头函数仅仅只会变量提升而已,因为()=>function关键字是不一样的,function是声明函数的关键字,()=>只是一个赋值的右值而已
this关键字
this指向问题,一般情况下this最终指向的是那个调用它的对象
1.全局作用域或者普通股函数中this指向全局对象window(定时器里this也是指向window)
2.方法调用中谁调用this指向谁
3.构造函数中this指向构造函数的实例
DOM
文档对象模型 通过DOM接口可以改变页面样式 结构 和内容
DOM树
一个页面就是一个文档 DOM中使用document表示
页面中所有标签都是元素,DOM中使用element表示
节点 页面中所有内容都是节点(标签、属性、文本、注释),DOM中使用node表示
DOM把以上内容都看作是对象
//console.dir() 打印返回的元素对象 可以更好的查看里面的属性和方法
1.getElementById 获取html的id元素
2.getElementsByTagName('li') 获取 某类标签元素 返回某类标签的集合
如果页面中只有一个li 返回的还是伪数组形式
【重要】
如果获取ol 里面的 li
通过获取某个父元素内部所有指定标签名的子元素
element.getElementsByTagName('标签名')
父元素必须是单个对象 必须指明是哪个对象,获取的时候不包括父元素自己
var ol = document.getElementsByTagName('ol') //[ol]
console.log(ol[0].getElementsByTagName('li')) //指明第一个ol
3.HTML5新增获取元素方式
通过类名获取元素
document.getElementsByClassName('box')
document.querySelector('.box') //返回指定选择器的第一个元素对象
document.querySelector('#box') //为ID时
document.querySelectorAll('.box') //有两个box时,选择所有 返回指定选择器的所有元素对象集合
4.获取body
document.body //返回body元素对象
document.documentElement //返回html元素对象
JS事件
事件源、事件类型、事件处理程序
(1)事件源:事件被触发的对象 谁 按钮
var btn=document.getElementById('btn')
(2)事件类型 如何触发 什么事件 比如鼠标点击还鼠标经过还是 键盘按下
(3)事件处理程序 通过一个函数赋值的方式 完成
btn.onclick = function(){
alert('点秋香');
}
改变元素内容
element.innerText 会去除html标签 空格和换行
elemenet.innerHTML 不会去除html标签 保留空格和换行
这两个属性是可读写的
表单修改内容 用 input.value=' ';
点击一次后被禁用 用input/this.disabled=true;
获取属性值
div.id / div.getAttribute('demo')
有时我们会有自定义属性,比如index 那么使用getAttribute比较方便
设置元素属性值
div.id="demo1" / div.setAttribute("属性","值")
😊H5自定义属性
为了保存并使用数据 有些数据只在页面中用到 而不需要存储在数据库中。
注意:data-开头为自定义属性
兼容性获取 div.getAttribute('data-index') --------更喜欢用
H5新增(只能获取data- 开头的): div.dataset.index / div.dataset['index']
(dataset是一个集合index是data- 后的名称)
注意 若 data-后有两节 需要有驼峰命名法 div.dataset.listName / div.dataset['listName']
利用层级关系获取元素
之前都是用DOM提供的方法获取元素 逻辑性不强且繁琐-之后介绍父子关系的获取元素法
节点拥有节点类型nodeType、节点名称nodeName、节点值nodeValue这三个属性
元素节点 nodeType=1 属性节点 nodeType=2 文本节点 nodeType=3 文本节点包括文字、空格、换行等
----实际开发中主要获取元素节点(标签)
-
父级节点 node.parentNode (亲爸爸) 如果找不到则返回为空
-
子节点 parentNode.childNodes (注意s) 得到所有子节点包括文本 和元素 但我们只需要元素节点,需要专门处理:parentNode.children 获取所有子元素节点
第一个子节点: .firstElementChid
最后一个子节点: lastElementChild 但是存在兼容性问题
实际开发: parentNode.children[0] parentNode.children[ parentNode.children.length-1]
-
兄弟节点 node.nextSibling 包含文本节点 previousSibling 下一个元素:node.nextElementSibling 上一个:node.previousElementSibling 有兼容性问题自己封装
-
创建节点 动态创建节点 document.creaElement('tagName')
添加元素: 父级加一个子级 ul.appendChild(li) 添加到父节点的指定节点前: 父节点.insertBefore(child, 指定元素) child需要document.createElement('li') 创建
-
删除节点
node.removeChild() 从DOM删除一个子节点 返回删除的节点
-
复制节点 node.cloneNode()
var ul = document.querySelector('ul'); var lili = ul.children[0].cloneNode();//括号为空是浅拷贝 只复制标签 不复制里面的内容 //括号里面加个 true 就会复制节点 ul.appendChild(lili);
-
创建元素
(1) document.write() 如果页面文档流加载完毕 再调用这句话会导致页面重绘
(2)element.innerHTML 是拼接字符串 比document.createElement耗时
事件高级
注册事件
1传统 :以on开头 比如onclick 特点 注册事件的唯一性
2监听: addEventListener() IE9之前不支持 可以用attachEvent()代替 特点:同一个元素同一个事件可以注册多个监听器 按注册顺序依次执行。
btns[1].addEventListener('click', function(){ //或者调用函数名 不需要加小括号 alert(22); })
删除事件
1传统 divs.onclick =null
2divs[1].removeEventListener('click', fn) //fn是函数名
DOM事件流
捕获阶段 document -> html -> body -> father -> son 元素.addEventListener('click', function(){}, true) 第三个参数为true
冒泡阶段 与捕获阶段反着来 第三个元素为false
第三个参数省略 属于冒泡阶段 ,点击了子元素 即使没有点击父元素但是还是会触发。
注意:
onblur onfocus onmouseenter onmouseleave 是没有冒泡的
事件对象
event就是一个事件对象 写到侦听函数中,小括号里面 当形参来看
事件对象只有有了事件才会存在。它是系统自动创建 不需要传递参数
事件对象 是我们事件的一系列相关数据的集合 比如鼠标点击里面 包含鼠标的相关信息,比如鼠标坐标....
btn.onclick=function(event/e){
//有兼容性问题 ie678只能window.event
e = e || window.event;//用的少
console.log(e);
}
e.target() 触发事件对象(比如点击谁就返回哪个元素) this 返回的是绑定事件的对象(元素)
阻止默认行为 e.preventDefault()
组织冒泡 e.stopPropagation()
事件委托/代理
例子: 快递站点 自行领取
原理:不是每个 子节点单独设置事件监听器 而是事件监听器设置在父节点上 然后利用冒泡原理设置每个子节点
ul.addEventListenner('click',function(e){}) // 给父节点设置监听器 那么点击任何li 都会有反应
e.target() 可以获得点击对象 (具体的li)
禁止鼠标右键菜单
document.addEventListener('contextmenu', function(e){
e.preventDefault();
})
禁止选中文字
document.addEventListener('selectstart', function(e){
e.preventDefault();
})
鼠标事件坐标
e.clientX e.clientY (相对于可视区域) | e.pageX e.pageY (相对于文档区域 拖动滚动条会变化) | e.screenX e.screenY 相对于电脑屏幕
键盘事件
传统都加on 一下的监听器写法
1.keyup 按键弹起 keydown 按键按下 keypress 按键按下 但是它不识别功能键 ctrl shift等 ---keyup事件触发时 文字已经落入文本框内 而另外两个
执行顺序:keydown -》 keypress -》 keyup
2.键盘事件对象
keyCode判断用户按下哪个键的ascii码值
keypress区分大小写 keydown和keypress 不区分
BOM
BOM概述
浏览器对象模型 提供了独立于内容而与浏览器窗口进行交互的对象 核心对象是window。比如页面大小发生变化 是window在操作,浏览器厂商自己定义。
window 对象的常见事件
1.window.onload()=function(){} 文档加载完毕才调用该事件,但是只能写一次,写多次以最后一个window.onload 为准
2.window.addEventListener(’load‘, function(){}) 多个不会冲突
3.document.addEventListener('DOMContentLoaded',function(){})
仅当DOM加载完成 不包括样式表 图片 flash等
4.调整窗口大小
window.addEventListener('resize',function(){})
当窗口小于一个大小时 隐藏某个值 完成响应式布局
window.innerWidth <= 800
JS执行机制 JS Async(异步)
JS同步任务会放在主线程执行栈内
异步任务是通过回调函数来实现,添加到任务队列中。
先执行同步任务,遇到回调函数放到任务队列中,一旦执行栈中的所有同步任务执行完毕,系统就会按次序读取任务队列中的异步任务,于是被读取的异步任务结束等待状态,进入执行栈,开始执行。
定时器
1.window.setTimeout(funciton(){}, 2000) 2秒之后调用此函数 可以省略时间 默认0 ; 函数可以写函数名
2.停止定时器 window.clearTimeout(timeoutID)
3.window.setInterval(回调函数,时间间隔 ) 反复调用一个函数
window.clearInterval(timeoutID)
setTimeout()
在使用 JavaScript 函数 setTimeout()
时,可以指定超时时执行的回调函数:
//三秒后执行myFunction函数
setTimeout(myFunction, 3000);
//或者传递整个函数
setTimeout(function() { myFunction("I love You !!!"); }, 3000);
function myFunction() {
document.getElementById("demo").innerHTML = "I love You !!";
}
setInterval(myFunction,1000) 每秒间隔
等待文件
如果您创建函数来加载外部资源(如脚本或文件),则在内容完全加载之前无法使用这些内容。
这是使用回调的最佳时机。
此例加载一个 HTML 文件 (mycar.html
),并在文件完全加载后在网页中显示该 HTML 文件:
function myDisplayer(some) { document.getElementById("demo").innerHTML = some; }
function getFile(myCallback) { let req = new XMLHttpRequest(); req.open('GET', "mycar.html"); req.onload = function() { if (req.status == 200) { myCallback(this.responseText); } else { myCallback("Error: " + req.status); } } req.send(); }
getFile(myDisplayer);
回调 某件事干完再回去调用函数
回调是作为参数传递给另一个函数的函数。
function myDisplayer(some){
document.getElementById("demo").innerHTML = some;
}
function myCalculator(num1, num2, myCallback){
let sum=num1+num2;
myCallback(sum);
}
myCalculator(5,5,myDisplayer);//不要使用括号
location对象
获取或设置窗体url 解析url
location属性
location.href 获取或设置整个URL host 主机域名 port返回端口号 pathname 返回路径 search 返回参数 hash 返回片段
location方法:
assign() 可以跳转页面(重定向) | replace() 替换当前页面 因为不记录历史 所以不能后退页面 | location.reload() 重新加载页面 相当于刷新按钮或者F5 参数为true 为强制刷新
navigator对象
包含浏览器类型
属性:userAgent
history对象
浏览器的历史记录进行交互 该对象包含用户访问过的 URL
back() forwaard() go(参数) 参数1前进一个页面 -1后退1个页面
PC端网页特效
元素偏移量offset
获取元素距离带有定位的父元素位置 父元素加relative, DOM中的parentNode不需要
自身大小(宽高)
注意:返回的数值都不带单位
client 元素可视区
动态得到该元素的边框大小 元素大小等
立即 执行函数 独立创建了一个作用域
不需要调用 写法:
1.
(function(a,b){
console.log(a+b);
})(1,2)
-
(function(){}())
淘宝flexibleJS
pageshow 重新加载页面
之前学的load ,火狐中有往返缓存,保存了整个 页面的DOM和javascript , 后退按钮不能刷新页面,但是pageshow无论页面是否来自缓存。在重新加载页面中会在load
scroll系列属性 可以得到元素大小、滚动距离
scroll高度是内容大小 和 client中的高度是盒子大小
获取页面被卷的头部
mouseenter 和 mouseover区别
mouseover 经过自身盒子和子盒子都会触发 但是只经过自身盒子触发
因为mouseenter不会冒泡 经过子盒子时会冒泡到父盒子 -》鼠标离开 mouseleave
动画函数封装
核心原理 setInterval()
常见网页特效
classList
添加类 classList.add("") / classList.remove("") / classList.toggle('') 切换类
本地存储
1 数据存储在用户浏览器中
2设置读取不方便 甚至页面刷新不丢失数据
3 容量较大 sessionStorage 5M 、localStorage 20M
4 只能存储字符串 可以将对象JSON.stringfy() 编码后存储
sessionStorage
生命周期 为关闭浏览器窗口 同一个页面下的数据可以共享 以键值对存储
存储数据:sessionStorage.setItem(key, value)
获取数据:sessionStorage.getItem(key)
删除数据:sessionStorage.remove(key)
删除所有数据:sessionStorage.clear()
localStorage
1.生命周期 永久生效,除非手动删除否则关闭页面也会存在
2.生命周期 永久生效,除非手动删除否则关闭页面也会存在