代码拉取完成,页面将自动刷新
//前端面试题(https://zhuanlan.zhihu.com/p/24970850?utm_source=wechat_session)(https://wiki.jirengu.com/doku.php?id=%E5%89%8D%E7%AB%AF%E9%9D%A2%E8%AF%95%E9%87%8D%E7%82%B9%E7%AA%81%E7%A0%B4)
//微任务终极考验面试题,一文讲解async/await转换Promise(https://zhuanlan.zhihu.com/p/450906325?utm_id=0)
JavaScript中undefined的秘密(https://zhuanlan.zhihu.com/p/413492921?utm_id=0)
js中scrollIntoView(调用元素的scrollIntoView方法将会滚动祖先容器,使得元素滚动到可见区域。如果祖先容器不具有滚动条,浏览器会继续向上查找最近的可以滚动的祖先容器,直到找到一个可以滚动的容器为止)
scrollLeft,scrollWidth,clientWidth,offsetWidth到底指的哪到哪的距离之完全详解(https://blog.csdn.net/u013063153/article/details/52805223,https://www.cnblogs.com/lem-worm/archive/2007/11/22/968787.html,https://blog.csdn.net/weixin_44100002/article/details/115342861)
//在javascript中,函数都会有一个返回值。返回值可以通过return关键字进行设置';如果函数里不写return,则函数会返回undefined,可以根据需要判断是否有返回值。
//javascript是一种严格区分大小写的语言,所以 Hello 和 hello 是两个不同的标识符,在输入关键字、变量名、函数名以及所有的标识符时,都必须采取一致的字符大小写形式,
//为了避免输入混乱和语法错误,建议采用小写字符编写代码,在一些特殊情况下可以使用大写形式
//前端网站响应式布局和自适应的区别有哪些(https://www.zhihu.com/pin/1658420630230937600)
//Javascript中扩展运算符的作用及使用场景(https://blog.csdn.net/jiangjunyuan168/article/details/126706007)
// js中的命名规则(https://blog.csdn.net/qq_68299987/article/details/134098148)
// javascript对象属性的命名规则(https://www.cnblogs.com/canger/p/6382944.html)
//基本类型为什么可以调用方法(https://juejin.cn/post/6954336834210136094)
//浏览器输入url会发生什么 - 巨详细完整版(https://zhuanlan.zhihu.com/p/678734779)
//深入解析 EventLoop 和浏览器渲染、帧动画、空闲回调的关系(https://zhuanlan.zhihu.com/p/142742003)
//DOM 更新渲染时机(https://zhuanlan.zhihu.com/p/679354127,https://blog.csdn.net/CRCFeng/article/details/130531662)
//Google I/O 2023(https://zhuanlan.zhihu.com/p/631879733)
//浏览器一帧做了那些事情(https://www.jianshu.com/p/c146ce2bbdf2)
//事件循环(Event Loop)相关概念 及 面试题(https://blog.csdn.net/m0_67841039/article/details/124975370,https://www.cnblogs.com/cuijinlin/p/13722517.html)
单线程是异步产生的原因,事件循环是异步的实现方式
//前端中的i/o操作指磁盘I/O(读写文件)和网络I/O(网络请求和响应)
//宏任务和微任务(https://blog.csdn.net/lrx276/article/details/134527716)
//浏览器中常见的宏任务:script( 整体代码),setTiomeout,setInterval,网络请求和响应,requestAnimationFrame,用户交互事件(DOM事件)的回调函数
//浏览器中常见的微任务:promise.then catch finally中的回调函数,queueMicrotask,MutationObserver(用来监视 DOM 变动。DOM 的任何变动,比如节点的增减、属性的变动、文本内容的变动都会触发MutationObserver事件)
//Http、SSE、Websocket的区别(https://blog.csdn.net/tiansyun/article/details/135638957)
//短轮询、长轮询、SSE 和 WebSocket之间的区别(https://www.cnblogs.com/superlizhao/p/13992807.html)
//长轮询的实现方式
async function subscribe() {
let response = await fetch("/subscribe");
if(response.status == 200){
// 获取并显示消息
let message = await response.text();
showMessage(message);
// 再次调用 subscribe() 以获取下一条消息
await subscribe();
}else{
if (response.status == 502) {
// 状态 502 是连接超时错误,
// 连接挂起时间过长时可能会发生,
// 远程服务器或代理会关闭它
// 让我们重新连接
await subscribe();
}else{
// 一个 error —— 让我们显示它
showMessage(response.statusText);
// 一秒后重新连接
await new Promise(resolve => setTimeout(resolve, 1000));
await subscribe();
}
}
}
subscribe();
//长轮询的实现方式
// 函数调用栈小结:
// 1.js是单线程,在主进程上运行
// 2.栈顶的执行上下文处于执行中,其它需要排队
// 3.全局上下文只有一个且处于栈底,页面关闭时出栈
// 4.函数执行上下文可存在多个,但应避免递归时堆栈溢出
// 5.函数调用时就会创建新的上下文,即使调用自身,也会创建不同的执行上下文
// let和const定义的变量存放在script作用域中,var定义的存放在window中
//JavaScript中的数据类型包括字符串、数字、布尔、数组、对象等,以下是它们之间互相转换的函数
// 字符串转数字:
// parseInt()函数:把字符串转换为整数。如果字符串以非数字字符开头,则返回NaN。
// parseFloat()函数:把字符串转换为浮点数。如果字符串以非数字字符开头,则返回NaN。
// Number()函数:把字符串转换为数字。如果字符串以非数字字符开头,则返回NaN。
// 数字转字符串:
// toString()方法:将数字转换为字符串。
// String()函数:将数字转换为字符串。
// 字符串转布尔:
// Boolean()函数:把字符串转换为布尔值。如果字符串为空字符串或者为0,则返回false;否则返回true。
// 布尔转字符串:
// toString()方法:将布尔值转换为字符串。
// String()函数:将布尔值转换为字符串。
// 数组转字符串:
// toString()方法:将数组转换为字符串,元素之间用逗号隔开。
// join()方法:与toString()类似,但可以指定元素之间的分隔符。
// 字符串转数组:
// split()方法:将字符串按照指定的分隔符分割成数组。
// 数字转布尔:
// Boolean()函数:将数字转换为布尔值。如果数字为0或NaN,则返回false;否则返回true。
// 布尔转数字:
// Number()函数:将布尔值转换为数字。true转换为1,false转换为0。
// 对象转字符串:
// JSON.stringify()方法:将对象转换为JSON格式的字符串。
// 字符串转对象:
// JSON.parse()方法:将JSON格式的字符串转换为对象。
//js中转函数和new 函数的区别:转函数得到的不一定是对象,new 函数得到的一定是对象
//js中GC中的算法-标记清除算法(可以有效的解决循环引用的问题)
//标记清除算法的核心思想是可达性
//这个算法是设置一个根对象(root object也就是window),垃圾回收器会定时从这个根对象开始(必须牢记是从根对象去向外找,是单项的过程,切记是单项的),
//找所有从根对象开始有引用到的对象并且打上标记,对于那些没有被引用的对象(也就是没有被标记的对象)就会被清除
// JS中全局变量和局部变量的生命周期
// 1.全局变量销毁时机:
// 1.1浏览器环境:全局变量存储在全局对象(window)中。只要页面没有被卸载(如用户关闭页面或刷新页面),全局变量就会一直存在//
// 1.2Node.js 环境:全局变量存储在全局对象(global)中,其生命周期与进程的生命周期相同。只要进程没有退出,全局变量就会一直存在
// 1.3全局变量(无论是基本数据类型还是引用数据类型)的值最终都存储在堆内存中
// 2.局部变量当函数调用的时候就要生成 执行完毕之后就销毁,函数体内部的变量在函数每次被调用就会创建一个新的
// 3.闭包内引用的变量除非手动把闭包函数赋值为null,否则不会被销毁(闭包中的基本数据类型和引用数据类型都存储在堆内存中。这是因为闭包需要保持对这些变量的引用,即使它们的作用域已经结束)
// function fads() {
// // let boj = function () {
// // }
// let asd=10
// return function () {
// console.log(asd);
// }
// }
// console.log(fads() == fads()); //false 因为每次函数fads调用返回的都是新的函数
//js 中函数的length属性
// 1.函数的length是js函数对象的一个属性,函数的length代表形参的个数
// 2.形参的数量不包括不包括剩余参数的个数,仅包括“第一个具有默认值之前的参数个数”
// function assd(a,s,d) {
// console.log(a, s,d);
// } //length是3
// function assd(a=1, s, d) {
// } //length是0
// function assd(a, s=1, d) {
// } //length是1
// function assd(a, s, d=1) {
// } //length是2
// 在JavaScript中,&&(逻辑与)、||(逻辑或)运算符和if语句的真假值判断规则是相同的,三元运算符是一种简化if-else语句的方式,和三元运算符真假值判断规则也是相同的。它们都遵循JavaScript中定义的真假值判断标准。以下是JavaScript中被认为是假(falsy)的值:
// false
// 0(数字零)
// -0(负零)
// ""(空字符串)
// null
// undefined
// NaN(Not a Number)
// 所有其他值都被认为是真(truthy)。
//js null、undefined与其他任何类型的值相等(null,undefined在==比较时不会被Number()转化为数字类型)比较时,结果都为false,
//只有null == undefined, null == null, undefined == undefined为true,如果是===判断,null === undefined也为false
null == 0 //false
undefined == 0 //false
//在关系运算符中(如<、>、<=、>=)用于比较两个值的大小时,null,undefined会被Number()强制转换成数字类型
null >= 0 //true Number(null)为0
undefined >= 0 //false Number(undefined)为NAN NaN不等于任何值,甚至是他自身 NaN==NaN为false
//对象相等性(===或==)仅通过引用判断,而非内容
//引用相同的对象不可能数据不同,因为操作的是同一内存,对象相等性(===或==)仅通过引用判断,而非内容
//js中的3个基本包装类型:String、Number、Boolean
var str1 = "hello world"
var str2 = str1.sunstring(5);
//所以实际上str1在调用方法时可以理解为执行了如下过程
// 1 var s1 = new String(str1);
// 2 var str2 = s1.substring(5);
// 3 s1 = null;
//Number、Boolean的值在调用方法的时候也是类似的操作
// JS中includes和indexOf的异同(https://www.jianshu.com/p/bbbb48506b81,https://blog.csdn.net/nanchen_J/article/details/120509505)
// JavaScript中鼠标事件的clientX、clientY、offsetX、offsetY、screenX、screenY(https://www.jianshu.com/p/bb9b87e7d9e1)
//js块级作用域
//1.考虑到环境导致的行为差异太大,应该避免在块级作用域内声明函数。如果确实需要,也应该写成函数表达式,而不是函数声明语句。
//例如
// 块级作用域内部的函数声明语句,建议不要使用
// {
// let a = 'secret';
// function f() {
// return a;
// }
// }
// 块级作用域内部,优先使用函数表达式
// {
// let a = 'secret';
// let f = function () {
// return a;
// };
// }
//2.箭头函数的this会忽略对象和块级作用域
//例如
// {
// let a = 5;
// let func3 = {
// sum: () => {
// console.log('a', this, this.a, 3000)
// }
// }
// func3.sum();//a Window undefined 3000
// }
//js中函数qwe中变量tem的值是由当前函数位置的外层作用域(全局)中的aa,而不是asd函数中的bb。总结函数的上层作用域是由函数当前的位置决定的,而函数中的this是由函数调用时决定的,是函数调用时的对象
// let tem="aa"
// function qwe() {
// console.log(tem)
// }
// function asd() {
// let tem = "bb"
// qwe()
// }
// asd() //aa
// let temsd = "aa"
// let qwase=null
// function aswed() {
// let temsd =10
// qwase = function() {
// console.log(temsd)
// }
// }
// aswed() //aa
// qwase()
//console.log(this) this在浏览器全局作用域中是window,在node全局作用域中是{}
// 那么this到底是怎么样的绑定规则呢?一起来学习一下吧
//绑定一:默认绑定;
//绑定二:隐式绑定;
//绑定三:显示绑定;
//绑定四:new绑定;
// function aa() {
// console.log(this)
// }
// var fn = aa.bind("aa") //显示绑定
// fn() //this是类数组 String {0:"a",1:"a",length:2}
//this绑定的优先级 new绑定 > 显示绑定 > 隐式绑定 > 默认绑定
//this 忽略显示绑定和函数的间接引用 这种情况使用默认绑定规则this指向window(this指函数调用时候所在的那个对象)
// function foo() {
// console.log(this)
// }
// //忽略显示绑定
// foo.call(null) //this指向window
// foo.apply(null) //this指向window
// var ww = foo.bind(null)
// ww()//this指向window
// var obj1 = {
// foo: function () {
// console.log(this)
// }
// }
// var obj2 = {};
// //函数的间接引用
// (obj2.bar = obj1.foo)() //this指向window
//隐式绑定的两种效果相同的写法(谁调用了这个函数,this指向谁(对象))
// var name = "window"
// var object = {
// name: "123",
// foo: function () {
// console.log(this.name)
// }
// }
// object.foo(); //123
// (object.foo)() //123效果和object.foo()一样
//在数组的原型上添加一个方法
// Array.prototype.com1 = function () {
// console.log(this);//[1,2,3]
// };
// [1,2,3].com1()
//在对象的原型上添加一个属性和方法
// Object.prototype.com2 = function () {
// console.log(this);// name: "xiao" }
// };
// Object.prototype.tens = "hen"
// let qwe = { name: "xiao" }
// qwe.com2()
// console.log(qwe.tens);
// // 任何一个构造函数都是继承自Object函数
// function Foo() { }
// let tem = new Foo()
// tem.com2()
// console.log(tem.tens);
//js模拟实现一个自己的call方法
// Function.prototype.myCall = function (thisArg, ...args) {
// let _symbol = Symbol()
// thisArg = (thisArg !== null && thisArg !== undefined) ? Object(thisArg) : window
// thisArg[_symbol] = this
// let result = thisArg[_symbol](...args)
// delete thisArg[_symbol]
// return result
// }
// function foo(...args) {
// console.log(this, args);
// return args.reduce((pre,next)=>pre+next)
// }
// let result1 = foo.myCall({ fn: function () { } }, 20, 30)
// foo.call("",1)
// console.log(result1);
//js模拟实现一个自己的Apply方法
// Function.prototype.myApply = function (thisArg, args) {
// let _symbol = Symbol()
// thisArg = thisArg !== undefined && thisArg !== null ? Object(thisArg) : window
// thisArg[_symbol] = this
// let result = thisArg[_symbol](...args)
// delete thisArg[_symbol]
// return result
// }
//js模拟实现一个自己的Bind方法
// Function.prototype.myBind = function (thisArg, ...args1) {
// let _symbol = Symbol()
// thisArg = thisArg !== undefined && thisArg !== null ? Object(thisArg) : window
// thisArg[_symbol] = this
// return (...args2) => {
// let result = thisArg[_symbol](...args1, ...args2)
// delete thisArg[_symbol]
// return result
// }
// }
//js模拟实现一个自己的bind方法
// Function.prototype.myBind = function (thisArg, ...args1) {
// let _symbol = Symbol()
// thisArg = (thisArg !== null && thisArg !== undefined) ? Object(thisArg) : window
// thisArg[_symbol] = this
// return function (...args2) {
// let result = thisArg[_symbol](...args1,...args2)
// delete thisArg[_symbol]
// return result
// }
// }
// function foo(...args) {
// console.log(this, args);
// return args.reduce((pre, next) => pre + next)
// }
// let result2 = foo.myBind({ age:100 }, 20, 30)
// console.log(result2(40,50));
//arguments可以了解下,不推荐使用了,推荐使用剩余参数的写法...args
// function abc() {
// arguments是个带length的类数组对象 { '0': 1, '1': 2, '2': 3,length:3 }
// //arguments可以获取length也可以通过索引获取arguments中的某个值arguments[index]
// console.log(arguments, arguments.length, arguments[0], Array.from(arguments), [...arguments], Array.prototype.slice.call(arguments));
// }
// abc(1, 2, 3)
//类数组不能使用数组的方法,如果想要用数组方法需要先把类数组转成数组(类数组的对象具有length属性,类数组对象转化成数组必须用Array.from,类数组不能用forEach方法,转化成数组可以用)
//把类数组转化成数组的方式1 [...arguments] 2 Array.from(arguments) 3 Array.prototype.slice.call(arguments) 推荐使用第一种方式或第二种
//js模拟实现一个自己的slice
Array.prototype.mySlice = function (start, end) {
let list = []
start = start ? start : 0
end = end ? end : this.length
for (let i = start; i < end; i++) {
list.push(this[i])
}
return list
}
// function fntem() {
// console.log(Array.prototype.mySlice.call(arguments));
// }
// fntem(10, 20, 30)
//js中能用纯函数就尽可能用纯函数,但不是必须用,比如function case(key,info){localStorage.setItem(key,info)}这个就不是纯函数,因为函数中业务逻辑需要这么写,纯函数就没法写了
//纯函数的定义
//1.一个函数的返回结果只依赖于它的参数或者说确定的输入,会产生确定的输出(确定的输入,会产生确定的输出意思是输入决定输出,一个输入只能对应一个输出。不同的输入可以有相同的输出,但是相同的输入不能有不同的输出)
//2.并且在执行过程里面没有副作用
//什么又是副作用呢?
//副作用的意思就是在执行一个函数的时候,除了返回函数值以外,还对调用函数产生了附加的影响,比如修改了全局变量,修改了参数或者改变外部的存储。
//纯函数在执行的过程中不会产生这样的副作用,有副作用的话往往容易产生不易发觉的BUG
// 纯函数优点:
// 1.纯函数非常容易做单元测试,不需要考虑到上下文环境,只需要考虑输入和输出
// 2.纯函数不那么复杂,更容易调试,易于组合,易于并行化。
//foo函数是一个纯函数
// function foo(num1, num2) {
// return num1 * 2 + num2 * num2
// }
// test是一个纯函数
// function test(info) {
// return {
// ...info,
// age: 100
// }
// }
//fn是一个纯函数
// const fn = (b) => {
// const obj = { x: 1 }
// obj.x = 2
// return obj.x + b
// }
//不是纯函数的有哪些呢?例子如下
//常用的能改变原数组的7个方法都不是纯函数
// bar不是一个纯函数, 因为它修改了外界的变量
// var name = "abc"
// function bar() {
// console.log("bar其他的代码执行")
// name = "cba"
// }
// bar()//baz也不是一个纯函数, 因为我们修改了传入的参数
// function baz(info) {
// info.age = 100
// }
// var obj = { name: "why", age: 18 }
// baz(obj)
// console.log(obj)
//柯里化
// function _koo(x,y,z) {
// return x + y + z
// }
// function koo(x) {
// return function (y) {
// return function (z) {
// return x + y + z
// }
// }
// }
// koo函数可以用es6写成 const _koo=x=>y=>z=>x+y+z _koo(10)(20)(30) //60
//柯里化的优势
// 1.单一职责,把多行代码分散到不同的函数中,方便管理维护
// 例如:
// function loo(x) {
// x = x + 2
// return function (y) {
// y = y * 2
// return function (z) {
// z = z * z
// return x+y+z
// }
// }
// }
// 2.重复代码逻辑复用0
// function zoo(x) {
// return function (y) {
// return function (z) {
// return x + y + z
// }
// }
// }
// const _zoo = zoo(10)(20) //10和20是要固定传的参数,这样做起到逻辑复用的效果
// _zoo(30)
// _zoo(40)
// _zoo(50)
//给一个函数传入一个函数参数把他变成柯里化函数
// function fncurring(x, y, z) {
// return x + y + z
// }
// function curring(fn) {
// function bar(...args) {
// if (fn.length <= args.length) {
// return fn.apply(this, args)
// } else {
// return function (...args2) {
// return bar.apply(this, [...args, ...args2]) //这里绑定this需要向老师确认下是否必须
// }
// }
// }
// return bar
// }
// const _curring = curring(fncurring)
// console.log(_curring(10), _curring(10, 20, 30),_curring(10, 20)(30), _curring(10)(20, 30), _curring(10)(20)(30), "63000");
//封装一个最简单的组合函数(compose)
// function double(count) {
// return count * 2
// }
// function square(count) {
// return count ** 2
// }
// function composeFn(double, square) {
// return function (count) {
// return square(double(count))
// }
// }
// const _composeFn = composeFn(double, square)
// console.log(_composeFn(10), "52");
//封装一个通用的组合函数(compose)
// function sum(a, b) {
// return a + b
// }
// function len(str) {
// return str.length
// }
// function addpro(str) {
// return "$" + str
// }
//第一种实现
// function compose(...fns) {
// return (...args) => {
// let pop = fns.pop()
// return fns.reduceRight((pre,current) => {
// return current(pre)
// }, pop(...args))
// }
// }
//第二种实现
//第一次pre是addpro函数,current是len函数
//第二次pre是function(...args){return addpro(len(...args))},current是sum函数
//最后返回值是function(...args){return function(...args){return addpro(len(...args))(sum(...args))}}
// function compose(...fns) {
// return fns.reduce((pre,current) => {
// return function (...args) {
// return pre(current(...args))
// }
// })
// }
//第二种实现的简写
// const compose = (...fns) => fns.reduce((pre, current) => (...args) => pre(current(...args)) )
// let rt = addpro(len(sum("a","b"))) //和下面两行的效果是相同的
// const result = compose(addpro, len, sum)
// console.log(result("a","b"));
//创建一个对象 1使用new创建 2使用字面量形式创建 推荐使用第二种方案创建
//1.
// let object1 = new Object();//new Object()值是{}
// object1.name = "xiaoming"
// object1.age = 18
// console.log(object1);
//2.
// let object2 = {
// name: "xiaoming",
// age:18
// }
/*上面两种创建对象它们的属性都是直接定义在对象内部的,这样来做的时候我们就不能对属性进行一些限制:比如某个属性是否可以被删除
添加,修改,枚举等等,如果我们想要对一个属性进行比较精准的操作控制,那么我们就可以使用属性描述符,
通过属性描述符可以精准的添加或修改对象的属性,属性描述符需要使用 Object.defineProperty 来对属性进行添加或者修改;
*/
//Object.defineProperty用法 1.数据属性描述符 2.存取属性描述符
// 1.数据属性描述符
// name和age虽然没有使用属性描述符来定义, 但是它们也是具备对应的特性的
// value: 赋值的value
// configurable: true
// enumerable: true
// writable: true
// var obj = {
// name: "why",
// age: 18
// }
// 用了属性描述符, 那么会有默认的特性
//Object.defineProperty(obj, "address", {
// value: "北京市", // 默认值undefined
// address属性是否可以删除/也不可以重新定义属性描述符
// configurable: false, // 默认值false
// address属性是否可以枚举
// enumerable: true, // 默认值false
// address属性是否可以修改赋值
// writable: false // 默认值false
//})
// 测试configurable的作用
// delete obj.name
// console.log(obj.name)
// delete obj.address
// console.log(obj.address)
// Object.defineProperty(obj, "address", {
// value: "广州市",
// configurable: true
// })
// 测试enumerable的作用
// console.log(obj)
// for (var key in obj) {
// console.log(key)
// }
// console.log(Object.keys(obj))
// 测试Writable的作用
// obj.address = "上海市"
// console.log(obj.address)
//2.存取属性描述符
// var obj = {
// name: "why",
// age: 18,
// _address: "北京市"
// }
// 1.隐藏某一个私有属性_address不希望被外界直接使用和赋值(其实是可以直接obj._address访问的_address的值的)
// 2.如果我们希望截获某一个属性它访问和设置值的过程时, 也会使用存取属性描述符
// Object.defineProperty(obj, "address", {
// enumerable: true,
// configurable: true,
// writable: false,
// get: function () {
// foo()
// return this._address
// },
// set: function (value) {
// bar()
// this._address = value
// }
// })
// console.log(obj.address)
// obj.address = "上海市"
// console.log(obj.address)
// function foo() {
// console.log("获取了一次address的值")
// }
// function bar() {
// console.log("设置了addres的值")
// }
//定义多个属性描述符
var obj = {
// 私有属性(js里面是没有严格意义的私有属性)
_age: 18,
_eating: function () { },
// set age(value) {
// this._age = value
// },
// get age() {
// return this._age
// }
}
// // Object.defineProperties(obj, {
// // name: {
// // configurable: true,
// // enumerable: true,
// // writable: true,
// // value: "why"
// // },
// // //下面age的效果和上面obj中的set age,get age效果是一样的,用哪一个都可以
// // age: {
// // configurable: true,
// // enumerable: true,
// // get: function () {
// // return this._age
// // },
// // set: function (value) {
// // this._age = value
// // }
// // }
// // })
// obj.age = 19
// console.log(obj.age)
// console.log(obj, "9654")
// // 获取某一个特性属性的属性描述符
// console.log(Object.getOwnPropertyDescriptor(obj, "name"))
// console.log(Object.getOwnPropertyDescriptor(obj, "age"))
// // 获取对象的所有属性描述符
console.log(Object.getOwnPropertyDescriptors(obj), obj, 200)
//Object.freeze()的用法
/*Object.freeze() 方法可以冻结一个对象,冻结指的是不能向这个对象添加新的属性,
不能修改其已有属性的值,不能删除已有属性,以及不能修改该对象已有属性的可枚举性、可配置性、可写性。
也就是说,这个对象永远是不可变的。该方法返回被冻结的对象。*/
// var obj = {
// name: 'why',
// age: 18
// }
// let sss = Object.freeze(obj)
// obj.name = "kobe"
// obj.height = 1.88
// delete obj.age
// console.log(obj)//{name: 'why',age: 18}
// console.log(obj, sss === obj)//true
// 如果一个函数被使用new操作符调用了,那么它会执行如下操作:
// 1.在内存中创建一个新的对象(空对象);
// 2.这个对象内部的[[prototype]]属性会被赋值为该构造函数的prototype属性;(后面详细讲);
// 3.构造函数内部的this,会指向创建出来的新对象;
// 4.执行函数的内部代码(函数体代码);
// 5.如果构造函数没有显示返回一个对象(return 基本类型数据,还是返回创建出来的新对象,这个特别注意),则返回创建出来的新对象,否则返回return后面的对象
// function Person1() { return 基本类型数据 } //new Person1()结果是{} 特别注意
// function Person2() { } //new Person2()结果是{} new Person1()和new Person2()结果一样
// function Person3() { return {name:"123"} } //new Person3()结果是{name:"123"}
/*任意一个对象上面都有一个隐式原型属性[[prototype]],可以通过__proto__(__proto__是浏览器提供的,有兼容性问题)访问
也可以通过Object.getPrototypeOf()(ECMA提供的方式)方法可以获取到,这个隐式原型属性在浏览器打印的值是{constructor:当前的构造函数本身},
浏览器中有constructor是因为方便我们调试才显示的,并且颜色是灰色的
node中打印的值是{},其实这个{}中是有constructor:当前的构造函数本身,但是constructor是不可枚举所以打印不出来
*/
// let obja = { name: "xiap" }
// let objb = {}
// console.log(obja.__proto__, Object.getPrototypeOf(objb), "5210");//{}
// class Point { /*...*/ }
// class ColorPoint extends Point { /*...*/ }
// console.log(Object.getPrototypeOf(ColorPoint) === ColorPoint.__proto__,
// Object.getPrototypeOf(ColorPoint) === Point, ColorPoint.__proto__ === Point)
//true true true 其实ColorPoint.__proto__=Point 这个继承的作用是实现子类继承父类的静态方法
//函数也是一个对象所以也有一个隐式原型属性[[prototype]],同时也有一个自己特有的显示原型prototype(ECMA很早就有的)属性
// function fon() {
// }
// console.log(fon.prototype, "6965");
/*谷歌浏览器打印的值是{name:"wang",constructor:function fon(){}}
(能打印出来值是因为浏览器方便我们调试才显示的,并且颜色是灰色的) 它里面的name属性是下面添加的 node中打印出来的值是{ }
其实这个{}中是有constructor:当前的构造函数本身,name:"wang",但是constructor和name是不可枚举所以打印不出来*/
// console.log(Object.getOwnPropertyDescriptors(fon.prototype), "9635")//{constructor:{configurable: true,enumerable: false,value:fon,writable: true}}
// let f1 = new fon()
// let f2 = new fon()
// // //f1,f2对象内部的[[prototype]]属性会被赋值为该构造函数的prototype属性//意思就是new fon().__proto__ = fon.prototype
// console.log(f1.__proto__ === fon.prototype)//true
// console.log(f2.__proto__ === fon.prototype)//true
// f1.__proto__.name = "wang"
// //f1.__proto__.name === f2.__proto__.name === fon.prototype.name //他们都是相等的
// console.log(f2.name, f2.__proto__.name === fon.prototype.name);
// console.log(fon.prototype.constructor, fon.prototype.constructor.name,);//[Function: fon] fon
//直接修改整个prototype对象
// fon.prototype = {
// // constructor: fon,
// name: "why",
// age: 18,
// height: 1.88
// }
// let f1 = new fon()
// console.log(f1.name, f1.age, f1.height)
// // 真实开发中我们可以通过Object.defineProperty方式添加constructor
// Object.defineProperty(fon.prototype, "constructor", {
// enumerable: false,
// configurable: true,
// writable: true,
// value: fon
// })
// 规范: 构造函数的首字母一般是大写(构造函数中的普通方法在Xxx.prototype上,静态方法在Xxx上)
// function Person(name, age, height, address) {
// this.name = name
// this.age = age
// this.height = height
// this.address = address
// this.eating = function () {
// console.log(this.name + "在吃东西~")
// }
// this.running = function () {
// console.log(this.name + "在跑步")
// }
// }
// var p1 = new Person("张三", 18, 1.88, "广州市")
// var p2 = new Person("李四", 20, 1.98, "北京市")
// console.log(p1)
// console.log(p2)
// p1.eating()
// p2.eating()
//获取一个对象中的属性的执行过程
// let obj = {
// name: "why",
// age: 18
// }
// [[get]]操作 获取address属性
// 1.在当前的对象中查找属性和方法
// 2.如果没有找到, 这个时候会去原型链(__proto__)对象上查找
// obj.__proto__ = {
// }
// //原型链
// obj.__proto__.__proto__ = {
// }
// obj.__proto__.__proto__.__proto__ = {
// address: "上海市",
// eating: function () {
// console.log(555);
// }
// }
// console.log(obj.address, obj.eating(), "99999")
//对象和函数的原型区别
// let asd = { name: "hexiao" }
// console.log(asd.__proto__, asd.__proto__.__proto__, Object.getOwnPropertyDescriptors(asd.__proto__), "000")
// function qwe() { }
// console.log(qwe.prototype, qwe.prototype.__proto__, qwe.prototype.__proto__.__proto__,
// Object.getOwnPropertyDescriptors(qwe.prototype), Object.getOwnPropertyDescriptors(qwe.prototype.__proto__), "1111")
//构造函数和原型的继承-寄生组合式继承
// function createObject(o) {
// function Fn() { }
// Fn.prototype = o
// return new Fn()
// }
// function inheritPrototype(SubType, SuperType) {
// //createObject(SuperType.prototype)等价于Object.create(SuperType.prototype)
// // SubType.prototype = createObject(SuperType.prototype)
// SubType.prototype = Object.create(SuperType.prototype)
// Object.defineProperty(SubType.prototype, "constructor", {
// enumerable: false,
// configurable: true,
// writable: true,
// value: SubType
// })
// }
// function Person(name, age, friends) {
// this.name = name
// this.age = age
// this.friends = friends
// }
// Person.prototype.running = function () {
// console.log("running~")
// }
// Person.prototype.eating = function () {
// console.log("eating~")
// }
// function Student(name, age, friends, sno, score) {
// Person.call(this, name, age, friends)
// this.sno = sno
// this.score = score
// }
// inheritPrototype(Student, Person)
// Student.prototype.studying = function () {
// console.log("studying~")
// }
// var stu = new Student("why", 18, ["kobe"], 111, 100)
// console.log(stu)
// stu.studying()
// console.log(stu.running, "96552");
// stu.running()
// stu.eating()
// console.log(stu.__proto__.constructor.name)
//判断对象中是否有某个属性
// var obj = {
// name: "why",
// age: 18
// }
// //给info对象添加address属性
// var info = Object.create(obj, {
// address: {
// value: "北京市",
// enumerable: true
// }
// })
// //hasOwnProperty方法判断
// console.log(info.hasOwnProperty("address"), info)//true
// console.log(info.hasOwnProperty("name"))//false
// in 操作符: 不管在当前对象还是原型中返回的都是true
// console.log("address" in info)//true
// console.log("name" in info)//true
// // for in
// for (var key in info) {
// console.log(key)//name,age,address
// }
//instanceof和isPrototypeOf用法,其实它们实现的是同一个效果,只是用法不同(instanceof可以正确的判断对象的类型,instanceof只能正确判断引用数据类型,而不能判断基本数据类型)
//instanceof定义:判断一个构造函数的prototype是否在某个实例对象的原型链上
// function createObject(o) {
// function Fn() { }
// Fn.prototype = o
// return new Fn()
// }
// function inheritPrototype(SubType, SuperType) {
// //createObject(SuperType.prototype)等价于Object.create(SuperType.prototype)
// // SubType.prototype = createObject(SuperType.prototype)
// SubType.prototype = Object.create(SuperType.prototype)
// Object.defineProperty(SubType.prototype, "constructor", {
// enumerable: false,
// configurable: true,
// writable: true,
// value: SubType
// })
// }
// function Person() {
// }
// function Student() {
// }
// inheritPrototype(Student, Person)
// console.log(Person.prototype.__proto__ === Object.prototype)//true
// var stu = new Student()
// console.log(stu instanceof Student) // true
// console.log(stu instanceof Person) // true
// console.log(stu instanceof Object) // true
// //isPrototypeOf定义:判断一个对象是否在一个实例对象的原型链上
// console.log(Student.prototype.isPrototypeOf(stu))//true
// console.log(Person.prototype.isPrototypeOf(stu))//true
// console.log(Object.prototype.isPrototypeOf(stu))//true
// var obj = {
// name: "why",
// age: 18
// }
// var info = Object.create(obj)
// console.log(obj.isPrototypeOf(info))//true
// console.log(info.__proto__ === obj);//true
//类在js中用的不是很多,推荐使用函数(函数是一等公民,vue和react都是函数式编程了)
//class类中constructor构造函数和方法的定义
// var names = ["abc", "cba", "nba"]
// class Person {
// constructor(name, age) {
// this.name = name
// this.age = age
// this._address = "广州市"
// }
// // 普通的实例方法
// // 创建出来的对象进行访问
// // var p = new Person()
// // p.eating()
// eating() {
// console.log(this.name + " eating~")
// }
// running() {
// console.log(this.name + " running~")
// }
// // 类的访问器方法
// get address() {
// console.log("拦截访问操作")
// return this._address
// }
// set address(newAddress) {
// console.log("拦截设置操作")
// this._address = newAddress
// }
// // 类的静态方法(类方法)
// // Person.createPerson()
// static randomPerson() {
// var nameIndex = Math.floor(Math.random() * names.length)
// var name = names[nameIndex]
// var age = Math.floor(Math.random() * 100)
// return new Person(name, age)
// }
// }
// var p = new Person("why", 18)
// p.eating()
// p.running()
// console.log(p.address)
// p.address = "北京市"
// console.log(p.address)
// // console.log(Object.getOwnPropertyDescriptors(Person.prototype))
// for (var i = 0; i < 50; i++) {
// console.log(Person.randomPerson())
// }
/*类中的继承(任何一个类默认都是继承自Object类,js中只支持单继承,
也就是只能有一个父类,但是可以通过混入的方式继承自多个类,一个类继承自多个类使用场景很少只作为了解即可)*/
// class Person {
// constructor(name, age) {
// this.name = name
// this.age = age
// this.x = 1;
// //new.target指向当前正在执行的函数
// console.log(new.target.name);
// }
// running() {
// console.log(this.name + " running~")
// }
// eating() {
// console.log(this.name + " eating~")
// }
// print() {
// console.log(this.x);
// }
// personMethod() {
// console.log("处理逻辑1")
// console.log("处理逻辑2")
// console.log("处理逻辑3")
// }
// static staticMethod() {
// console.log(this.x);
// console.log("PersonStaticMethod")
// }
// }
// class Student extends Person {
// constructor(name, age, sno) {
// /*super(name, age虽然代表了父类Person的构造函数,但是返回的是子类Student的实例,
// 即super内部的this指的是Student的实例,因此super(name, age)在这里相当于
// 相当于Person.prototype.constructor.call(this, name, age)*/
// super(name, age)
// this.sno = sno
// this.x = 2;
// }
// studying() {
// console.log(this.name + " studying~")
// }
// // 子类对父类的方法的重写
// running() {
// console.log("student " + this.name + " running")
// }
// //ES6规定,在子类普通方法中通过super调用父类的方法时,方法内部的this指向当前的子类实例
// m() {
// //super.print()相当于Person.prototype.print.call(this)
// super.print();
// }
// // 重写personMethod方法
// personMethod() {
// //super作为对象时,在普通方法中,指向父类的原型对象;在静态方法中,指向父类。
// // 复用父类中的处理逻辑
// super.personMethod()
// console.log("处理逻辑4")
// console.log("处理逻辑5")
// console.log("处理逻辑6")
// }
// // 重写静态方法
// static staticMethod() {
// console.log(super.studying, "9666");//undefined
// //super.staticMethod()相当于Person.staticMethod.call(this)
// super.staticMethod()
// console.log("StudentStaticMethod")
// }
// }
// Person.staticMethod();//undefined
// Student.x = 33
// let stu = new Student("why", 18, 111)//new.target.name是Student 在super()执行时,new.target.name它指向的是子类Student的构造函数
// console.log(stu)
// stu.m()//2
// stu.eating()
// stu.running()
// stu.personMethod()
// Student.staticMethod()
//继承内置类
// class HYArray extends Array {
// firstItem() {
// return this[0]
// }
// lastItem() {
// return this[this.length - 1]
// }
// }
// var arr = new HYArray(1, 2, 3)
// console.log(arr.firstItem(), arr.filter(item => item > 2))//1 HYArray(1) [ 3 ]
// console.log(arr.lastItem())//3
/* 多态: 当对不同的数据类型执行同一个操作时, 如果表现出来的行为(形态)不一样, 那么就是多态的体现
(下面的代码就可以叫多态, 实际上我们经常写这样的代码, 只是没有一个官网的叫法而已,知道这个概念即可)*/
// function calcArea(foo) {
// console.log(foo.getArea())
// }
// var obj1 = {
// name: "why",
// getArea: function () {
// return 1000
// }
// }
// class Person {
// getArea() {
// return 100
// }
// }
// var p = new Person()
// calcArea(obj1)
// calcArea(p)
// // 也是多态的体现
// function sum(m, n) {
// return m + n
// }
// sum(20, 30)
// sum("abc", "cba")
//字面量增强写法
// var name = "why"
// var age = 18
// var obj = {
// // 1.property shorthand(属性的简写)
// name,
// age,
// // 2.method shorthand(方法的简写)
// foo: function () {
// console.log(this)
// },
// bar() {
// console.log(this)
// },
// baz: () => {
// console.log(this)
// },
// // 3.computed property name(计算属性名)
// [name + 123]: 'hehehehe'
// }
// obj.baz()
// obj.bar()
// obj.foo()
// // obj[name + 123] = "hahaha"
// console.log(obj)
//数组解构
var names = ["abc", "cba", "nba"]
// var item1 = names[0]
// var item2 = names[1]
// var item3 = names[2]
// 对数组的解构: []
// const [item1, item2, item3] = names
// console.log(item1, item2, item3)
// item1 = 20
// console.log(item1);//报错 const定义的变量item1不能被赋值
// // 解构后面的元素
// var [, , itemz] = names
// console.log(itemz)
// // 解构出一个元素,后面的元素放到一个新数组中
// var [itemx, ...newNames] = names
// console.log(itemx, newNames)
// // 解构的默认值
// var [itema, itemb, itemc, itemd = "aaa"] = names
// console.log(itemd)
//对象解构
// var obj = {
// name: "why",
// age: 18,
// height: 1.88
// }
// 对象的解构: {}
// var { name, age, height } = obj
// name="455"
// console.log(name, age, height)//报错 const定义的变量name不能赋值
// var { age } = obj
// console.log(age)
//变量从新命名为newName
// var { name: newName } = obj
// console.log(newName)
// //变量从新命名为newAddress并赋值默认值
// var { address: newAddress = "广州市" } = obj
// console.log(newAddress)
// function foo(info) {
// console.log(info.name, info.age)
// }
// foo(obj)
// function bar({ name, age }) {
// console.log(name, age)
// }
// bar(obj)
// ES6的代码块级作用域(开发过程中优先使用const,如果明确知道某个变量要被修改的时候在用let)
// 对let/const/function/class声明的类型是有效
// {
// let foo = "why"
// function demo() {
// console.log("demo function")
// }
// class Person { }
// }
// console.log(foo) // foo is not defined
// 不同的浏览器有不同实现的(大部分浏览器为了兼容以前的代码, 让function是没有块级作用域)
//demo() //demo function 可以打印出来值
//var p = new Person() // Person is not defined
//if,switch,for循环中的{}都是块级作用域
//块级作用域的应用场景
//const btns = document.getElementsByTagName('button')
// for (var i = 0; i < btns.length; i++) {
// (function(n) {
// btns[i].onclick = function() {
// console.log("第" + n + "个按钮被点击")
// }
// })(i)
// }
// console.log(i)
//这里的let不能换成const,因为i++,i的值不停的变化
// for (let i = 0; i < btns.length; i++) {
// btns[i].onclick = function () {
// console.log("第" + i + "个按钮被点击")
// }
// }
//for循环的执行过程
// {
// let i = 0
// btns[0].onclick = function () {
// console.log("第" + i + "个按钮被点击")
// }
// }
// {
// let i = 1
// btns[1].onclick = function () {
// console.log("第" + i + "个按钮被点击")
// }
// }
// {
// let i = 2
// btns[2].onclick = function () {
// console.log("第" + i + "个按钮被点击")
// }
// }
// 这里的let可以换成const
// const names = ["abc", "cba", "nba"]
// for (let item of names) {
// console.log(item)
// }
//for...of的执行过程
// {
// const item = "abc"
// console.log(item)
// }
// {
// const item = "cba"
// console.log(item)
// }
// {
// const item = "nba"
// console.log(item)
// }
// // ES6之前拼接字符串和其他标识符
// const name = "why"
// const age = 18
// const height = 1.88
// // console.log("my name is " + name + ", age is " + age + ", height is " + height)
// // ES6提供模板字符串 ``
// const message = `my name is ${name}, age is ${age}, height is ${height}`
// console.log(message)
//可以写表达式
// const info = `age double is ${age===18?"我们":"他们"}`
// console.log(info)
// function doubleAge() {
// return age * 2
// }
//也可以调用方法
// const info2 = `double age is ${doubleAge()}`
// console.log(info2)
// //下面这个模块字符串用法了解即可,实际业务代码不用,一些库可能会用到
// // 第一个参数依然是模块字符串中整个字符串, 只是被切成多块,放到了一个数组中
// // 第二个参数是模块字符串中, 第一个 ${}
// function foo(m, n, x) {
// console.log(m, n, x, '---------')
// }
// // foo("Hello", "World")
// // 另外调用函数的方式: 标签模块字符串
// // foo``
// // foo`Hello World`
// const name1 = "why"
// const age1 = 18
// // ['Hello', 'Wo', 'rld']
// foo`Hello${name1}Wo${age1}rld`
//下面代码中,参数变量a,b是默认声明的,在函数体中,不能用let或const再次声明,否则会报错
// function ssw(a,b) {
// let a = 10
// let b=20
// }
// ssw(null, null)
//函数默认值参数
// function qwe({ name="xiaohua",age=20}={}){
// console.log(name,age)
// }
// qwe()
// // 有默认值的形参最好放到最后,不然想要输出默认值的参数在函数调用时需要写undefined
// function bar(x, y, z = 30) {
// console.log(x, y, z)
// }
// bar(10, 20)
//bar(, 10, 20) //这样写时会报错的,,号前面必须写undefined或其他数据
// 有默认值的函数的length属性(了解即可实际代码用的比较少,它的规则是从默认值(包括默认值)开始后面的参数都不算length的个数)
// function baz(x, y, z, m=20, n) {
// console.log(x, y, z, m, n)
// }
// console.log(baz.length)//3
//剩余参数必须放到最后否则会报错(代码中不推荐在使用arguments了)
// function foo(m, n,...args) {
// console.log(m, n)
// console.log(args)
// console.log(arguments)
// }
// foo(20, 30, 40, 50, 60)
//箭头函数不能作为构造函数(箭头函数内部没有this)
// var bar = () => {
// console.log(this, arguments)
// }
// console.log(bar.prototype)//undefined
// // bar is not a constructor(构造函数)
// const b = new bar()
//展开运算符
// const names = ["abc", "cba", "nba"]
// const name = "why"
// const info = { name: "why", age: 18 }
// // 1.函数调用时
// function foo(x, y, z) {
// console.log(x, y, z)
// }
// // foo.apply(null, names)
// foo(...names)
// foo(...name)
// // 2.构造数组时
// const newNames = [...names, ...name]
// console.log(newNames)
// // 3.构建对象字面量时ES2018(ES9)
// const obj = { ...info, address: "广州市", ...names }
// console.log(obj)
//数字的进制(只有十进制常用,其他都不常用仅作了解)
// const num1 = 100 // 十进制
// // b -> binary
// const num2 = 0b100 // 二进制
// // o -> octonary
// const num3 = 0o100 // 八进制
// // x -> hexadecimal
// const num4 = 0x100 // 十六进制 内存地址经常用这个表示
// console.log(num1, num2, num3, num4)
// // 大的数值的连接符(ES2021 ES12)
// const num = 100_00_000_000_000_000
// console.log(num)
// 1.ES6中Symbol的基本使用(es6中支持用Symbol作为对象的属性,我们把它当成唯一不同的字符串理解就行了)
// const s1 = Symbol()
// const s2 = Symbol()
// // console.log(s1 === s2) //false
// // // ES2019(ES10)中, Symbol还有一个描述(description)
// const s3 = Symbol("aaa")
// // console.log(s3.description)//aaa
// // 2.Symbol值作为key
// // 2.1.在定义对象字面量时使用
// const obj = {
// [s1]: "abc",
// [s2]: "cba"
// }
// // 3.2.新增属性
// obj[s3] = "nba"
// // 3.3.Object.defineProperty方式
// const s4 = Symbol()
// Object.defineProperty(obj, s4, {
// enumerable: true,
// configurable: true,
// writable: true,
// value: "mba"
// })
// console.log(obj[s1], obj[s2], obj[s3], obj[s4])
// // 注意: 不能通过.语法获取
// // console.log(obj.s1)
let use1 = { name: "lisi", key: Symbol() }
let use2 = { name: "lisi", key: Symbol() }
let obd = { name }
// // 4.使用Symbol作为key的属性名,在for in遍历或Object.keys等中是获取不到这些Symbol值
// // 需要Object.getOwnPropertySymbols来获取所有Symbol的key
// console.log(Object.keys(obj))
// console.log(Object.getOwnPropertyNames(obj),"5666")
// console.log(Object.getOwnPropertySymbols(obj))
// const sKeys = Object.getOwnPropertySymbols(obj)
// for (const sKey of sKeys) {
// console.log(obj[sKey])
// }
// 5.Symbol.for(key)/Symbol.keyFor(symbol) 了解即可实际代码几乎不怎么用
// const sa = Symbol.for("aaa")
// const sb = Symbol.for("aaa")
// console.log(sa === sb)
// const key = Symbol.keyFor(sa)
// console.log(key)
// const sc = Symbol.for(key)
// console.log(sa === sc)
//set的用法
//new Set()可以接受数组,类数组,字符串作为参数
//数组去重
// let set = new Set([1, 2, 3, 4, 4]);
//Array.from(set)和[...set]是把set结构转化成数组两种方式
//let newArray = Array.from(set)
//扩展运算符(...)内部使用for...of循环,所以也可以用于 Set 结构
// let newArray = [...set]
// console.log(newArray, "633");
//接受类数组作为参数
// const set1 = new Set(document.querySelectorAll('div'));
// //size返回Set实例的成员总数
// const _size = set1.size
// console.log(set1, _size, "633");
//接受类字符串作为参数
// const newString = [...new Set('ababbc')].join('')
// console.log(newString, "633");//"abc"
//下面代码向 Set 实例添加了两次NaN,但是只会加入一个。这表明,在 Set 内部,两个NaN是相等的,另外,两个{}对象总是不相等的,因为内存地址不一样
// let set = new Set();
// let a = NaN;
// let b = NaN;
// set.add(a);
// set.add(b);
// set.add({});
// console.log(set.size) // 2
// set.add({});
// console.log(set.size) // 3
// //obj是同一个对象添加两次,但是set内部只有一个
// const obj = {age:45}
// set.add(obj)
// set.add(obj)
// console.log(set)
//Set 实例的属性和方法
//属性
// Set.prototype.constructor:构造函数,默认就是Set函数。
// Set.prototype.size:返回Set实例的成员总数。
//方法
// Set.prototype.add(value):添加某个值,返回 Set 结构本身
// const s=new Set();
// s.add(1).add(2).add(2);//可以链式调用
// console.log(s);
// Set.prototype.delete(value):删除某个值,返回一个布尔值,表示删除是否成功。
// Set.prototype.has(value):返回一个布尔值,表示该值是否为Set的成员。
// Set.prototype.clear():清除所有成员,没有返回值。
//遍历方法
//由于 Set 结构没有键名,只有键值(或者说键名和键值是同一个值),所以keys方法和values方法的行为完全一致
// let set = new Set(['red', 'green', 'blue']);
// console.log(set, set.size, set.keys().size, set.values().size, set.entries().size);
// console.log(set);
// //new Set(['red', 'green', 'blue'])等同于下面代码
// let allArray = ['red', 'green', 'blue']
// let _set = new Set()
// allArray.forEach(item => {
// _set.add(item)
// })
// console.log(_set);
// for (let item of set.keys()) {
// console.log(item); // red green blue
// }
// for (let item of set.values()) {
// console.log(item);// red green blue
// }
// for (let item of set.entries()) {
// console.log(item);//["red", "red"] ["green", "green"] ["blue", "blue"]
// }
// set.forEach((item,key) => {
// console.log(item, key);//red red green green blue blue
// })
// for (const item of set) {
// console.log(item);//red green blue
//}
//set有size属性,set.keys(),set.values(),set.entries()没有size属性
//WeakSet的使用和注意事项(了解即可)
// 1.WeakSet 的成员只能是对象,而不能是其他类型的值。
/*2.WeakSet 中的对象都是弱引用,如果其他对象都不再引用该对象,那么垃圾回收机制会自动回收该对象所占用的内存,
不考虑该对象还存在于 WeakSet 之中*/
//属性
//WeakSet 没有size属性有constructor属性
//方法 WeakSet 不能遍历,是因为成员都是弱引用,随时可能消失 所以没有forEach,for...of的用法
// WeakSet.prototype.add(value):向 WeakSet 实例添加一个新成员。
// WeakSet.prototype.delete(value):清除 WeakSet 实例的指定成员。
// WeakSet.prototype.has(value):返回一个布尔值,表示某个值是否在 WeakSet 实例之中
//下面是 WeakSet 的另一个例子
//const foos = new WeakSet()
// class Foo {
// constructor() {
// foos.add(this)
// }
// method() {
// if (!foos.has(this)) {
// throw new TypeError('Foo.prototype.method 只能在Foo的实例上调用!');
// }
// }
// }
//Map的使用
// const map = new Map([
// ['name', '张三'],
// ['title', 'Author']
// ]);
// console.log(map);
// map.size // 2
// map.has('name') // true
// map.get('name') // "张三"
// map.has('title') // true
// map.get('title') // "Author"
//Map构造函数接受数组作为参数,实际上执行的是下面的算法。
// const items = [
// ['name', '张三'],
// ['title', 'Author']
// ];
// const map = new Map();
// items.forEach(
// ([key, value]) => map.set(key, value)
// );
//属性
// Map.prototype.constructor:构造函数,默认就是Map函数。
// Map.prototype.size:返回Map实例的成员总数。
//方法
//1.Map.prototype.set(key, value) set方法设置键名key对应的键值为value,然后返回整个 Map 结构。如果key已经有值,则键值会被更新,否则就新生成该键
// let map = new Map()
// .set(1, 'a')
// .set(2, 'b')
// .set(3, 'c'); 可以链式调用
//2.Map.prototype.get(key) get方法读取key对应的键值,如果找不到key,返回undefined。
//3.Map.prototype.has(key) has方法返回一个布尔值,表示某个键是否在当前 Map 对象之中
//4.Map.prototype.delete(key) delete方法删除某个键,返回true。如果删除失败,返回false
//5.Map.prototype.clear() clear方法清除所有成员,没有返回值
//遍历方法
// Map.prototype.keys():返回键名的遍历器。
// Map.prototype.values():返回键值的遍历器。
// Map.prototype.entries():返回所有成员的遍历器。
// Map.prototype.forEach():遍历 Map 的所有成员。
// const map = new Map([
// ['F', 'no'],
// ['T', 'yes'],
// ]);
// console.log(map);
// for (let key of map.keys()) {
// console.log(key);//"F" "T"
// }
// for (let value of map.values()) {
// console.log(value);//"no" "yes"
// }
// for (let [key, value] of map.entries()) {
// console.log(key, value);//"F" "no" "T" "yes"
// }
// for (let item of map.entries()) {
// console.log(item);//["F" "no"] ["T" "yes"]
// }
//Map 结构转为数组结构,比较快速的方法是使用扩展运算符(...)
// const map = new Map([
// [1, 'one'],
// [2, 'two'],
// [3, 'three'],
// ]);
// [...map.keys()];
// [1, 2, 3]
// [...map.values()];
// ['one', 'two', 'three']
// [...map.entries()];
// [[1,'one'], [2, 'two'], [3, 'three']]
// [...map]
// [[1,'one'], [2, 'two'], [3, 'three']]
//[...map.entries()]和[...map]结果是一样的
//map有size属性,map.keys(),map.values(),map.entries()没有size属性
//WeakMap的注意事项和使用(需要掌握vue3响应式源码中用这个实现)
//注意事项
//1.WeakMap 的key只能是是对象(null除外),而不能是其他类型的值。
//2.WeakMap 中的对象都是弱引用,如果其他对象都不再引用该对象,那么垃圾回收机制会自动回收该对象所占用的内存
//使用
//WeakMap.prototype.constructor 构造函数,默认就是WeakMap函数
//WeakMap只有四个方法可用 get()、set()、has()、delete()
//const wm = new WeakMap();
// size、forEach、clear 方法都不存在
// wm.size // undefined
// wm.forEach // undefined
// wm.clear // undefined
//es7中新增的内容
// 1.includes
// const namesArray = ["abc", "cba", "nba", "mba", NaN]
// if (namesArray.indexOf("cba") !== -1) {
// console.log("包含abc元素")
// }
// if (namesArray.includes("cba", 2)) {
// console.log("包含abc元素")
// }
// //indexOf没法判断NaN
// if (namesArray.indexOf(NaN) !== -1) {
// console.log("包含NaN")
// }
// //includes可以判断NaN
// if (namesArray.includes(NaN)) {
// console.log("包含NaN")
// }
// 2.幂运算 **
// let numb1 = Math.pow(3, 3) //Math.pow(x,y) 方法返回 x 的 y 次幂 es5的用法
// let numb2 = 3 ** 3 //es7的用法
// console.log(numb1, numb2);
//es8中新增的内容
//1.Object.keys,Object.values,Object.entries用法
// const obj = {
// name: "why",
// age: 18
// }
// console.log(Object.keys(obj))
// console.log(Object.values(obj))
// 用的非常少
// console.log(Object.values(["abc", "cba", "nba"]))//[ 'abc', 'cba', 'nba' ]
// //Object.values("abc"),Array.from("abc"),[..."abc"]结果是一样的,推荐用[..."abc"]
// console.log(Object.values("abc"),[..."abc"],Array.from("abc"));//[ 'a', 'b', 'c' ]
// console.log(Object.entries(["abc", "cba", "nba"]))//[ [ '0', 'abc' ], [ '1', 'cba' ], [ '2', 'nba' ] ]
// console.log(Object.entries("abc"))//[ [ '0', 'a' ], [ '1', 'b' ], [ '2', 'c' ] ]
//2.padStart和padEnd
//Ees8引入了字符串补全长度的功能。如果某个字符串不够指定长度,会在头部或尾部补全。padStart() 用于头部补全,padEnd() 用于尾部补全
// const message = "Hello World"
// const newMessage = message.padStart(15, "*").padEnd(20, "-")
// console.log(newMessage, message);
// //使用场景(身份证号或银行卡号部分位数遮盖)
// const cardNumber = "321324234242342342341312"
// const lastFourCard = cardNumber.slice(-4)
// const finalCard = lastFourCard.padStart(cardNumber.length, "*")
// console.log(finalCard);
//3.Object.getOwnPropertyDescriptors() 获取一个对象的属性描述符
//4.async await
//es9中新增的内容
// 1.Async iterators:后续迭代器讲解
// 2.Object spread operators:let obj={} let obg1={...obj} 展开运算符
// 3.Promise finally:后续讲Promise讲解
//es10中新增的内容
//1.flat flatMap 用法
// const numbers = [1, 2, [3, 4, [5, 6]]];
// //flat()函数的参数是指定要提取嵌套数组的深度,默认值为 1
// numbers.flat(); //[1, 2, 3, 4, [5, 6]]
// numbers.flat(1); //[1, 2, 3, 4, [5, 6]]
// numbers.flat(2); //[1, 2, 3, 4, 5, 6]
// numbers.flat().flat(); //[1, 2, 3, 4, 5, 6]
// //使用Infinity可以展开任意深度嵌套的数组
// numbers.flat(Infinity)//[1, 2, 3, 4, 5, 6]
//flatMap() 方法是 先执行map() 方法,然后在执行深度为 1 的 flat() 方法。
//flatMap()的使用场景
// const messages = ["Hello World", "hello lyh", "my name is coderwhy"]
// const words = messages.flatMap(item => {
// return item.split(" ")
// })
// console.log(words)
//2.Object.fromEntries的用法
// const obj = {
// name: "why",
// age: 18,
// height: 1.88
// }
// const entries = Object.entries(obj)
// console.log(entries)//[ [ 'name', 'why' ], [ 'age', 18 ], [ 'height', 1.88 ] ]
// const newObj = Object.fromEntries(entries)
// console.log(newObj)//{ name: 'why', age: 18, height: 1.88 }
//Object.fromEntries的使用场景,把一个url中拼接的参数转化成一个对象
//window.location.search='?name=why&age=18&height=1.88' window.location.search获取url中拼接的参数字符串
const queryString = '?name=why&age=18&height=1.88'
const queryParams = new URLSearchParams(queryString)
// console.log(queryParams, [...queryParams], queryParams.entries() ,"5633");
for (const param of queryParams) {
console.log(param)
}
/*Object.fromEntries(queryParams),Object.fromEntries(queryParams.entries()),Object.fromEntries([...queryParams])这3种效果一样,
Object.fromEntries()传递的参数既可以是可迭代的对象也可以是entries数组*/
//const paramObj = Object.fromEntries(queryParams.entries())
const paramObj = Object.fromEntries(queryParams)
//const paramObj = Object.fromEntries([...queryParams])
console.log(paramObj)
//3.trimStart和trimEnd的用法
// const message = " Hello World "
// console.log(message.trim())
// console.log(message.trimStart())
// console.log(message.trimEnd())
//4.Symbol description:已经讲过了
//5.Optional catch binding:后面讲解try cach讲解
//ES11中新增的内容
// 1.ES11之前 max_safe_integer 大数字的用法(了解即可)
// const maxInt = Number.MAX_SAFE_INTEGER
// console.log(maxInt) // 9007199254740991
// console.log(maxInt + 1)
// console.log(maxInt + 2)
// // ES11之后: BigInt 大数字的用法(了解即可)
// const bigInt = 900719925474099100n
// console.log(900719925474099100+10,"966");
// console.log(bigInt + 10n)
// const num = 100
// console.log(bigInt + BigInt(num), "6335")
// const smallNum = Number(bigInt)
// console.log(smallNum)
//2.空值合并运算 ?? (foo的值是null或undefined时,bar的值是"defualt value",否则bar的值是foo)
// const foo = undefined
// // const bar = foo || "default value"
// const bar = foo ?? "defualt value"
// console.log(bar)
//3.可选链?.
// const info = {
// name: "why",
// // friend: {
// // girlFriend: {
// // name: "hmm"
// // }
// // }
// }
//es5只能用下面的if判断写法
// console.log(info.friend.girlFriend.name)
// if (info && info.friend && info.friend.girlFriend) {
// console.log(info.friend.girlFriend.name)
// }
// ES11提供了可选链(代码可以这样写)
//console.log(info.friend?.girlFriend?.name)
//info.friend?.girlFriend?.name="632" 这样写会报错 可选链获取的变量不能被赋值,只能获取值才可以用可选链
//console.log('其他的代码逻辑')
// 4.globalThis(获取某个环境下的全局对象 Global Object)
// 在浏览器下
// console.log(window)
// console.log(this)
// 在node下
// console.log(global)
//console.log(globalThis)//在浏览器中是window,在node中是global
// 5.Dynamic Import:后续ES Module模块化中讲解。
// 6.Promise.allSettled:后续讲Promise的时候讲解。
// 7.import meta:后续ES Module模块化中讲解
//es12中新增的内容
// 1.FinalizationRegistry类
// const finalRegistry = new FinalizationRegistry((value) => {
// console.log("注册在finalRegistry的对象, 某一个被销毁", value)
// })
// let obj = { name: "why" }
// let info = { age: 18 }
// finalRegistry.register(obj, "obj")
// finalRegistry.register(info, "value")
// obj = null
// info = null
// 2.WeakRef类(弱引用)
// WeakRef.prototype.deref:
// > 如果原对象没有销毁, 那么可以获取到原对象
// > 如果原对象已经销毁, 那么获取到的是undefined
// const finalRegistry = new FinalizationRegistry((value) => {
// console.log("注册在finalRegistry的对象, 某一个被销毁", value)
// })
// let obj = { name: "why" }
// let info = new WeakRef(obj)
// finalRegistry.register(obj, "obj")
// obj = null
// setTimeout(() => {
// console.log(info.deref()?.name)
// console.log(info.deref() && info.deref().name)
// }, 10000)
//3.||=,&&=,??=
// 3.1||= 逻辑或赋值运算
// let message = "hello world"
// message = message || "default value"
// message ||= "default value"
// console.log(message)
// 3.2&&= 逻辑与赋值运算(比较少用了解即可)
// &&
// const obj = {
// name: "why",
// foo: function() {
// console.log("foo函数被调用")
// }
// }
// obj.foo && obj.foo()
// &&=
// let info = {
// name: "why"
// }
// // 1.判断info
// // 2.有值的情况下, 取出info.name
// // info = info && info.name
// info &&= info.name
// console.log(info)
// 3.3??= 逻辑空赋值运算
// let message = 0
// message ??= "default value"
// console.log(message)
// 4.Numeric Separator:讲过了;1000_00_00_00 用下划线使得数据更加清晰
// 5.String.replaceAll:字符串替换;
//proxy和Reflect的用法
//监听对象的方式es5用法
// const obj = {
// name: "why",
// age: 18
// }
// Object.defineProperty(obj, "name", {
// get: function() {
// console.log("监听到obj对象的name属性被访问了")
// },
// set: function() {
// console.log("监听到obj对象的name属性被设置值")
// }
// })
// Object.keys(obj).forEach(key => {
// let value = obj[key]
// Object.defineProperty(obj, key, {
// get: function () {
// console.log(`监听到obj对象的${key}属性被访问了`)
// return value
// },
// set: function (newValue) {
// console.log(`监听到obj对象的${key}属性被设置值`)
// value = newValue
// }
// })
// })
// obj.name = "kobe"
// obj.age = 30
// console.log(obj.name)
// console.log(obj.age)
//es6的用法
// const obj = {
// name: "why",
// age: 18
// }
// const objProxy = new Proxy(obj, {
// // 获取值时的捕获器
// get: function (target, key) {
// console.log(`监听到对象的${key}属性被访问了`, target)
// return target[key]
// },
// // 设置值时的捕获器
// set: function (target, key, newValue) {
// console.log(`监听到对象的${key}属性被设置值`, target)
// target[key] = newValue
// },
// // 监听in的捕获器
// has: function (target, key) {
// console.log(`监听到对象的${key}属性in操作`, target)
// return key in target
// },
// // 监听delete的捕获器
// deleteProperty: function (target, key) {
// console.log(`监听到对象的${key}属性in操作`, target)
// delete target[key]
// }
// })
// console.log(objProxy.name)
// console.log(objProxy.age)
// objProxy.name = "kobe"
// objProxy.age = 30
// console.log(obj.name)
// console.log(obj.age)
// in操作符
//console.log("name" in objProxy)
// delete操作
// delete objProxy.name
// console.log(objProxy, obj, "96552122");
//Proxy对函数对象的监听(了解即可)
// function foo() { }
// const fooProxy = new Proxy(foo, {
// apply: function (target, thisArg, argArray) {
// console.log("对foo函数进行了apply调用")
// return target.apply(thisArg, argArray)
// },
// construct: function (target, argArray, newTarget) {
// console.log("对foo函数进行了new调用")
// return new target(...argArray)
// }
// })
// fooProxy.apply({}, ["abc", "cba"])
// new fooProxy("abc", "cba")
//Reflect和Proxy一起使用(要熟练掌握)
// const obj = {
// name: "why",
// age: 18
// }
// const objProxy = new Proxy(obj, {
// //receiver参数只存在于set和get函数中,receiver其实是objProxy
// get: function (target, key, receiver) {
// console.log("get---------")
// return Reflect.get(target, key) // 返回target[key]的值
// },
// set: function (target, key, newValue, receiver) {
// console.log("set---------")
// const result = Reflect.set(target, key, newValue)//返回布尔值
// // if (result) {
// // } else {
// // }
// return result
// },
// // 监听in的捕获器
// has: function (target, key) {
// console.log(`监听到对象的${key}属性in操作`, target)
// return Reflect.has(target, key)//返回布尔值
// },
// // 监听delete的捕获器
// deleteProperty: function (target, key) {
// console.log(`监听到对象的${key}属性in操作`, target)
// return Reflect.deleteProperty(target, key)//返回布尔值
// }
// })
// //执行get方法
// console.log(objProxy.name,"000")
// //执行set方法
// objProxy.name = "kobe"
// console.log(objProxy.name, "111")
// // 执行has方法 "name" in objProxy等价于Reflect.has(objProxy, 'name')
// console.log("name" in objProxy, "222")
// // 执行deleteProperty方法 delete objProxy.age等价于Reflect.deleteProperty(objProxy, 'age')
// delete objProxy.age
// console.log(objProxy, obj, "333");
//console.log(objProxy.name, obj)
//receiver参数的作用(了解即可)
// const obj = {
// _name: "why",
// get name() {
// return this._name
// },
// set name(newValue) {
// this._name = newValue
// }
// }
// const objProxy = new Proxy(obj, {
// get: function (target, key, receiver) {
// // receiver是创建出来的代理对象,就是objProxy,
// console.log("get方法被访问--------", key, receiver)
// console.log(receiver === objProxy)
// return Reflect.get(target, key, receiver)//receiver作用把objProxy赋值给obj中set和get中的this
// },
// set: function (target, key, newValue, receiver) {
// console.log("set方法被访问--------", key)
// console.log(receiver === objProxy)
// Reflect.set(target, key, newValue, receiver)//receiver作用把objProxy赋值给obj中set和get中的this
// }
// })
// console.log(objProxy.name)
// objProxy.name = "kobe"
//Reflect中construct作用(了解即可)
// function Student(name, age) {
// this.name = name
// this.age = age
// }
// function Teacher() { }
// // const stu = new Student("why", 18)
// // console.log(stu)
// // console.log(stu.__proto__ === Student.prototype)
// // 执行Student函数中的内容, 但是创建出来对象是Teacher对象
// const teacher = Reflect.construct(Student, ["why", 18], Teacher)
// console.log(teacher)
// console.log(teacher.__proto__ === Teacher.prototype)
// let s1 = Symbol("jw")
// const objss = {
// name: "jt",
// age: 12,
// [s1]: "ok"
// }
// //想要获取所有的key不能用for in和forEach,因为拿不到Symbol的值,所以需要用reflect.ownKeys
// console.log(Reflect.ownKeys(objss)) //[ 'name', 'age', Symbol(jw) ]
// const fn1 = function (a, b) {
// console.log(a, b, 200);
// }
// //自定义apply默认会调用它,
// fn1.apply = function () {
// console.log("apply");
// }
// fn1.apply() //apply
// //如果想要调用fn1函数本身的apply需要用下面这两个他们是等价的
// //call的作用是把apply方法的中this指向fn1,并让apply方法执行 fn1.apply(null,[1,2])
// Function.prototype.apply.call(fn1, null, [1, 2])
// Reflect.apply(fn1, null, [1, 2])
// //和Reflect搭配的常用方法有apply,proxy(get,set,deleteProperty,has,ownKeys)
//promise的用法
//Promise巧妙的用法
// let wes = null
// new Promise((resolve, reject) => {
// wes = resolve
// }).then(res => {
// console.log(1245);
// })
// setTimeout(() => {
// wes()
// }, 5000)
//promise的注意事项
//1.new Promise(fn)中的参数函数fn会立即被执行
/*2.下面的resolve()和reject()中只会执行第一个也就是resolve(),如果是reject()在第一个也只会执行reject(),不会都执行,
因为Promise状态一旦确定下来, 那么就是不可更改的(锁定)*/
const promise1 = new Promise((resolve, reject) => {
// reject("00")
// resolve(11)
// console.log(123000);//123000
return 3210
//throw "错误"
})
console.log(promise1, 963000);//Promise { 11 }
promise1.then((res) => {
console.log("res", res);//res是执行resolve() //11
}, err => {
console.log("err", err);//err是执行reject()
})
// 用setTimeout模拟异步请求
//request.js
// function requestData(url,) {
// // 异步请求的代码会被放入到executor中
// return new Promise((resolve, reject) => {
// // 模拟网络请求
// setTimeout(() => {
// // 拿到请求的结果
// // url传入的是coderwhy, 请求成功
// if (url === "coderwhy") {
// // 成功
// let names = ["abc", "cba", "nba"]
// resolve(names)
// } else { // 否则请求失败
// // 失败
// let errMessage = "请求失败, url错误"
// reject(errMessage)
// }
// }, 3000);
// })
// }
// // main.js
// const promise = requestData("coderwhy")
// promise.then((res) => {
// console.log("请求成功:", res)
// }, (err) => {
// console.log("请求失败:", err)
// })
/**
* const p1=Promise.resolve(parameter)中parameter参数使用注意事项
* 1> parameter是普通的值或者对象 pending -> fulfilled
* 2> parameter是Promise
* 那么当前的p1的状态会由parameter这个Promise来决定
* 相当于状态进行了移交
* 3> parameter是对象, 并且这个对象有实现then方法(并且这个对象是实现了thenable接口)
* 那么也会执行该then方法, 并且由该then方法决定后续状态
*/
// 1.传入Promise的特殊情况
const newPromise = new Promise((resolve, reject) => {
//resolve("aaaaaa")
reject("err message")
})
new Promise((resolve, reject) => {
// pending -> fulfilled
resolve(newPromise)
}).then(res => {
console.log("res:", res)
}, err => {
console.log("err:", err)
throw "错误"
return 1230
})
// 2.传入一个对象, 这个对象有then方法
new Promise((resolve, reject) => {
// pending -> fulfilled
const obj = {
then: function (resolve, reject) {
// resolve("resolve message")
reject("reject message")
}
}
resolve(obj)
}).then(res => {
console.log("res:", res)
}, err => {
console.log("err:", err)
})
// // eatable/runable
// const obj = {
// eat: function () {
// },
// run: function () {
// }
// }
// Promise的原型上有哪些方法
// console.log(Object.getOwnPropertyDescriptors(Promise.prototype))//获取原型上的属性描述符
/*promise对象中then和catch方法的返回值是Promise.resolve(xxx)或Promise.reject(xxx),
如果then和catch方法中的参数函数中 1.代码逻辑报错(xxx.map is not a function或xxx is not defined) 或 2.抛出错误(throw xxx) 或 3.return Promise.reject(xxx)时,
then和catch方法的返回值是Promise.reject(xxx),如果then和catch方法中的参数函数不是上面3中情况,
then和catch方法的返回值都是Promise.resolve(xxx)*/
//promise对象中then方法使用注意事项
// const promise = new Promise((resolve, reject) => {
// resolve("hahaha")
// })
// 1.同一个Promise可以被多次调用then方法
// 当我们的resolve方法被回调时, 所有的then方法传入的回调函数都会被调用
// promise.then(res => {
// console.log("res1:", res)
// })
//第一中情况
// const powws = Promise.resolve(11).then((res) => {
// console.log(res, 456);
// throw "cuowu"
// })
// console.log(powws, 4120);
//第二中情况
const powwsss = Promise.reject(11).catch((res) => {
console.log(res, 456);
//throw "错误" //throw 语句抛出一个错误,JavaScript会停止执行并抛出错误信息。
asd.name
"12".map()
return Promise.reject(222) //这行代码不会执行
console.log(123);
})
console.log(powwsss, 4120);
powwsss.then(res => {
console.log(res, 789);
}).catch((err) => {
console.log(err, 6963200);//错误
})
// promise.then(res => {
// console.log("res2:", res)
// })
// promise.then(res => {
// console.log("res3:", res)
// })
// 2.then方法传入的 "回调函数: 可以有返回值
// then方法本身也是有返回值的, 它的返回值是Promise
// 2.1 如果我们返回的是一个普通值aaaaaa(数值/字符串/普通对象/undefined), 那么这个普通的值被作为then方法返回新的Promise的resolve值
// promise.then(res => {
// return "aaaaaa"
// }).then(res => {
// console.log("res:", res)
// return "bbbbbb"
// })
// 2.2 如果我们返回的是一个Promise
// promise.then(res => {
// return new Promise((resolve, reject) => {
// setTimeout(() => {
// resolve(111111)
// }, 3000)
// })
// }).then(res => {
// console.log("res:", res)
// })
// 2.3 如果返回的是一个对象, 并且该对象实现了thenable
// promise.then(res => {
// return {
// then: function(resolve, reject) {
// resolve(222222)
// }
// }
// }).then(res => {
// console.log("res:", res)
// })
//promise对象中的catch用法
//1.同一个Promise可以被多次调用catch方法
// 当我们的reject方法被回调时, 所有的catch方法传入的回调函数都会被调用
// const promise = new Promise((resolve, reject) => {
// reject("hahaha")
// })
// promise.catch(res => {
// console.log("res1:", res)
// })
// promise.catch(res => {
// console.log("res2:", res)
// })
// promise.catch(res => {
// console.log("res3:", res)
// })
//2.当executor抛出异常时, 也是会调用错误(拒绝)捕获的回调函数的
//下面函数中throw和报错都能被catch捕获到
const _promise = new Promise((resolve, reject) => {
resolve()
//throw new Error("rejected status")
"12".map()
})
_promise.then(res => {
console.log(res, 6520);
"12".splice() //报错也能被捕获到
}).catch(err => {
console.log("err1:", err) //TypeError: "12".splice is not a function
})
Promise.reject(123)
console.log(451);
// _promise.then(res => {
// // return new Promise((resolve, reject) => {
// // reject("then rejected status")
// // })
// throw new Error("error message")
// }).catch(err => { //catch优先捕获_promise中的reject或抛出异常throw new Error(),如果_promise中的没有reject或异常在去捕获_promise.then(callback)callback函数中的异常或间接的reject,如果callback函数中没有异常或间接的reject,则catch函数中的参数函数不执行
// console.log("err2:", err)
// //throw new Error("error message1233")
// throw "error message1233"
// }).catch(err => {
// console.log("err3:", err)
// })
//3.catch函数的返回值用法和then函数一样也是返回new Promise(resolve =>resolve(x))这里的x指catch return value
// const promise = new Promise((resolve, reject) => {
// reject("111111")
// })
// promise.then(res => {
// console.log("res:", res)
// }).catch(err => {
// console.log("err:", err)
// return "catch return value"
// }).then(res => {
// console.log("res result:", res)
// }).catch(err => {
// console.log("err result:", err)
// })
// promise对象中的finally用法(1.没有参数 2.最终都会执行)
// const promise = new Promise((resolve, reject) => {
// resolve("resolve message")
// //reject("reject message")
// })
// promise.then(res => {
// console.log("res:", res)
// }).catch(err => {
// console.log("err:", err)
// }).finally(() => {
// console.log("finally code execute")
// })
//函数中try finally中代码的执行顺序
// 类方法Promise.resolve(参数)参数的用法 它和new Promise(resolve=>resolve(参数))参数的用法是一样的
// 1.普通的值
// const promise1 = Promise.resolve({ name: "why" })
// 相当于
// const promise2 = new Promise((resolve, reject) => {
// resolve({ name: "why" })
// })
// 2.传入Promise
// const promise = Promise.resolve(new Promise((resolve, reject) => {
// resolve("11111")
// }))
// promise.then(res => {
// console.log("res:", res)
// })
// 3.传入thenable对象
// const promise = Promise.resolve({
// then: function (resolve, reject) {
// resolve(555)
// }})
// promise.then(res => {
// console.log("res:", res)
// })
//类方法Promise.reject(参数)参数的用法
// const promise = Promise.reject("rejected message")
// 相当于
// const promise2 = new Promsie((resolve, reject) => {
// reject("rejected message")
// })
// 注意: Promise.reject(参数,它没有resolve传入带有then方法的对象参数的用法)中的参数无论传入什么值下面catch方法中的err就是什么值,直白说err的值就等于参数的值
//const promisess = Promise.reject(new Promise((resolve) => resolve(555)))
// promisess.then(res => {
// console.log("res:", res)
// }).catch(err => {
// console.log("err:", err)
// })
const promisssse = Promise.reject({
then(resolve) {
resolve(112)
}
})
promisssse.then(res => {
console.log("res:", res)
}).catch(err => {
console.log("err:", err)
})
//Promise.all()的用法
// const p1 = new Promise((resolve, reject) => {
// setTimeout(() => {
// resolve(11111)
// }, 1000);
// })
// const p2 = new Promise((resolve, reject) => {
// setTimeout(() => {
// resolve(22222)
// }, 2000);
// })
// const p3 = new Promise((resolve, reject) => {
// setTimeout(() => {
// resolve(33333)
// }, 3000);
// })
//注意事项
//1. "aaaa"会转化成Promise.resolve("aaaa"), 数组中的值不是promise的全部会转成Promise.resolve(xxx)
//2. 所有的Promise都变成resolved时, p1、p2、p3的返回值和aaa组成一个数组传递给then函数中的res
//3. 只要p1、p2、p3之中有一个被rejected,此时第一个被reject的实例的返回值,会传递给catch函数中的err
// Promise.all([p2, p1, p3, "aaaa"]).then(res => {
// console.log(res)
// }).catch(err => {
// console.log("err:", err)
// })
//Promise.allSettled()的用法(实际项目中推荐使用这个不推荐使用all方法了)
// const p1 = new Promise((resolve, reject) => {
// setTimeout(() => {
// resolve(11111)
// }, 1000);
// })
// const p2 = new Promise((resolve, reject) => {
// setTimeout(() => {
// reject(22222)
// }, 2000);
// })
// const p3 = new Promise((resolve, reject) => {
// setTimeout(() => {
// resolve(33333)
// }, 3000);
// })
//1. "aaaa"会转化成Promise.resolve("aaaa"), 数组中的值不是promise的全部会转成Promise.resolve(xxx)
//2. allSettled结果只会调用then()函数不会调用catch函数
// Promise.allSettled([p1, p2, p3,"aaa"]).then(res => {
// console.log(res)
// }).catch(err => {
// console.log(err)
// })
// Promise.race()的用法
// const p1 = new Promise((resolve, reject) => {
// setTimeout(() => {
// resolve(11111)
// }, 3000);
// })
// const p2 = new Promise((resolve, reject) => {
// setTimeout(() => {
// reject(22222)
// }, 5000);
// })
// const p3 = new Promise((resolve, reject) => {
// setTimeout(() => {
// resolve(33333)
// }, 1000);
// })
//注意事项
//1. 数组中的值不是promise的全部会转成Promise.resolve(xxx)
//2. 只要p1、p2、p3之中有一个实例率先改变状态,那个率先改变的 Promise 实例的返回值(可能是resolved状态也可能是rejectd)是res或err
// Promise.race([p1, p2, p3]).then(res => {
// console.log("res:", res)
// }).catch(err => {
// console.log("err:", err)
// })
//Promise.any()的用法
// const p1 = new Promise((resolve, reject) => {
// setTimeout(() => {
// // resolve(11111)
// reject(1111)
// }, 1000);
// })
// const p2 = new Promise((resolve, reject) => {
// setTimeout(() => {
// //resolve(22222)
// reject(22222)
// }, 5000);
// })
// const p3 = new Promise((resolve, reject) => {
// setTimeout(() => {
// // resolve(33333)
// reject(3333)
// }, 3000);
// })
//注意事项
//1. 数组中的值不是promise的全部会转成Promise.resolve(xxx)
//2. 只要参数实例有一个变成fulfilled状态(优先等待第一个fulfilled状态),包装实例就会变成fulfilled状态;如果所有参数实例都变成rejected状态,包装实例就会变成rejected状态
// Promise.any([p1, p2, p3]).then(res => {
// console.log("res:", res)
// }).catch(err => {
// console.log("err:", err,err.errors)//[ 1111, 22222, 3333 ]
// })
//老师实现一个Promise(用于参考)
// const PROMISE_STATUS_PENDING = 'pending'
// const PROMISE_STATUS_FULFILLED = 'fulfilled'
// const PROMISE_STATUS_REJECTED = 'rejected'
// // 工具函数
// function execFunctionWithCatchError(execFn, value, resolve, reject) {
// try {
// const result = execFn(value)
// resolve(result)
// } catch (err) {
// reject(err)
// }
// }
// class HYPromise {
// constructor(executor) {
// this.status = PROMISE_STATUS_PENDING
// this.value = undefined
// this.reason = undefined
// this.onFulfilledFns = []
// this.onRejectedFns = []
// const resolve = (value) => {
// if (this.status === PROMISE_STATUS_PENDING) {
// // 添加微任务
// queueMicrotask(() => {
// if (this.status !== PROMISE_STATUS_PENDING) return
// this.status = PROMISE_STATUS_FULFILLED
// this.value = value
// this.onFulfilledFns.forEach(fn => {
// fn(this.value)
// })
// });
// }
// }
// const reject = (reason) => {
// if (this.status === PROMISE_STATUS_PENDING) {
// // 添加微任务
// queueMicrotask(() => {
// if (this.status !== PROMISE_STATUS_PENDING) return
// this.status = PROMISE_STATUS_REJECTED
// this.reason = reason
// this.onRejectedFns.forEach(fn => {
// fn(this.reason)
// })
// })
// }
// }
// try {
// executor(resolve, reject)
// } catch (err) {
// reject(err)
// }
// }
// then(onFulfilled, onRejected) {
// const defaultOnRejected = err => { throw err }
// onRejected = onRejected || defaultOnRejected
// const defaultOnFulfilled = value => { return value }
// onFulfilled = onFulfilled || defaultOnFulfilled
// return new HYPromise((resolve, reject) => {
// // 1.如果在then调用的时候, 状态已经确定下来
// if (this.status === PROMISE_STATUS_FULFILLED && onFulfilled) {
// execFunctionWithCatchError(onFulfilled, this.value, resolve, reject)
// }
// if (this.status === PROMISE_STATUS_REJECTED && onRejected) {
// execFunctionWithCatchError(onRejected, this.reason, resolve, reject)
// }
// // 2.将成功回调和失败的回调放到数组中
// if (this.status === PROMISE_STATUS_PENDING) {
// if (onFulfilled) this.onFulfilledFns.push(() => {
// execFunctionWithCatchError(onFulfilled, this.value, resolve, reject)
// })
// if (onRejected) this.onRejectedFns.push(() => {
// execFunctionWithCatchError(onRejected, this.reason, resolve, reject)
// })
// }
// })
// }
// catch(onRejected) {
// return this.then(undefined, onRejected)
// }
// // finally(onFinally) {
// // this.then(() => {
// // onFinally()
// // }, () => {
// // onFinally()
// // })
// // }
// finally(onFinally) {
// this.then(onFinally, onFinally)
// }
// static resolve(value) {
// return new HYPromise((resolve) => resolve(value))
// }
// static reject(reason) {
// return new HYPromise((resolve, reject) => reject(reason))
// }
// static all(promises) {
// // 问题关键: 什么时候要执行resolve, 什么时候要执行reject
// return new HYPromise((resolve, reject) => {
// const values = []
// promises.forEach(promise => {
// promise.then(res => {
// values.push(res)
// if (values.length === promises.length) {
// resolve(values)
// }
// }, err => {
// reject(err)
// })
// })
// })
// }
// static allSettled(promises) {
// return new HYPromise((resolve) => {
// const results = []
// promises.forEach(promise => {
// promise.then(res => {
// results.push({ status: PROMISE_STATUS_FULFILLED, value: res })
// if (results.length === promises.length) {
// resolve(results)
// }
// }, err => {
// results.push({ status: PROMISE_STATUS_REJECTED, value: err })
// if (results.length === promises.length) {
// resolve(results)
// }
// })
// })
// })
// }
// static race(promises) {
// return new HYPromise((resolve, reject) => {
// promises.forEach(promise => {
// // promise.then(res => {
// // resolve(res)
// // }, err => {
// // reject(err)
// // })
// promise.then(resolve, reject)
// })
// })
// }
// static any(promises) {
// // resolve必须等到有一个成功的结果
// // reject所有的都失败才执行reject
// const reasons = []
// return new HYPromise((resolve, reject) => {
// promises.forEach(promise => {
// promise.then(resolve, err => {
// reasons.push(err)
// if (reasons.length === promises.length) {
// reject(new AggregateError(reasons))
// }
// })
// })
// })
// }
// }
// const promise = new HYPromise((resolve, reject) => {
// console.log("状态pending")
// resolve(1111) // resolved/fulfilled
// // reject(2222)
// })
// // 调用then方法多次调用
// promise.then(res => {
// console.log("res1:", res)
// return "aaaaa"
// }).then(res => {
// console.log("res2:", res)
// return "bbbbbvvv"
// }).catch(err => {
// console.log("err:", err)
// }).then(res => {
// console.log("res3:", res)
// }).finally(() => {
// console.log("finally")
// })
// HYPromise.resolve("Hello World").then(res => {
// console.log("res:", res)
// })
// HYPromise.reject("Error Message").catch(err => {
// console.log("err:", err)
// })
// const p1 = new Promise((resolve, reject) => {
// setTimeout(() => { reject(1111) }, 3000)
// })
// const p2 = new Promise((resolve, reject) => {
// setTimeout(() => { reject(2222) }, 2000)
// })
// const p3 = new Promise((resolve, reject) => {
// setTimeout(() => { reject(3333) }, 3000)
// })
// // HYPromise.all([p1, p2, p3]).then(res => {
// // console.log(res)
// // }).catch(err => {
// // console.log(err)
// // })
// HYPromise.allSettled([p1, p2, p3]).then(res => {
// console.log(res)
// })
// // HYPromise.race([p1, p2, p3]).then(res => {
// // console.log("res:", res)
// // }).catch(err => {
// // console.log("err:", err)
// // })
// HYPromise.any([p1, p2, p3]).then(res => {
// console.log("res:", res)
// }).catch(err => {
// console.log("err:", err.errors)
// })
//自己手写实现一个Promise(参考codewhy老师视频20和21节课)
const commonFn = (fn, value, resolve, reject) => {
try {
const result = fn(value)
resolve(result)
} catch (err) {
reject(err)
}
}
class HYMPromise {
constructor(extera) {
this.state = "pending"
this.onFullfieldfns = []
this.onRejectedfns = []
const resolve = (value) => {
queueMicrotask(() => {
if (this.state == "pending") {
this.state = "resolved"
this.value = value
this.onFullfieldfns.forEach(fn => {
fn()
})
}
})
}
const reject = (reason) => {
queueMicrotask(() => {
if (this.state == "pending") {
this.state = "rejected"
this.reason = reason
this.onRejectedfns.forEach(fn => {
fn()
})
}
})
}
try {
extera(resolve, reject)
} catch (err) {
reject(err)
}
}
then(onFulfilled, onRejected) {
onFulfilled = onFulfilled || (value => value)
onRejected = onRejected || (err => { throw err })
return new HYMPromise((resolve, reject) => {
if (this.state == "resolved") {
commonFn(onFulfilled, this.value, resolve, reject)
}
if (this.state == "rejected") {
commonFn(onRejected, this.reason, resolve, reject)
}
if (this.state == "pending") {
this.onFullfieldfns.push(() => {
commonFn(onFulfilled, this.value, resolve, reject)
})
this.onRejectedfns.push(() => {
commonFn(onRejected, this.reason, resolve, reject)
})
}
})
}
catch(onRejected) {
return this.then(undefined, onRejected)
}
finally(back) {
this.then(back, back)
}
static resolve(value) {
return new Promise((resolve) => {
resolve(value)
})
}
static reject(value) {
return new Promise((resolve, reject) => {
reject(value)
})
}
static all(promises) {
let resolves = []
return new Promise((resolve, reject) => {
for (let promise of promises) {
promise.then(res => {
resolves.push(res)
if (resolves.length === promises.length) resolve(resolves)
}, reject)
}
// promises.forEach(promise => {
// promise.then(res => {
// resolves.push(res)
// if (resolves.length === promises.length) resolve(resolves)
// }, reject)
// })
})
}
static allSettled(promises) {
let resolves = []
return new Promise((resolve, reject) => {
promises.forEach((promise) => {
promise.then((res) => {
resolves.push({
status: "fulfilled",
value: res
})
if (resolves.length === promises.length) resolve(resolves)
}, (err) => {
resolves.push({
status: "rejected",
reason: err
})
if (resolves.length === promises.length) resolve(resolves)
})
})
})
}
static race(promises) {
return new Promise((resolve, reject) => {
promises.forEach((promise) => {
promise.then(resolve, reject)
})
})
}
static any(promises) {
let rejects = []
return new Promise((resolve, reject) => {
promises.forEach((promise) => {
promise.then(resolve, (err) => {
rejects.push(err)
if (rejects.length === promises.length) reject(new AggregateError(rejects))
})
})
})
}
}
const p11 = new Promise((resolve, reject) => {
setTimeout(() => { resolve(1111) }, 300)
})
const p22 = new Promise((resolve, reject) => {
setTimeout(() => { resolve(2222) }, 200)
})
const p33 = new Promise((resolve, reject) => {
setTimeout(() => { resolve(3333) }, 100)
})
function sleeps(delay, number) {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log(number);
resolve(number)
}, delay);
})
}
async function hydtf(sss) {
for (let item of sss) {
const res = await item()
console.log(res);
// item.then(res => {
// console.log(res);
// })
} //继发执行
// sss.forEach(async v => {
// const res = await v()
// console.log(res);
// // v.then(res => {
// // console.log(res);
// // })
// }) //forEach,forEach中加async await, 不加async await的for of 这3中情况都是并发执行(同时执行),加async await的for of是继发执行(按先后顺序执行)
}
hydtf([()=>sleeps(300,1111), ()=>sleeps(200,2222), ()=>sleeps(100,3333)])
Promise.all([p11, p22, p33]).then(res => {
console.log(res, 6000)
}).catch(err => {
console.log(err)
})
// 宏任务微任务执行顺序
// fn1,fn2中async/await转换Promise就是fn3 这种带有async/await的函数只有转换成promise的形式才能分析执行顺序
async function fn1(){
console.log('test1')
console.log(await test2())
console.log('test2')
}
async function fn2(){
console.log('test3')
return await 'return value'
}
// fn1,fn2中async/await转换Promise就是fn3 这种带有async/await的函数只有转换成promise的形式才能分析执行顺序
async function fn3(){
console.log('test1')
new Promise(resolve1=>{
Promise.resolve('return value').then(res=>{
console.log('res')
resolve1(res)
})
}).then(res1=>{
console.log('return value')
console.log('test2')
})
}
fn3()
new Promise((resolve,reject)=>{
resolve()
}).then(()=>{
console.log('promise2')
})
test1
res
promise2
test2
// fn1,fn2中async/await转换Promise就是fn3 这种带有async/await的函数只有转换成promise的形式才能分析执行顺序
setTimeout(function () {
console.log("setTimeout");
new Promise(function (resolve) {
console.log("promise1");
resolve();
}).then(function () {
console.log("promise2");
});
}, 0);
setTimeout(function () {
console.log("setTimeout2");
new Promise(function (resolve) {
console.log("promise3");
resolve();
}).then(function () {
console.log("promise4");
});
}, 0);
setTimeout
promise1
promise2
setTimeout2
promise3
promise4
// 宏任务微任务执行顺序
//迭代器(了解即可)
//迭代器的定义是帮助我们对某个数据结构遍历的对象
//迭代器满足的条件
//1.需要有一个next函数(无参数或者一个参数),返回一个应当拥有以下两个属性的对象
//2.done和value属性,如果迭代器可以产生序列中的下一个值,done则为 false,value为数据结构中对应的值,
//如果迭代器已将序列迭代完毕,done则为 true,value为undefined
//forEach是可迭代对象iterable内置的方法,也可以用 for of 但是forEach更简单推荐用forEach,但是如果要在循环中使用await 不推荐用forEach推荐用for of
//封装一个迭代器函数
// function createArrayIterator(arr) {
// let index = 0
// return {
// next: function () {
// if (index < arr.length) {
// return { done: false, value: arr[index++] }
// } else {
// return { done: true, value: undefined }
// }
// }
// }
// }
// const strings = ["abc", "cba", "nba"]
// const nums = [10, 22, 33, 12]
// const namesIterator = createArrayIterator(strings)
// console.log(namesIterator.next())
// console.log(namesIterator.next())
// console.log(namesIterator.next())
// console.log(namesIterator.next())
// const numsIterator = createArrayIterator(nums)
// console.log(numsIterator.next())
// console.log(numsIterator.next())
// console.log(numsIterator.next())
// console.log(numsIterator.next())
// console.log(numsIterator.next())
// 创建一个可迭代对象来访问数组
//可迭代对象满足的条件
//1.可迭代对象中有Symbol.iterator属性,它的值是一个函数,这个函数的返回值是一个迭代器
// const iterableObj = {
// names: ["abc", "cba", "nba"],
// [Symbol.iterator]: function () {
// let index = 0
// return {
// next: () => {
// if (index < this.names.length) {
// return { done: false, value: this.names[index++] }
// } else {
// return { done: true, value: undefined }
// }
// }
// }
// }
// }
// iterableObj对象就是一个可迭代对象
// console.log(iterableObj[Symbol.iterator])
// 1.第一次调用iterableObj[Symbol.iterator]函数
// const iterator = iterableObj[Symbol.iterator]()
// console.log(iterator.next())
// console.log(iterator.next())
// console.log(iterator.next())
// console.log(iterator.next())
// // 2.第二次调用iterableObj[Symbol.iterator]函数
// const iterator1 = iterableObj[Symbol.iterator]()
// console.log(iterator1.next())
// console.log(iterator1.next())
// console.log(iterator1.next())
// console.log(iterator1.next())
// 3.for...of可以遍历的东西必须是一个可迭代对象
// const obj = {
// name: "why",
// age: 18
// }
// for (const item of obj) {
// console.log(item)
// }
// 我们平时创建的很多原生对象已经实现了可迭代协议,会生成一个迭代器(Iterator)对象的:String、Array、Set、Map、arguments对象、NodeList集合(querySelectorAll生成的就是NodeList),对象不是一个可迭代对象(上面的obj)
//生成器(了解即可)
//生成器(本质是一个特殊的迭代器)定义是ES6中新增的一种函数控制、使用的方案,它可以让我们更加灵活的控制函数什么时候继续执行、暂停执行等
// 当遇到yield时候是暂停函数的执行
// 当遇到return时候生成器就停止执行
// function* foo() {
// console.log("函数开始执行~")
// const value1 = 100
// console.log("第一段代码:", value1)
// yield value1
// const value2 = 200
// console.log("第二段代码:", value2)
// yield value2
// const value3 = 300
// console.log("第三段代码:", value3)
// yield value3
// console.log("函数执行结束~")
// return "123"
// }
// // generator本质上是一个特殊的iterator
// const generator1 = foo()
// console.log("返回值1:", generator1.next())
// console.log("返回值2:", generator1.next())
// console.log("返回值3:", generator1.next())
// console.log("返回值4:", generator1.next())
//生成器上的next方法可以传递参数
// function* foo(num) {
// console.log("函数开始执行~")
// const value1 = 100 * num
// console.log("第一段代码:", value1)
// const n = yield value1
// const value2 = 200 * n
// console.log("第二段代码:", value2)
// const count = yield value2
// const value3 = 300 * count
// console.log("第三段代码:", value3)
// const bum = yield value3
// console.log("返回值:", bum)
// console.log("函数执行结束~")
// return "123"
// }
// // 生成器上的next方法可以传递参数
// const generator = foo(5)
// console.log(generator.next())
// // 第二段代码, 第二次调用next的时候执行的
// console.log(generator.next(10))
// console.log(generator.next(25))
// console.log(generator.next(30))
//生成器替代迭代器使用
// function createArrayIterator(arr) {
// let index = 0
// return {
// next: function () {
// if (index < arr.length) {
// return { done: false, value: arr[index++] }
// } else {
// return { done: true, value: undefined }
// }
// }
// }
// }
//1.下面生成器函数替代上面返回迭代器的函数
// function* createArrayIterator(arr) {
// // 1.第一种写法
// // yield "abc" // { done: false, value: "abc" }
// // yield "cba" // { done: false, value: "abc" }
// // yield "nba" // { done: false, value: "abc" }
// // 2.第二种写法
// // for (const item of arr) {
// // yield item
// // }
// // 3.第三种写法 yield* (yield*是第二种写法的语法糖)
// yield* arr
// }
// const contents = ["abc", "cba", "nba"]
// const namesIterator = createArrayIterator(contents)
// console.log(namesIterator.next())
// console.log(namesIterator.next())
// console.log(namesIterator.next())
// console.log(namesIterator.next())
// 2.创建一个生成器函数, 这个函数可以迭代一个范围内的数字
// function* createRangeIterator(start, end) {
// while (start < end) {
// yield start++
// }
// // return {
// // next: function () {
// // if (start < end) {
// // return { done: false, value: start++ }
// // } else {
// // return { done: true, value: undefined }
// // }
// // }
// // }
// }
// const rangeIterator = createRangeIterator(10, 20)
// console.log(rangeIterator.next())
// console.log(rangeIterator.next())
// console.log(rangeIterator.next())
// console.log(rangeIterator.next())
// console.log(rangeIterator.next())
// 3.class案例
// class Classroom {
// constructor(address, name, students) {
// this.address = address
// this.name = name
// this.students = students
// }
// entry(newStudent) {
// this.students.push(newStudent)
// }
// foo = () => {
// console.log("foo function")
// }
// // [Symbol.iterator] = function*() {
// // yield* this.students
// // }
// *[Symbol.iterator]() {
// yield* this.students
// }
// }
// const classroom = new Classroom("3幢", "1102", ["abc", "cba"])
// for (const item of classroom) {
// console.log(item)
// }
//异步代码的处理方案(async await之前的使用方式)
// function requestData(url) {
// // 异步请求的代码会被放入到executor中
// return new Promise((resolve, reject) => {
// // 模拟网络请求
// setTimeout(() => {
// // 拿到请求的结果
// resolve(url)
// }, 2000);
// })
// }
// 需求:
// 1> url: why -> res: why
// 2> url: res + "aaa" -> res: whyaaa
// 3> url: res + "bbb" => res: whyaaabbb
// 1.第一种方案: 多次回调
// 回调地狱
// requestData("why").then(res => {
// requestData(res + "aaa").then(res => {
// requestData(res + "bbb").then(res => {
// console.log(res)
// })
// })
// })
// 2.第二种方案: Promise中then的返回值来解决
// requestData("why").then(res => {
// return requestData(res + "aaa")
// }).then(res => {
// return requestData(res + "bbb")
// }).then(res => {
// console.log(res)
// })
// 3.第三种方案: Promise + generator实现
// function* getData() {
// const res1 = yield requestData("why")
// const res2 = yield requestData(res1 + "aaa")
// const res3 = yield requestData(res2 + "bbb")
// const res4 = yield requestData(res3 + "ccc")
// console.log(res4)
// }
// // 1> 手动执行生成器函数
// const generator = getData()
// generator.next().value.then(res => {
// generator.next(res).value.then(res => {
// generator.next(res).value.then(res => {
// generator.next(res)
// })
// })
// })
// 2> 自己封装了一个自动执行的函数
// function execGenerator(genFn) {
// const generator = genFn()
// function exec(res) {
// const result = generator.next(res)
// if (result.done) {
// return result.value
// }
// result.value.then(res => {
// exec(res)
// })
// }
// exec()
// }
// execGenerator(getData)
// 3> 第三方包co自动执行
// TJ: co/n(nvm)/commander(coderwhy/vue cli)/express/koa(egg)
// const co = require('co')
// co(getData)
// 4.第四种方案: async/await(本质是Promise + generator(生成器)的语法糖)
// async function getData() {
// const res1 = await requestData("why")
// const res2 = await requestData(res1 + "aaa")
// const res3 = await requestData(res2 + "bbb")
// const res4 = await requestData(res3 + "ccc")
// console.log(res4)
// }
// getData()
//async await用法
//async用法
/*async函数是一个异步函数(函数内部没有特别之处(比如await)的话和同步函数执行流程是一样的),
如果async函数内部抛出错误(throw xxx)或return Promise.reject(xxx)或return {
then: function (resolve, reject) {
reject("hahahah")
}
}时,
async函数的返回值是Promise.reject(xxx),如果async函数内部的其他代码写法,返回值都是Promise.resolve(xxx)*/
// async function ss() {
// console.log("内部的代码执行1")
// return 111
// }
// console.log("script start")
// console.log(ss());//Promise {<fulfilled>: 111} 如果ss函数中没有返回值,结果Promise {<fulfilled>: undefined}
// console.log("script end")
// ss().then(res => {
// console.log("res", res);//111
// }).catch(err => {
// console.log("err", err);
// })
//async函数和普通函数的区别
//1.返回值的区别
async function foo() {
// console.log("foo function start~")
// console.log("中间代码~")
// console.log("foo function end~")
//1.返回一个值
//2.返回thenable
// return {
// then: function (resolve, reject) {
// reject("hahahah")
// }
// }
// 3.返回Promise
// return new Promise((resolve, reject) => {
// setTimeout(() => {
// reject("hehehehe")
// }, 2000)
// })
}
// // 异步函数的返回值一定是一个Promise
// const promise = foo()
// console.log(promise, "58666")
// promise.then(res => {
// console.log("promise then function exec:", res)
// }).catch(err => {
// console.log("err:", err)
// })
//2.抛出异常的区别
//普通函数抛出异常没有try catch捕获的话程序会崩掉,后面代码停止执行,有的话正常执行
// function foo() {
// console.log("foo function start~")
// throw new Error("error message")
// console.log("foo function end~") //这行代码不会执行
// }
// foo()
// console.log("后续还有代码~~~~~") //同步函数这行代码不会执行
//异步函数抛出异常有没有try catch捕获程序都能正常执行
// async function foo() {
// console.log("foo function start~")
// // 异步函数中的异常, 会被作为异步函数返回的Promise的reject值的
// throw new Error("error message")
// console.log("foo function end~")//这行代码不会执行
// }
// // // 异步函数的返回值一定是一个Promise
// foo()
// // foo().catch(err => {
// // console.log("coderwhy err:", err) //error message 会捕获异步函数中的错误
// // })
// console.log("后续还有代码~~~~~") //异步函数这行代码会执行
//async await一起使用
// 1.await跟上表达式
// function requestData() {
// return new Promise((resolve, reject) => {
// setTimeout(() => {
// // resolve(222)
// reject(1111)
// }, 2000);
// })
// }
// async function foo() {
/*requestData()的返回值如果是是Promise.resolve(xxx),那么res1=xxx,
后面的console.log(1),console.log(2),console.log(3)代码
相当于这样写Promise.resolve(xxx).then(res=>{console.log(1),console.log(2),console.log(3)})并且依次执行
如果requestData()的返回值是Promise.reject(xxx),那么console.log(1),console.log(2),console.log(3)就不在执行了
xxx是foo()函数返回的promise的reject函数的实际参数值,也相当于是Promise.reject(xxx)*/
// const res1 = await requestData()
// console.log("1", res1)
// console.log("2")
// console.log("3")
// const res2 = await requestData()
// console.log("res2后面的代码", res2)
// }
// 2.跟上其他的值
// async function foo() {
// // const res1 = await 123
// // const res1 = await {
// // then: function(resolve, reject) {
// // resolve("abc")
// // }
// // }
// const res1 = await new Promise((resolve) => {
// resolve("why")
// })
// console.log("res1:", res1)
// }
// // 3.reject值
// async function foo() {
// const res1 = await requestData()
// console.log("res1:", res1)
// }
// foo().catch(err => {
// console.log("err:", err)
// })
//浏览器的宏任务和微任务队列
//宏任务和微任务队列执行顺序:同步代码优先执行完,然后微任务队列中的代码执行完,最后在执行宏任务队列中的代码
//宏任务队列有哪些回调函数?
// 1.setTimeout,setInterval中的回调函数
// 2.ajax的回调函数
// 3.DOM事件(点击,移动,键盘按下,抬起等等事件)对应的回调函数
// 4.UI渲染完之后的回调函数
//微任务队列有哪些回调函数?
// queueMicrotask(() => {
// console.log("queueMicrotask")
// })
// Promise.resolve().then(() => {
// console.log("Promise then")
// })
//1.queueMicrotask中的回调函数
//2.Promise.then或Promise.catch中的回调函数
//node的事件循环在24节课后半部分
/**
* 如果我们有一个函数, 在调用这个函数时, 如果出现了错误, 那么我们应该是去修复这个错误.
*/
// function sum(num1, num2) {
// // 当传入的参数的类型不正确时, 应该告知调用者一个错误
// if (typeof num1 !== "number" || typeof num2 !== "number") {
// // return undefined
// throw "parameters is error type~"
// }
// return num1 + num2
// }
// // 调用者(如果没有对错误进行处理, 那么程序会直接终止)
// console.log(sum({ name: "why" }, true))
// //sum({ name: "why" }, true)
// // try {
// // sum(null, 30)
// // } catch (e) {
// // console.log(e, "633595")
// // }finally {
// console.log("finally代码执行~, close操作")
// }
// console.log("后续的代码会继续运行~")
//序列化方法stringify细节
// const obj = {
// name: "why",
// age: 18,
// friends: {
// name: "kobe"
// },
// hobbies: ["篮球", "足球"],
// foo: function() {
// console.log("foo function")
// }
// // toJSON: function() {
// // return "123456"
// // }
// }
// // 需求: 将上面的对象转成JSON字符串
// // 1.直接转化(foo函数会被过滤掉,因为JSON格式数据不支持函数)
// const jsonString1 = JSON.stringify(obj)
// console.log(jsonString1)
// // 2.stringify第二个参数replacer
// // 2.1. 传入数组: 设定哪些是需要转换
// const jsonString2 = JSON.stringify(obj, ["name", "friends"])
// console.log(jsonString2)
// // 2.2. 传入回调函数:
// const jsonString3 = JSON.stringify(obj, (key, value) => {
// if (key === "age") {
// return value + 1
// }
// return value
// })
// console.log(jsonString3)
// // 3.stringify第三参数 space
// const jsonString4 = JSON.stringify(obj, null, "---")
// console.log(jsonString4)
// // 4.如果obj对象中有toJSON方法 结果是toJSON函数的返回值 123456
// //JSON字符串解析parse细节传入第二个回调函数参数
// const JSONString = '{"name":"why","age":19,"friends":{"name":"kobe"},"hobbies":["篮球","足球"]}'
// const info = JSON.parse(JSONString, (key, value) => {
// if (key === "age") {
// return value - 1
// }
// return value
// })
// console.log(info)
//Storage存储
//localStorage存储是在同一个域(协议,ip和端口号都相同)下的不同标签页(浏览器窗口)中存储的内容是相同的
//sessionStorage存储只是在一个标签页里有效,在另外一个协议,ip和端口号相同的标签页中是无效的
// const loginBtn = document.getElementById("btn")
// loginBtn.onclick = function () {
// localStorage.setItem("name", "localStorage")
// sessionStorage.setItem("name", "sessionStorage")
// }
//Storage常见的属性和方法
// 1.setItem
// localStorage.setItem("name", "coderwhy")
// localStorage.setItem("age", 18)
// // 2.length
// console.log(localStorage.length)
// for (let i = 0; i < localStorage.length; i++) {
// const key = localStorage.key(i)
// console.log(localStorage.getItem(key))
// }
// // 3.key方法
// console.log(localStorage.key(0))
// // 4.getItem(key)
// console.log(localStorage.getItem("age"))
// // 5.removeItem
// localStorage.removeItem("age")
// // 6.clear方法
// localStorage.clear()
//认识BOM
//我们可以将BOM看成是连接JavaScript脚本与浏览器窗口的桥梁(BOM是浏览器提供的,方便js操作浏览器)
// BOM主要包括一下的对象模型:
// window(是JS的最顶层对象,其他的BOM对象都是window对象的属性)包括全局属性、方法,控制浏览器窗口相关的属性、方法
// location:浏览器连接到的对象的位置(URL);
// history:操作浏览器的历史;
// document:当前窗口操作文档的对象;
// window对象在浏览器中有两个身份:
// 身份一:全局对象。
// 我们知道ECMAScript其实是有一个全局对象的,这个全局对象在Node中是global;
// 在浏览器中就是window对象;
// 身份二:浏览器窗口对象。
// 作为浏览器窗口时,提供了对浏览器操作的相关的API;
//防抖函数和节流函数的实现
//防抖函数
// const iptEl = document.getElementById("ipt")
// let counter = 0
// const inputChange = function (event) {
// console.log(`发送了第${++counter}次网络请求`, this, event)
// return "aaaaaaaaaaaa"
// }
// const debounceChange = debounce(inputChange, 3000, (res) => {
// console.log("拿到真正执行函数的返回值:", res)
// })
// iptEl.oninput = debounceChange
// //取消功能
// const cancelBtn = document.querySelector("#cancel")
// cancelBtn.onclick = function () {
// debounceChange.cancel()
// }
// //immediate第一次是否立即执行
// function debounce(fn, delay, handleCallback, immediate = false) {
// // 1.定义一个定时器, 保存上一次的定时器
// let timer = null
// let isInvoke = true
// // 2.真正执行的函数
// const _debounce = function (...args) {
// // 判断是否需要立即执行
// if (immediate && isInvoke) {
// const res = fn.apply(this, args)
// if (handleCallback && typeof handleCallback === 'function') handleCallback(res)
// isInvoke = false
// } else {
// // 取消上一次的定时器
// if (timer) clearTimeout(timer)
// // 延迟执行
// timer = setTimeout(() => {
// // 外部传入的真正要执行的函数
// const res = fn.apply(this, args)
// if (handleCallback && typeof handleCallback === 'function') handleCallback(res)
// isInvoke = true
// timer = null //不写的话timer会被赋值成一个随机数1,2,3,4...
// }, delay)
// }
// }
// // 封装取消功能
// _debounce.cancel = function () {
// if (timer) clearTimeout(timer)
// timer = null
// isInvoke = true
// }
// return _debounce
// }
//防抖简易版(单位时间内事件多次触发只会执行最后一次,前面的触发的定时器都被取消了)
function debounce(fn) {
let timer = null
return function (...arg) {
clearTimeout(timer)
timer = setTimeout(() => {
fn.apply(this, arg)
timer = null
}, 1000)
}
}
//节流
// const iptEl = document.getElementById("ipt")
// let counter = 0
// const inputChange = function (event) {
// console.log(`发送了第${++counter}次网络请求`, this, event)
// return "aaaaaaaaaaaa"
// }
// const debounceChange = throttle(inputChange, 2000, {
// leading: true,//第一次是否执行
// trailing: true,//最后一次是否执行
// handleCallback: function (res) {
// console.log("callback", res);
// }
// })
// iptEl.oninput = debounceChange
// // //取消功能
// const cancelBtn = document.querySelector("#cancel")
// cancelBtn.onclick = function () {
// debounceChange.cancel()
// }
// function throttle(fn, interval, { leading = false, trailing = false, handleCallback } = {}) {
// // 1.记录上一次的开始时间
// let lastTime = 0
// let timer = null
// // 2.事件触发时, 真正执行的函数
// const _throttle = function (...args) {
// // 2.1.获取当前事件触发时的时间
// const nowTime = new Date().getTime()
// if (!lastTime && !leading) lastTime = nowTime
// // 2.2.使用当前触发的时间和之前的时间间隔以及上一次开始的时间, 计算出还剩余多长事件需要去触发函数
// const remainTime = interval - (nowTime - lastTime)
// if (remainTime <= 0) {
// if (timer) {
// clearTimeout(timer)
// timer = null
// }
// // 2.3.真正触发函数
// const res = fn.apply(this, args)
// if (handleCallback && typeof handleCallback === 'function') handleCallback(res)
// // 2.4.保留上次触发的时间
// lastTime = nowTime
// } else {
// if (trailing && !timer) {
// timer = setTimeout(() => {
// const res = fn.apply(this, args)
// if (handleCallback && typeof handleCallback === 'function') handleCallback(res)
// lastTime = !leading ? 0 : new Date().getTime()
// timer = null
// }, remainTime)
// }
// }
// }
// _throttle.cancel = function () {
// if (timer) clearTimeout(timer)
// timer = null
// lastTime = 0
// }
// return _throttle
// }
//节流简易版(单位时间内只会触发第一次,后面触发的事件都不会走定时器了)
function throttle(fn) {
let isTimerRun = false
return function (...args) {
if (isTimerRun) return
isTimerRun = true
setTimeout(() => {
fn.apply(this, args)
isTimerRun = false
}, 1000)
}
}
//函数对象的用法
// let obj11 = {
// name: "why",
// tem: () => {
// },
// array: [11, 2, 3]
// }
// for (let key in obj11.array) {
// console.log(key, "9652");
// }
// let obj22 = { ...obj11 }
// obj11.tem.age = 100
// console.log(obj22.tem.age, obj11.tem === obj22.tem, "12356")
// let qwes = new Function("let s=100;console.log(111);return 555")
// console.log(qwes, qwes(), "963");
//把一个对象中属性的值合并到另外一个对象中
// const obj = {
// name: "wyet",
// age: 20,
// tem: {
// title: "teyee",
// telrm: "jduyrh",
// uyrtsd: "50"
// },
// [Symbol()]: 100
// }
const isObj = (value) => typeof value === "object" && value !== null
function margeObj(state, objOrfn) {
const keys = Reflect.ownKeys(objOrfn)
for (const key of keys) {
let oldVal = state[key]
let newVal = objOrfn[key]
if (isObj(oldVal) && isObj(newVal)) {
state[key] = margeObj(oldVal, newVal)
} else {
state[key] = newVal
}
}
return state
}
// //Reflect.ownKeys(obj) 可以获取所有的属性,Object.keys(obj)和for...in不能获取为symbol值的属性
// console.log(Reflect.ownKeys(obj), margeObj(obj, {
// tes: 200,
// [Symbol()]: 900,
// tem: {
// title: "er",
// wye: 500
// }
// }));
//深拷贝
const deepClone = (obj, map = new WeakMap()) => {
if (obj instanceof Set) {
return new Set(obj)
}
if (obj instanceof Map) {
return new Map(obj)
}
//WeakMap 和 WeakSet 最明显的局限性就是不能迭代,并且无法获取所有当前内容
if (obj === null || typeof obj == "symbol" || typeof obj == "function" || typeof obj !== "object" || obj instanceof WeakSet || obj instanceof WeakMap) {
return obj
}
if (map.has(obj)) {
return map.get(obj)
}
const newObj = Array.isArray(obj) ? [] : {}
//Reflect.ownKeys(obj) 可以获取所有的属性,Object.keys(obj)和for...in不能获取为symbol值的属性
const keys = Reflect.ownKeys(obj)
for (const key of keys) {
newObj[key] = deepClone(obj[key], map)
}
map.set(obj, newObj)
return newObj
}
// const s1 = Symbol("aaa")
// const s2 = Symbol("bbb")
// const oldObject = {
// name: "why",
// friend: {
// name: "kou",
// age: 18
// },
// array: [1, 2, 3],
// foo: function () {
// console.log("函数");
// },
// [s1]: "abc",
// s2: s2,
// set: new Set([1, 2, 3]),
// map: new Map([["a", "abc"], ["b", "cba"]])
// }
// oldObject.info = oldObject
// const newObj = deepClone(oldObject)
// console.log(newObj == oldObject, "00000")
// oldObject.name = "whys"
// oldObject.friend.age = 2000
// oldObject.array[0] = 300
// oldObject.set.add(111)
// oldObject.map.set("qqq", "wwww")
// console.log(oldObject, newObj, "11111")
//WeakMap弱引用的用法
// let asd = { name: "why" }
// let qwe = {}
// const weakmap = new WeakMap()
// const map = new Map()
// //weakmap.set(asd, "对象内容").set(qwe, "空对象")
// map.set(asd, "对象内容").set(qwe, "空对象")
// console.log(map, "8966");
// asd = null
// setTimeout(() => {
// console.log(map, "123");
// }, 8000)
//单例模式(一个类只有一个实例对象)
const Person = (() => {
function Animal() { }
let instance = null
return function () {
if (!instance) instance = new Animal()
return instance
}
})()
const p1 = Person()
const p2 = Person()
console.log(p1 == p2)//true
//观察者模式
class Dep {
constructor() {
this.deps = []
}
add(watcher) {
if (!this.deps.includes(watcher)) {
this.deps.push(watcher)
}
}
remove(watcher) {
if (this.deps.includes(watcher)) {
let index = this.deps.indexOf(watcher)
this.deps.splice(index, 1)
}
}
notify() {
this.deps.forEach(item => {
if (item.update) {
item.update()
}
})
}
}
class Watcher {
constructor() { }
update() {
console.log("更新我");
}
}
const dep = new Dep()
const watcher1 = new Watcher()
const watcher2 = new Watcher()
dep.add(watcher1)
dep.add(watcher2)
dep.notify()
//发布订阅模式
//vue中的事件总线(mini-mitt)
class JHmitt {
constructor() {
this.obj = {}
}
on(name, callback, thisAge) {
if (!(this.obj[name])) {
this.obj[name] = []
}
this.obj[name].push({
callback,
thisAge
})
}
emit(name, ...args) {
const headers = this.obj[name]
if (!headers) return
headers.forEach(item => {
item.callback.apply(item.thisAge, args)
})
}
off(name, callback) {
const headers = this.obj[name]
if (!headers) return
headers.forEach((item, index) => {
if (callback === undefined) {
this.obj[name] = []
} else {
if (item.callback === callback) {
headers.splice(index, 1)
}
}
})
}
}
// const newJHmitt = new JHmitt()
// const callback = function (...args) {
// console.log(args, 123);//this在浏览器中是window
// }
// newJHmitt.on("abc", callback)
// newJHmitt.on("abc", function () {
// console.log("监听abc", this.name);
// }, { name: "why" })
// newJHmitt.emit("abc", 456)
// newJHmitt.off("abc")
// newJHmitt.emit("abc",789)
//自己手写发布订阅模式
class mitts {
constructor() {
this.obj = {};
}
//订阅
on(name, callback, thisArg) {
if (!this.obj[name]) {
this.obj[name] = []
}
this.obj[name].push({
callback,
thisArg
})
}
//发布
emit(name, ...arg) {
if (this.obj[name]) {
this.obj[name].forEach(item => {
item.callback.apply(item.thisArg, arg)
})
}
}
off(name, callback) {
if (callback) {
let index = this.obj[name].findIndex(item => callback === item.callback)
if (index >= 0) {
this.obj[name].splice(index, 1)
}
} else {
this.obj[name] = []
}
}
}
//实现原生reduce方法
// Array.prototype.reduce = function (callback,pre) {
// for (let i = 0; i < this.length; i++){
// if (!pre) {
// pre = callback(this[i], this[i + 1], i + 1, this)
// i++
// } else {
// pre = callback(pre, this[i], i, this)
// }
// }
// return pre
// }
// let total = [1, 2, 3].reduce(function (pre,current) {
// return pre + current
// })
// console.log(total, "56633");
// for...of和async await结合用法
function sleep(value) {
return new Promise((resolve, reject) => {
if (value < 3) {
resolve(100)
} else {
reject(500)
}
})
}
async function chainAnimationsAsync() {
const telist = []
try {
for (let value of [1, 2, 3, 4, 5]) {
//下面这段代码失败就会跳出整个循环,然后执行catch方法
res = await sleep(value);
telist.push(res)
}
} catch (err) {
telist.push(err)
console.log(err, 9100);
}
return telist
}
chainAnimationsAsync().then((res) => {
console.log(res, 9200);
}, (err) => {
console.log(err, 400);
}); //500 9100 [ 100, 100, 500 ] 9200
const p11 = new Promise((resolve, reject) => {
setTimeout(() => {
reject(1)
}, 1000)
})
const p22 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(2)
}, 2000)
})
const p33 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(3)
}, 3000)
})
const pss = Promise.any([p11, p22, p33]);
pss.then((res) => {
console.log(res, 100);
}).catch((err) => {
console.log(err, 200);
})
let dgf = null
const resd = async () => {
const res = await new Promise((resolve) => {
dgf = resolve
})
console.log(res);
}
resd()
setTimeout(() => {
dgf(456)
})
//return(只能在函数中使用), break, continue的使用
//break, continue,return都可以用于for循环,for...in,for...of,while循环,break, continue不能用于forEach,some,map,filter,every,reduce等等
function sdws(){
for (let i = 0; i < 6; i++) {
if (i == 3) {
continue
console.log("for循环", i);//不会执行
}
console.log("for循环", i);
}
}
sdws()
for (let key in [1, 2, 3, 4, 5]) {
if (key > 3) {
continue
}
console.log("for in循环", key);
}
for (let value of [1, 2, 3, 4, 5]) {
if (value > 3) {
continue
}
console.log("for of循环", value);
}
let is = 10
while (is--) {
if (is == 5) {
continue
}
console.log(is)
}
//在forEach使用 return,return false,return true语句实现continue关键字的效果(跳出当前循环,后面的循环会执行)
var arr = [1, 2, 3, 4, 5];
arr.forEach(function (item) {
if (item === 3) {
console.log('forEach')
return true
}
console.log(item);
}); //1 2 forEach 4 5
//下面这两用的不多,了解下就行
//return,return false(它会跳出当前本次循环,后面的循环会执行) return true(它会跳出整个循环,后面的循环不会再执行)
var arr = [1, 2, 3, 4, 5];
arr.some(item => {
if (item === 4) {
return true
}
console.log(item);
});//1 2 3
//return false 跳出整个循环,return ture 也需要写
var arr = [1, 2, 3, 4, 5];
arr.every(item => {
if (item === 4) {
return false
}
console.log(item);
// 如果没有return true 的话,直接输出 1 后,跳出循环
return true
});
//return,return false(它会跳出当前本次循环,后面的循环会执行) return true(它会跳出整个循环,后面的循环不会再执行)
//在for循环,for...in,for...of,while循环中使用return与break效果一样,都是直接跳出整个循环,但是要使用return,for循环,for...in,for...of,while循环必须在一个函数中
let ss = (function () {
let arr = [1, 2, 3, 4, 5]
// for (let i = 0; i < arr.length; i++) {
// console.log(arr[i])
// if (arr[i] == 3) {
// console.log('for')
// return 55
// }
// }
for (let value of [1, 2, 3, 4, 5]) {
if (value == 3) {
return 55
}
console.log("for of循环", value);
}
// for (let key in [1, 2, 3, 4, 5]) {
// if (key == 3) {
// return 55
// }
// console.log("for in循环", key);
// }
// let is = 10
// while (is--) {
// if (is == 5) {
// return 55
// }
// console.log(is)
// }
})();
console.log('---------------------', ss);//ss是55
// forEach方法的返回值是undefined
let ww = (function () {
let arr = [1, 2, 3, 4, 5]
return arr.forEach(item => {
if (item == 3) {
console.log('forEach')
return 33
}
console.log(item)
})
})();
console.log('---------------------', ww);//ww是undefined
//求和的两种方式1.递归 2.reduce
// let ssa=[1,2,3,4]
// function sad(...args) {
// return args.length ? args.pop() + sad(...args) : 0
// }
// console.log(sad(...ssa));
// let sunm = [1, 2, 3, 4].reduce((a, b) => a + b)
// console.log(sunm);
//in和hasOwnProperty区别(in会检测原型上的属性,hasOwnProperty不会)
// let a = { url: "houdunren.com" }
// let b = { name: "houdunren" }
// Object.setPrototypeOf(a,b)
// console.log("name" in a);//
// console.log(a.hasOwnProperty("name"));
// //类中的私有属性
// class Uste{
// #host = "123" //私有属性
// #tem() {//私有方法
// console.log(123)
// }
// constructor() {
// }
// }
// let sw = new Uste()
// sw.#host = 1232
// sw.#tem()
//构造函数和类中的继承(重要需要掌握)
function Asas() {
}
Asas.prototype.show = function () {
console.log(1111)
}
function Bsf() {
}
Bsf.prototype.show = function () {
console.log(222)
}
// Object.setPrototypeOf(Asas.prototype, Bsf.prototype)和Asas.prototype.__proto__=Bsf.prototype是一样的
Asas.prototype = Object.create(Bsf.prototype)
const asas = new Asas()
console.log(asas.show())
console.dir(Asas)
class Qwe {
show() {
console.log(123, this)
}
}
class Awe extends Qwe {
static asd = "45210"
dgdf = 1230
constructor() {
super() //super()相当于A.prototype.constructor.call(this)
}//constructor可以不写,会默认被添加
show() {
//super作为对象时,在普通方法中,指向父类的原型对象;在静态方法中,指向父类
//在子类普通方法中通过super调用父类的方法时,方法内部的this指向当前的子类实例
super.show()//Qwe.prototype.show()
console.log(963)
}
//在子类的静态方法中通过super调用父类的方法时,方法内部的this指向当前的子类,而不是子类的实例
static tem() {
console.log(145)
}
}
//类中的普通方法在Awe.prototype上,普通属性在实例对象上,静态属性和方法都在Awe类(构造函数)上
//类的继承用的是Awe.__proto__=Qwe和Object.setPrototypeOf(Awe.prototype,Qwe.prototype) 两个
const awe = new Awe()
console.log(awe.show(), awe.__proto__.__proto__);
console.log(Awe.tem(), Awe.asd, awe)
console.dir(Awe)
console.log(sum(1, 2)(3)(4)(2, 3, 5));
function sum(...args1) {
let list = []
list.push(...args1)
return function (...args2) {
list.push(...args2)
return function (...args3) {
list.push(...args3)
return function (...args4) {
list.push(...args4)
return list.reduce((pre, next) => {
return pre + next
})
}
}
}
}
//Promise.all并发的缺陷:
//这时候考虑一个场景:如果你的promises数组中每个对象都是http请求,或者说每个对象包含了复杂的调用处理。而这样的对象有几十万个那么会出现的情况是,
//你在瞬间发出几十万http请求(tcp连接数不足可能造成等待),或者堆积了无数调用栈导致内存溢出,这时候,我们就需要考虑对并发做限制。
//使用promise.race和Promise.allSettled,limit控制并发请求数量,limit表示当前最大请求数量
function sleeps(delay, number) {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log(number);
resolve(number)
}, delay);
})
}
const somelists = [() => sleeps(1000, 1), () => sleeps(500, 2), () => sleeps(300, 3), () => sleeps(400, 4)]
async function dosomesing(fns, limit = 3) {
const resultLists=[]
const lists = new Set()
for (const [index,fn] of Object.entries(fns)) {
const promise = fn()
lists.add(promise)
promise.then(res=>{
lists.delete(promise)
resultLists.push({
index,
res,
status: 'fulfilled'
})
}).catch(err=>{
lists.delete(promise)
resultLists.push({
index,
err,
status: 'rejected'
})
})
if (lists.size >= limit) {
try {
await Promise.race(lists)
} catch (err) {
console.log(err)
}
}
}
await Promise.allSettled(lists)
resultLists.sort((a,b)=>a.index-b.index)
return resultLists
}
dosomesing(somelists).then(res=>{
console.log(res,5000);//res是somelists数组按顺序的接口请求结果
})
async function sgdff(){
console.log(123);
}
console.log(sgdff());
console.log(234);
//生成唯一标识
1.
const algorithm=()=>{
let abc=['a','b','c','d','e','f','g','h','i','g','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z'];
let [max,min]=[Math.floor(Math.random()*(10-7+1)+1),Math.floor(Math.random()*(17-10+1)+17)];
abc=abc.sort(()=>0.4-Math.random()).slice(max,min).slice(0,8).join("");
var a=new Date().getTime()+abc;
return a
}
2.
const onlyVal=()=>{
let ran=Math.random()*new Date();
return ran.toString(16).replace(".","")
}
//finally用法的注意事项
// res 的值是 undefined
Promise.resolve(2).then(() => {}, () => {}).then(res=>{
console.log(res);
})
// res 的值是 2
Promise.resolve(2).finally(() => {}).then(res=>{
console.log(res);
})
// err 的值是 undefined
Promise.reject(3).then(() => {}, () => {}).then(err=>{
console.log(err);
})
// err 的值是 3
Promise.reject(3).finally(() => {}).catch(err=>{
console.log(err);
})
//函数中try catch finally中代码的执行顺序(http://t.csdnimg.cn/AGM5p)
// try{...}包含块中的代码有错误,则运行catch(err){...}内的代码,
// 否则不运行catch(err){...}内的代码
try{
asas()
}catch(err){
console.log(err,1111);
}
console.log(222222);
asas()
console.log(33333);
async function f() {
try{
// Promise.reject(200)
await Promise.reject('出错了');
//throw "1230"
//asas.a()
}catch(err){
console.log(err,5300);
return 1230
}finally{
console.log(111);
}
}
f() //浏览器中执行顺序:出错了,5300 111 Promise {<fulfilled>: 1230}
function qse() {
console.log(123856);
return 600
}
function wer() {
try {
//let qwe = qse()
return qse()
} finally {
console.log(456);
//return 300 //finally中有return就只执行finally中的return,try或catch中的return都不会执行了,finally没有return那就执行try或catch中的return
}
}
console.log(wer());//123856 456 600
let test1 = () => { try{ return 123 } finally { return 789 } }
console.log(test1()); //789
let test2 = () => { try{ throw 123 } finally { return 789 } }
console.log(test2());
function ssasd() {
try {
// var a = 1;
console.log(a); //打印a
return 410
console.log(d); //打印d
} catch (err) {
console.log("捕获到了错误a:" + err);
console.log(b); //此时b未定义,没有finally的话就会报错
} finally { //try,catch,finally中有return或代码报错,或throw错误,finally中的return或代码报错或throw错误会覆盖try,catch中的return或代码报错或throw错误
console.log("finally执行");
// console.log(c); //此时c未定义,会报错;
// return 120
}
}
// ssasd()
console.log(ssasd(),123000)
// 使用try catch throw跳出forEach循环
try {
[1,2,3].forEach(function(item,index){
if(item == 2){
throw new Error("Error"); //结束循环
}
console.log(item);
})
} catch(e){
console.log(e,111);
}finally{
console.log("finally",22222);
}
//函数中try catch finally中代码的执行顺序
// for循环数组(arr)并使用splice删除符合数组(arr)条件的某个元素(使用倒序循环这种方式,js中的forEach,for of for in都不行,因为他们底层实现都是基于正序for循环i++)
//数组中删除符合条件的某个元素推荐使用filter方法
//正向循环结果有问题
let arrs = [1,3,3, 2,4, 5];
let len=arrs.length
for (let i = 0; i < len; i++) {
if (arrs[i] === 3) {
arrs.splice(i, 1); // 删除元素
}
}
console.log(arrs)
let arr = [1, 1,2, 1,3]
let tems=arr.filter(v=>v!==1) //推荐使用filter方法,简单准确
for (let i = arr.length-1; i>=0; i--) { //倒序循环也可以,就是有些复杂
if (arr[i] === 1) {
arr.splice(i, 1);
};
};
console.log(arr);
//深度冻结
// methods:{
// deepFreeze(object) {
// // 获取对象的属性名
// const propNames = Reflect.ownKeys(object);
// // 冻结自身前先冻结属性
// for (const name of propNames) {
// const value = object[name];
// if ((value && typeof value === "object") || typeof value === "function") {
// this.deepFreeze(value);
// }
// }
// return Object.freeze(object);
// }
// }
// let x=1
// let y=2
// // let [x,y]=[y,x] //错误写法
// [x,y]=[y,x] //正确写法
//过期闭包(https://segmentfault.com/a/1190000020805789)参考这个链接内容
function createIncrement(i) {
let value = 0;
function increment() {
value += i;
console.log(value);
const message = `Current value is ${value}`;
return function logValue() {
console.log(message);
};
}
return increment;
}
const inc = createIncrement(1);
inc()(); // 打印 1
inc()(); // 打印 2
inc()();
//set和map的forEach用法
const set=new Set([1,2])
set.forEach((item,index)=>{
console.log(item,index);//1 1 2 2 item(键值)和index(键名)是相同的
})
// 在node中报错 用run code的时候报错,在浏览器中正常
set.keys().forEach((item,index)=>{
console.log(item,index);// 1 0 2 1 遍历方式和数组一样
})
set.values().forEach((item,index)=>{
console.log(item,index);// 1 0 2 1 遍历方式和数组一样
})
set.entries().forEach((item,index)=>{
console.log(item,index);// [1,1] 0 [2,2] 1 键名和键值是相等的, 遍历方式和数组一样
})
// 在node中报错 用run code的时候报错,在浏览器中正常
const map=new Map([[1,2],[3,4]])
map.forEach((item,index)=>{
console.log(item,index);//2 1 4 3 item(键值)和index(键名)
})
map.keys().forEach((item,index)=>{
console.log(item,index);// 1 0 3 1 遍历方式和数组一样
})
map.values().forEach((item,index)=>{
console.log(item,index);// 2 0 4 1 遍历方式和数组一样
})
map.entries().forEach((item,index)=>{
console.log(item,index);// [1,2] 0 [3,4] 1 遍历方式和数组一样
})
Object.entries(a) //a参数的类型是对象或带有length属性的类数组
Object.fromEntries(a) //a参数的类型是可迭代的对象Iterable
// JS---使用parseInt()和parseFloat()转换数字
// parseInt()和parseFloat()也是把其他数据类型转换为number类型的。但是它们的处理原理和Number()完全不一样。
// 它们是把字符串类型转换为数字类型,如果处理的值不是字符串,需要先转换为字符串,然后再去转换为number类型。
// 它们的转换规则是:从字符串最左边开始查找,把找到的有效数字字符转换为数字,一直遇到一个非有效数字字符为止,则结束查找
// console.log(Number('12px')) // => NaN
// console.log(parseInt('12px')) // => 12
// console.log(parseInt('12px345')) // => 12
// console.log(parseInt('12.5px')) // => 12
// console.log(parseFloat('12.5px')) // => 12.5 parseFloat只比parseInt多识别一个小数点
async function async1(){
console.log(1);
console.log(await async2());
console.log(3);
}
async function async2(){
console.log(2);
return await 500 //这里不加await 整个结果是 1 2 Promise1 500 3 Promise2 Promise3 Promise4 加了await结果是 1 2 Promise1 Promise2 500 3 Promise3 Promise4
}
async1()
new Promise(resolve=>{
console.log('Promise1');
resolve()
}).then(res=>{
console.log('Promise2');
}).then(res=>{
console.log('Promise3');
}).then(res=>{
console.log('Promise4');
})
//这3种情况可以好好理解下
let i=0
while(i<5){
// function ssgf(){
// setTimeout(()=>{
// setTimeout(()=>{
// setTimeout(()=>{
// console.log(i,"00000")
// })
// })
// })
// }
// ssgf()//5 5 5 5 5
//注意函数传参和不传的区别
function ssgf(i){
setTimeout(()=>{
setTimeout(()=>{
setTimeout(()=>{
console.log(i,"00000")
})
})
})
}
ssgf(i) //0 1 2 3 4
i++
}
for(let value of [1,2,3,4]){
const gdff=value+'sss'
function ssgf(){
setTimeout(()=>{
setTimeout(()=>{
setTimeout(()=>{
console.log(value,gdff,1111)
})
})
})
}
ssgf()
}
[1,2,3,4].forEach(value=>{
function ssgf(){
setTimeout(()=>{
setTimeout(()=>{
setTimeout(()=>{
console.log(value,222222)
})
})
})
}
ssgf()
})
//这3种情况可以好好理解下
// 当你在函数内部的for循环中使用return时,当代码执行到return时,它会立即终止循环以及整个函数的执行
// function add(a, b) {
// return a + b; // 先计算 a + b 的值,然后返回这个计算结果,所以,简而言之,是先执行表达式,然后return这个表达式的值
// }
// let result = add(2, 3); // 这里 result 将会是 5,因为函数执行了 return 表达式 2+3 并返回了结果
//获取一个变量i的余数i%5 它的余数是0,1,2,3,4 规律总结:%后面的值是4 余数就是0123 ,%后面的值是3 余数就是012
//当直接使用 == 或 === 操作符比较两个对象时,实际上比较的是这两个对象的引用是否指向同一个内存地址,而不是比较它们内部的属性值是否相等
//Date.now()获取当前时间的毫秒级时间戳
//createRenderer渲染dom和cavas过程学习下(可以有时间再学,崔晓瑞视频)
//正则(可以有时间再学,可以看下王红元视频)
//向军大叔路由视频(有时间再学)
//js 中对象的访问器在对象冻结之后为什么还可以访问
在 JavaScript 中,访问器属性(由 get 和 set 方法定义的属性)是对象的一部分,但它们并不存储值,而是提供获取和设置值的途径。
即使一个对象被 Object.freeze() 方法冻结,访问器属性仍然可以被访问,
不存储值:访问器属性不直接存储值,它们只是定义了当属性被访问或赋值时应执行的操作。因此,即使对象被冻结,访问这些属性不会违反对象的不可变性
{
let a=1
if(a==1){
a=2
console.log(100)
}
else if(a==2){
console.log(200)
}
}
function buildTree(data, parentId = 0) {
return data
.filter(item => item.pid === parentId)
.map(item => ({
...item,
children: buildTree(data, item.id)
}));
}
const flatData = [
{ id: 1, pid: 0, name: "body" },
{ id: 2, pid: 1, name: "title" },
{ id: 3, pid: 2, name: "div" }
];
const treeData = buildTree(flatData);
console.log(treeData);
function multiplication(x) {
let result = x;
function multiply(y) {
if (y !== undefined) {
result *= y;
return multiply;
} else {
return result;
}
}
return multiply;
}
// 测试
console.log(multiplication(4)()); // 4
console.log(multiplication(4)(5)()); // 20
console.log(multiplication(4)(5)(6)()); // 120
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。