JavaScript 高级编程(二)
JavaScript 高级编程(二)
BOM
一套操作浏览器的API。
常见对象
window
: 代表整个浏览器窗口注意: window是BOM中的一个对象, 并且是一个顶级的对象(全局)
Navigator
: 代表当前浏览器的信息, 通过Navigator我们就能判断用户当前是什么浏览器Location
: 代表浏览器地址栏的信息, 通过Location我们就能设置或者获取当前地址信息History: 代表浏览器的历史信息, 通过History来实现刷新/上一步/下一步
注意点: 出于隐私考虑, 我们并不能拿到用户所有的历史记录, 只能拿到当前的历史记录
Screen
: 代表用户的屏幕信息
Navigator
Navigator.userAgent
判断是什么浏览器(Chrome, FireFox)。
Location
代表地址栏信息。
window.Location.href
获取、设置当前标签页的地址。
window.Location.reload(boolean)
重新加载页面,传入参数为true
的话会强制更新缓存。
History
window.History.forward()
浏览器页面前进方法(打开过的前进的页面)。
window.History.back()
浏览器页面回退方法(打开过的回退的页面)。
window.History.go(num)
num
代表前进几个页面,可以为负数,比forward()
方法更前好;num为0时,刷新页面。
函数防抖
函数防抖时优化高频率执行js代码的一种手段,可以让被调用的函数在一次连续的高频操作中只被调用一次。
具体作用:减少代码执行次数,优化网页性能。
具体封装:
function debounce(fn, delay) { // fn = testlet timerId = null;// 返回防抖函数return function () {let self = this;let args = arguments;timerId && clearTimeout(timerId);timerId = setTimeout(function () {fn.apply(self, args);}, delay || 1000);}
}
函数节流
函数节流也是优化高频率执行js代码的手段,与函数防抖只执行一次不同的是,函数节流可能会执行多次(3~4次)。
具体作用:减少代码执行次数,优化网页性能。
具体封装:
function throttle(fn, delay) {let timerId = null;let flag = true;return function () {if(!flag) return;flag = false;let self = this;let args = arguments;timerId && clearTimeout(timerId);timerId = setTimeout(function () {flag = true;fn.apply(self, args);}, delay || 1000);}
}
JavaScrip 新特性
SessionStorage和LocalStorage
和Cookie一样, SessionStorage和LocalStorage也是用于存储网页中的数据的
Cookie、 SessionStorage、LocalStorage区别
无论通过以上那种方式存储的数据, 切记不能将敏感数据直接存储到本地
Cookie | SessionStorage | LocalStorage | |
---|---|---|---|
容量 | 大小(4KB左右)和个数(20~50)限制 | 大小限制(5M左右) | 大小限制(5M左右) |
网络请求 | 每次都会携带在HTTP头中,如果使用cookie保存过多数据会带来性能问题 | 仅在浏览器中保存,不参与和服务器的通信 | 仅在浏览器中保存,不参与和服务器的通信 |
应用场景 | 判断用户是否登录 | 表单数据 | ·购物车 |
生命周期 | 关闭浏览器后失效, 也可以设置过期时间 | 仅在当前会话(窗口)下有效,关闭窗口或浏览器后被清除, 不能设置过期时间 | 除非被清除,否则永久保存 |
无论通过以上那种方式存储的数据, 切记不能将敏感数据直接存储到本地
同源策略?
同源策略(Same origin policy)是一种约定,它是浏览器最核心也最基本的安全功能
所谓同源是指: 协议,域名,端口都相同,就是同源, 否则就是跨域(CORS
)
协议+一级域名+二级域名+端口号都相同, 所以同源
http://www.it666.com:80/index.html
http://www.it666.com:80/detail.html协议不同, 所以不同源, 是跨域
http://www.it666.com:80/index.html
https://www.it666.com:80/index.html一级域名不同, 所以不同源, 是跨域
http://www.it666.com:80/index.html
http://www.itzb.com:80/index.html二级域名不同, 所以不同源, 是跨域
http://www.it666.com:80/index.html
http://edu.it666.com:80/index.html端口号不同, 所以不同源, 是跨域
http://www.it666.com:80/index.html
http://www.it666.com:8090/index.html
同源策略带来的影响
在同源策略下, 浏览器只允许Ajax请求同源的数据, 不允许请求不同源的数据
但在企业开发中, 一般情况下为了提升网页的性能, 网页和数据都是单独存储在不同服务器上的
这时如果再通过Ajax请求数据就会拿不到跨域数据
跨域解决方案 jsonp
JSONP
让网页从别的地址(跨域的地址)那获取资料,即跨域读取数据
JSONP实现跨域访问的原理
- 在同一界面中可以定义多个script标签
- 同一个界面中多个script标签中的数据可以相互访问
- 可以通过script的src属性导入其它资源
- 通过src属性导入其它资源的本质就是将资源拷贝到script标签中
- script的src属性不仅能导入本地资源, 还能导入远程资源
- 由于script的src属性没有同源限制, 所以可以通过script的src属性来请求跨域数据
优化一
在企业开发中通过JSONP来获取跨域的数据,一般情况下服务器返回的都不会是一个变量, 而是一个函数的调用。
优化二
通过URL参数的方式来动态指定函数名称
优化三
由于script标签默认是同步, 前面的script标签没有加载完数据, 后面的script标签就不会被执行
所以请求数据的script标签必须放到后面。
通过JS动态创建script标签, 因为JS动态创建的script标签默认就是异步的,
不用等到前面的标签加载完就可以执行后面的script标签
let oScript = document.createElement("script");
oScript.src = "http://127.0.0.1:80/jQuery/Ajax/20-jsonp.php?cb=test";
document.body.appendChild(oScript);function test(data) {console.log(data);
}
// 当前网页的地址: http://127.0.0.1:63342/jQuery/Ajax/22-jQuery%E4%B8%ADjsonp%E4%BD%BF%E7%94%A8.html
// 当前资源的地址: http://127.0.0.1:80/jQuery/Ajax/22-jsonp.php$.ajax({url: "http://127.0.0.1:80/jQuery/Ajax/22-jsonp.php",data:{"teacher": "lnj","age": 34},dataType: "jsonp", // 告诉jQuery需要请求跨域的数据jsonp: "cb", // 告诉jQuery服务器在获取回调函数名称的时候需要用什么key来获取jsonpCallback: "lnj", // 告诉jQuery服务器在获取回调函数名称的时候回调函数的名称是什么success: function (msg) {console.log(msg);}
});
JS的同步和异步
JS是单线程
JS中的代码都是串行的, 前面没有执行完毕后面不能执行同步代码和异步代码
除了"事件绑定的函数"和"回调函数"以外的都是同步代码- 程序运行会从上至下依次执行所有的同步代码
- 在执行的过程中如果遇到异步代码会将异步代码放到事件循环中
- 当所有同步代码都执行完毕后, JS会不断检测 事件循环中的异步代码是否满足条件
- 一旦满足条件就执行满足条件的异步代码
promise作用
企业开发中为了保存异步代码的执行顺序, 那么就会出现回调函数层层嵌套
如果回调函数嵌套的层数太多, 就会导致代码的阅读性, 可维护性大大降低
promise对象可以将异步操作以同步流程来表示, 避免了回调函数层层嵌套(回调地狱)
Promise?
Promise是ES6中新增的一个对象,
- 用同步的流程来表示异步的操作
- 避免回调函数层层嵌套(回调地狱)问题
Promise基本用法
创建Promis对象
new Promise(function(resolve, reject){});
promise对象不是异步的, 只要创建promise对象就会立即执行存放的代码
Promise同步的流程来表示异步
promise对象是通过状态的改变来实现的, 只要状态发生改变就会自动触发对应的函数Promise对象三种状态
pending
: 默认状态,只要没有告诉promise
任务是成功还是失败就是pending
状态fulfilled
(resolved): 只要调用resolve
函数, 状态就会变为fulfilled
, 表示操作成功rejected
: 只要调用rejected
函数, 状态就会变为rejected
, 表示操作失败
注意点: 状态一旦改变既不可逆
监听Promise状态改变
我们还可以通过函数来监听状态的变化
resolved --> then()
rejected --> catch()
then
then
方法接收两个参数,
第一个参数是状态切换为成功时的回调,
第二个参数是状态切换为失败时的回调
let promise = new Promise(function (resolve, reject) {// resolve(); // 将状态修改为成功reject(); // 将状态修改为失败
});
promise.then(function () {console.log("成功");
}, function () {console.log("失败");
});
在修改promise状态时, 可以传递参数给then方法中的回到函数
// resolve = success, reject = error; let promise = new Promise(function (resolve, reject) {// resolve("111"); // 将状态修改为成功 success("111");reject("aaa"); // 将状态修改为失败 error("aaa"); }); = function success(data) {console.log(data); } function error(data) {console.log(data); } promise.then(success, error);
同一个promise对象可以多次调用then方法,
当该promise对象的状态时所有then方法都会被执行let promise = new Promise(function (resolve, reject) {// resolve(); // 将状态修改为成功reject(); // 将状态修改为失败 }); promise.then(function () {console.log("成功1"); }, function () {console.log("失败1"); }); promise.then(function () {console.log("成功2"); }, function () {console.log("失败2"); });
每次执行完毕后会返回一个新的promise对象
let promise = new Promise(function (resolve, reject) {resolve(); // 将状态修改为成功// reject(); // 将状态修改为失败 }); let p2 = promise.then(function () {console.log("成功1"); }, function () {console.log("失败1"); }); console.log(p2); console.log(promise === p2); // false
上一个promise对象的
then
方法给下一个promise对象的then
方法传递参数
注意点: 无论是在上一个promise对象成功的回调还是失败的回调传递的参数,
都会传递给下一个promise对象成功的回调let promise = new Promise(function (resolve, reject) {// resolve("111"); // 将状态修改为成功reject("aaa"); // 将状态修改为失败 }); let p2 = promise.then(function (data) {console.log("成功1", data);return "222"; // return 就能传给下一个promise }, function (data) {console.log("失败1", data);return "bbb"; // 失败的回调不会传,只会传成功的 }); p2.then(function (data) {console.log("成功2", data); }, function (data) {console.log("失败2", data); });
如果then方法返回的是一个Promise对象, 那么会将返回的Promise对象的
执行结果中的值传递给下一个then方法let promise = new Promise(function (resolve, reject) {resolve("111"); // 将状态修改为成功// reject("aaa"); // 将状态修改为失败 }); let ppp = new Promise(function (resolve, reject) {// resolve("222"); // 将状态修改为成功reject("bbb"); // 将状态修改为失败 }); let p2 = promise.then(function (data) {console.log("成功1", data);return ppp; // 传递 promise 对象 }, function (data) {console.log("失败1", data);return "bbb"; }); p2.then(function (data) {console.log("成功2", data); }, function (data) {console.log("失败2", data);
catch 方法
catch方法
catch 其实是 then(undefined, () => {}) 的语法糖
。let promise = new Promise(function (resolve, reject) {// resolve(); // 将状态修改为成功reject(); // 将状态修改为失败 }); promise.catch(function () {console.log("abc"); });
分开监听
注意点: 如果需要分开监听, 也就是通过then监听成功通过catch监听失败;那么必须使用链式编程, 否则会报错
let promise = new Promise(function (resolve, reject) {// resolve(); // 将状态修改为成功reject(); // 将状态修改为失败 }); // promise.then(function () {// console.log("成功"); // }).catch(function () {// console.log("失败"); // }); // 分开监听会出错 promise.then(function () {console.log("成功"); }); // 返回新的 Promise 对象会继承原来的状态 // 新的Promise 没有监听到,状态出错会报错 promise.catch(function () {console.log("失败"); });
不使用链式编程的注意点
- 如果promise的状态是失败, 但是没有对应失败的监听就会报错
- then方法会返回一个新的promise, 新的promise会继承原有promise的状态
- 如果新的promise状态是失败, 但是没有对应失败的监听也会报错
catch方法可以捕获上一个
Promise
对象then
中的异常。其他特点同
then
Promise all()静态
方法
- all方法接收一个数组
- 如果数组中有多个Promise对象,只有都成功才会执行then方法,并且会按照添加的顺序, 将所有成功的结果重新打包到一个数组中返回给我们
- 如果数组中不是Promise对象, 那么会直接执行then方法
Promise race()
静态方法
race
方法接收一个数组,- 如果数组中有多个
Promise
对象, 谁先返回状态就听谁的, 后返回的会忽略 - 如果数组中不是
Promise
对象, 那么会直接执行then方法
JS中的异常处理
简单粗暴就是有错误出现
由于JS是单线程的, 编写的代码都是串行的,
所以一旦前面代码出现错误,程序就会被中断, 后续代码就不会被执行
自身编写代码问题, --> 手动修复BUG
外界原因问题, -->
try{}catch{}
对于一些可预见的异常, 我们可以使用try{}catch{}
来处理,JS中如何进行异常处理
// 利用try{}catch{}来处理异常可以保证程序不被中断, 也可以记录错误原因以便于后续优化迭代更新 try {// 可能遇到的意外的代码 } catch(e) {// 捕获错误的代码块 }
fetch
什么是
fetch
?
fetch是ES6中新增的, 基于Promise
的网络请求方法fetch
基本使用fetch(url, {options}).then(...).catch(...);
options: 中可用body
属性传递字符串化的post
对象
axios
axios 是一个基于 promise
的 HTTP 库网络请求插件
axios特点
- 可以用在浏览器和 node.js 中
- 支持 Promise API
- 自动转换 JSON 数据
- 客户端支持防御 XSRF
执行 GET
请求
// 为给定 ID 的 user 创建请求
axios.get('/user?ID=12345').then(function (response) {console.log(response);}).catch(function (error) {console.log(error);});// 可选地,上面的请求可以这样做
axios.get('/user', {params: {ID: 12345}}).then(function (response) {console.log(response);}).catch(function (error) {console.log(error);});
执行 POST
请求
axios.post('/user', {firstName: 'Fred',lastName: 'Flintstone'}).then(function (response) {console.log(response);}).catch(function (error) {console.log(error);});
全局 axios 默认值
axios.defaults.timeout = 2000 // 设置 2000ms 接收服务器数据的限定时间,若 2000ms 内无法获取到数据,将报错
axios.defaults.baseURL = 'http://127.0.0.1' // 设置项目根地址,便于项目上线时修改
Symbol
ES6
,用来表示生成独一无二的值
通过Symbol生成独一无二的值时可以设置一个标记, 这个标记仅仅用于区分, 没有其它任何含义。
let name = Symbol("name"); // 生成一个标记为 name 的Symbol值
特点
类型转换不能转换成数值
不能进行运算
前面不加
new
,将其视为基本数据类型Symbol
生成的值,一定要保存下来才能使用for
循环无法遍历出Symbol
属性和方法可使用Object静态方法取出
Symbol
属性和方法,以数组形式返回Object.getOwnPropertySymbols(obj)
Iterator
迭代器,提供for..of
机制的标准接口。
以下数据类型都实现的Iterator接口
Array/Map/Set/String/TypedArray/函数的 arguments 对象/NodeList 对象
特点
- 只要一个数据已经实现了
Iterator
接口, 那么这个数据就有一个叫做[Symbol.iterator]
的属性 [Symbol.iterator]
的属性会返回一个函数[Symbol.iterator]
返回的函数执行之后会返回一个对象[Symbol.iterator]
函数返回的对象中又一个名称叫做next的方法next方法
每次执行都会返回一个对象{value: 1, done: false}
- 这个对象中存储了当前取出的数据和是否取完了的标记
// 实现数组类型
class myArray {constructor () {for (let i = 0; i < arguments.length; i++) {this[i] = arguments[i]}this.length = arguments.length}[Symbol.iterator] () {let self = thislet index = 0return {next () {if (index < self.length) {return {value: self[index++],done: false}} else {return {value: self[index],done: true}}}}}
}let arr = new myArray(1, 3, 5)
for (let item of arr) {console.log(item)
} // output: 1 3 5
// let it = arr[Symbol.iterator]()
// console.log(it.next()) // {value: 1, done: false}
// console.log(it.next()) // {value: 3, done: false}
// console.log(it.next()) // {value: 5, done: false}
// console.log(it.next()) // {value: undefined, done: true}
应用
解构赋值
实现了
Iterator
接口的数据才能进行解构赋值let arr = new myArray(1, 3)let [x, y, z] = arrconsole.log(x, y, z) // 1 3 undefined
扩展运算符
实现了
Iterator
接口的数据才能进行扩展运算let arr = new myArray(1, 3) let brr = new myArray(2, 4) console.log([...arr, ...brr]) // [1, 3, 2, 4]
Generator
Generator函数
Generator
函数是 ES6 提供的一种异步编程解决方案
Generator
函数内部可以封装多个状态, 因此又可以理解为是一个状态机
定义Generator函数
只需要在普通函数的function后面加上*
即可
function* gen() {// statements
}
Generator函数和普通函数区别
3.1调用Generator函数后, 无论函数有没有返回值, 都会返回一个迭代器对象,
3.2调用Generator函数后, 函数中封装的代码不会立即被执行
普通函数调用后 | Generator函数调用后 |
---|---|
返回定义的返回值 | 一定返回迭代器对象 |
立即执行 | 不会立即执行 |
yield
只能用于Generator
函数中
Generator
函数内部使用yield关键字定义状态yield
关键字可以让Generator
内部的逻辑能够切割成多个部分。通过调用迭代器对象的
next
方法执行一个部分代码,执行哪个部分就会返回哪个部分定义的状态
在调用
next
方法的时候可以传递一个参数, 这个参数会传递给上一个yieldfunction * gen () {console.log('yield 1')let data = yield '1'console.log(data)yield '2'console.log('yield 3')yield '3' }let i = gen() i.next() // 1 i.next('parm') // yield i.next() // 3 i.next() //
应用场景
应用场景, 让函数返回多个值
利用
Generator
函数,可以在任意对象上快速部署Iterator
接口let obj = {name: 'lnj',age: 34,gender: 'man',[Symbol.iterator]: function * () {let keys = Object.keys(this)for (let key of keys) {yield obj[key]} } } // 可使用 for...of for (let prop of obj) {console.log(prop) }
用同步的流程来表示异步的操作
async
&& await
async函数
async
函数是ES8中新增的一个函数, 用于定义一个异步函数
async
函数函数中的代码会自动从上至下的执行代码
await操作符
await
操作符只能在异步函数 async function
中使用
await
表达式会暂停当前async function
的执行,等待 Promise
处理完成。
若 Promise
正常处理(fulfilled
),其回调的resolve
函数参数作为 await
表达式的值,然后继续执行 async function
。
JavaScript 高级编程(二)相关推荐
- 侯捷面向对象高级编程(二)
侯捷面向对象高级编程(二) 转换函数 转换函数没有返回值,返回值就是double即函数名,不需要自己写 因为转换函数一般不会改变其中内容,所以要加const限定 两条路都可以走,就回产生歧义,报错 e ...
- JavaScript高级编程 III
原文地址:http://www.onlamp.com/pub/a/onlamp/2007/11/20/advanced-javascript-iii.html JavaScript高级编程I:http ...
- 【读书笔记】JavaScript高级编程(二)
2019独角兽企业重金招聘Python工程师标准>>> 书中第3章 基本概念摘要(一) 3.3 变量 使用var操作符定义的变量将成为定义该变量的作用域中的局部变量.也就是说,如果在 ...
- javascript高级编程教程,javascript基础入门案例
谁有比较好的javascript视频教程 李炎恢的javascript教程,在verycd上可以下载. 结合<javascript高级程序设计>学习,应该会比较好,他这个教程就是参考了&l ...
- javascript高级编程学习笔记(二)——继承
2019独角兽企业重金招聘Python工程师标准>>> 写读书笔记的好处在于加深记忆,前一篇总结了编程中创建的对象的几种方式,以及常用的方式,这一篇总结实现继承的方式: 1.对象冒充 ...
- JavaScript高级程序设计(二):在HTML中使用JavaScript
一.使用<script>元素 1.<script>元素定义了6个属性: async:可选.表示应该立即下载脚本,但不应该妨碍页面中的其他操作,比如下载其他资源或等待加载其他脚本 ...
- JavaScript高级编程设计(第三版)——第四章:变量作用域和内存问题
系列文章目录 第二章:在html中使用javaScript 第三章:基本概念 第四章:变量作用域和内存问题 第五章:引用类型 目录 系列文章目录 前言 一.基本数据类型和引用类型的值? 1.数据类型 ...
- JavaScript高级编程设计(第三版)——第三章:基本概念
系列文章目录 第二章:在html中使用javaScript 第三章:基本概念 第四章:变量作用域和内存问题 目录 系列文章目录 前言 一.语法 1.标识符 2.关键字和保留字 二.数据类型 1.nul ...
- JavaScript高级编程(一)——基本概念
语法 关键字与保留字 变量 ECMAScript的变量是松散类型的,即每个变量仅仅只是一个用于保存值的占位符而已: var message; 定义变量但未初始化但变量,会保存一个特殊但值-- ...
最新文章
- (C++) A+B 输入输出练习IV 每行的第一个数N,表示本行后面有N个数。 如果N=0时,表示输入结束,且这一行不要计算。
- redis(3)-redis基本类型
- 机器学习、超参数、最优超参数、网格搜索、随机搜索、贝叶斯优化、Google Vizier、Adviser
- 用缓动函数模拟物理动画
- 在java中下列描述错误的是_在 JAVA 中 , 关于类的方法 , 下列描述错误的是 ()._学小易找答案...
- Training RNNs as Fast as CNNs
- H5各种头部meta标签的功能
- SAP CRM Fiori My Appointment应用里点了Edit按钮后三个Roundtrip分析
- 获取周一_Ace足球网冬至版周一推介
- 获取计算机最大磁盘,Qt获取电脑磁盘容量(示例代码)
- AD-批量启用账户命令 Enable-adaccount
- 1026 逃跑的拉尔夫
- 拉格朗日中值定理ξ怎么求_【实力干货】!!!高中数学教材之外的常用定理和公式!!!...
- 微信小程序游戏怎么开发入门教程
- 看工业4.0道路上,美国和德国的不同路径
- 定义图书类Book,具有属性账号id,铭name.作者author和价格price,在创建图书对象时要求通过构造器进行创建,- -次性将四个属性全部赋值
- VUE3 之 组件传参
- 抓取chrome所有版本密码
- 2019-04-28 21:43:41.098 ERROR 2920 --- [nio-8888-exec-1] o.a.c.c.C.[.[.[/].[dispatcherServlet] :
- 修改sublime的快捷键