JS必备知识点
将工作中遇到的问题记录在此
-
数据类型 null对象
值类型(基本类型):字符串(String)、数字(Number)、布尔(Boolean)、对空(Null)、未定义(Undefined)、Symbol。
引用数据类型:对象(Object)、数组(Array)、函数(Function)。 -
NAN数值型
NaN 即非数值(Not a Number),NaN 属性用于引用特殊的非数字值,该属性指定的并不是不合法的数字。
NaN 属性 与 Number.Nan 属性相同。
提示: 请使用 isNaN() 来判断一个值是否是数字。原因是 NaN 与所有值都不相等,包括它自己。是Number中的一个值
-
undefined和null的区别
undefined表示一个未声明的变量,或已声明但没有赋值的变量,或一个并不存在的对象属性。
nulLL定义并赋值了,只是值为nuLL
-
数组属不属于对象
数组是一种特殊类型的对象。 在 JavaScript 中对数组使用 typeof 运算符会返回 “object”。
-
typeof与instanceof区别是什么
typeof主要用来判断基础数据类型,instanceof则是用来判断引用数据类型。
-
事件的绑定 三种
-
在DOM元素中直接绑定;
-
在JavaScript代码中绑定;
-
3.绑定事件监听函数。
使用removeEventListener() 方法来移除 addEventListener() 方法添加的事件句柄。
element.addEventListener(event, function, useCapture)
参数 描述 event 必须。字符串,指定事件名。注意: 不要使用 “on” 前缀。 例如,使用 “click” ,而不是使用 “onclick”。提示: 所有 HTML DOM 事件,可以查看我们完整的 HTML DOM Event 对象参考手册。 function 必须。指定要事件触发时执行的函数。 当事件对象会作为第一个参数传入函数。 事件对象的类型取决于特定的事件。例如, “click” 事件属于 MouseEvent(鼠标事件) 对象。 useCapture 可选。布尔值,指定事件是否在捕获或冒泡阶段执行。 可能值: * true - 事件句柄在捕获阶段执行 * false- false- 默认。事件句柄在冒泡阶段执行 移除 addEventListener() 方法添加的 “mousemove” 事件:
// 向 <div> 元素添加事件句柄 document.getElementById("myDIV").addEventListener("mousemove", myFunction); // 移除 <div> 元素的事件句柄 document.getElementById("myDIV").removeEventListener("mousemove", myFunction);
-
-
鼠标事件哪几个 七个
事件类型 说明 click 单击鼠标左键时发生,如果右键也按下则不会发生。当用户的焦点在按钮上并按了 Enter 键时,同样会触发这个事件 dblclick 双击鼠标左键时发生,如果右键也按下则不会发生 mousedown 单击任意一个鼠标按钮时发生 mouseout 鼠标指针位于某个元素上且将要移出元素的边界时发生 mouseover 鼠标指针移出某个元素到另一个元素上时发生 mouseup 松开任意一个鼠标按钮时发生 mousemove 鼠标在某个元素上时持续发生 -
事件冒泡,事件捕获
-
事件冒泡
在 冒泡 中,内部元素的事件会先被触发,然后再触发外部元素,即: <p> 元素的点击事件先触发,然后会触发 <div> 元素的点击事件。false
-
事件捕获
在 捕获 中,外部元素的事件会先被触发,然后才会触发内部元素的事件,即: <div> 元素的点击事件先触发 ,然后再触发 <p> 元素的点击事件。true
-
-
事件委托
事件委托,通俗地来讲,就是把一个元素响应事件(click、keydown…)的函数委托到另一个元素;
一般来讲,会把一个或者一组元素的事件委托到它的父层或者更外层元素上,真正绑定事件的是外层元素,当事件响应到需要绑定的元素上时,会通过事件冒泡机制从而触发它的外层元素的绑定事件上,然后在外层元素上去执行函数。
-
闭包的概念
闭包是一种保护私有变量的机制,在函数执行时形成私有的作用域,保护里面的私有变量不受外界干扰。
直观的说就是形成一个不销毁的栈环境。
-
写个例子
var add = (function () { var counter = 0; return function () {return counter += 1;} })(); add(); add(); add();
-
-
变量提升
解析器会先解析代码,然后把声明的变量的声明提升到最前,这就叫做变量提升。
使用
var
定义的代码,声明会被提升到前面(依旧在函数内部),赋值还在原位置ES6之前我们一般使用var来声明变量,提升简单来说就是把我们所写的类似于var a = 123;这样的代码,声明提升到它所在作用域的顶端去执行,到我们代码所在的位置来赋值。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
console.log(v1);//undefined var v1 = 100; function foo() { console.log(v1);//undefined var v1 = 200; console.log(v1);//200 } foo(); console.log(v1); //100
-
this
-
在方法中,this 表示该方法所属的对象。
-
如果单独使用,this 表示全局对象。
-
在函数中,this 表示全局对象。
-
在函数中,在严格模式下,this 是未定义的(undefined)。
-
在事件中,this 表示接收事件的元素。
-
类似 call() 和 apply() 方法可以将 this 引用到任何对象。
-
-
getEID和getEclass区别
id只会获取一个对象
class会获取一个伪数组
-
浏览器加载顺序
-
用户输入网址(假设是个 HTML 页面,并且是第一次访问),浏览器向服务器发出请求,服务器返回 HTML 文件;
-
浏览器开始载入 HTML 代码,发现 <head> 标签内有一个 <link> 标签引用外部 CSS 文件;
-
浏览器又发出 CSS 文件的请求,服务器返回这个 CSS 文件;
-
浏览器继续载入 HTML 中 <body> 部分的代码,并且 CSS 文件已经拿到手了,可以开始渲染页面了;
-
浏览器在代码中发现一个 < img > 标签引用了一张图片,向服务器发出请求。此时浏览器不会等到图片下载完,而是继续渲染后面的代码;
-
服务器返回图片文件,由于图片占用了一定面积,影响了后面段落的排布,因此浏览器需要回过头来重新渲染这部分代码;
-
浏览器发现了一个包含一行 JavaScript 代码的 <script> 标签,赶快运行它;
-
JavaScript 脚本执行了这条语句,它命令浏览器隐藏掉代码中的某个 <div>(style.display=”none”)。杯具啊,突然就少了这么一个元素,浏览器不得不重新渲染这部分代码;
-
终于等到了 </html> 的到来,浏览器泪流满面……
-
等等,还没完,用户点了一下界面中的“换肤”按钮,JavaScript 让浏览器换了一下 <link> 标签的 CSS 路径;
-
浏览器召集了在座的各位 < div><span>< ul>< li> 们,“大伙儿收拾收拾行李,咱得重新来过……”,浏览器向服务器请求了新的CSS文件,重新渲染页面。
-
-
回调函数的理解
回调函数就是一个函数,它是在我们启动一个异步任务的时候就告诉它:等你完成了这个任务之后要干什么。这样一来主线程几乎不用关心异步任务的状态了,他自己会善始善终。
-
数组创建
-
字面量方式(json方式)
var arr1 = []; //创建一个空数组 var arr2 = [5]; //创建一个具有单个元素的数组 var arr3 = [5,6,7]; //创建一个具有多个元素的数组
-
构造函数方式
var arr1 = new Array(); //创建一个空数组 var arr2 = new Array(5); //创建一个长度为5,值为空的数组 var arr3 = new Array(5,6,7); //创建一个具有多个元素的数组
-
-
数组的方法
方法名 对应版本 功能 原数组是否改变 concat() ES5- 合并数组,并返回合并之后的数据 no join() ES5- 使用分隔符,将数组转为字符串并返回 no pop() ES5- 删除最后一位,并返回删除的数据 yes shift() ES5- 删除第一位,并返回删除的数据 yes unshift() ES5- 在第一位新增一或多个数据,返回长度 yes push() ES5- 在最后一位新增一或多个数据,返回长度 yes reverse() ES5- 反转数组,返回结果 yes slice() ES5- 截取指定位置的数组,并返回 no sort() ES5- 排序(字符规则),返回结果 yes splice() ES5- 删除指定位置,并替换,返回删除的数据 yes toString() ES5- 直接转为字符串,并返回 no valueOf() ES5- 返回数组对象的原始值 no indexOf() ES5 查询并返回数据的索引 no lastIndexOf() ES5 反向查询并返回数据的索引 no forEach() ES5 参数为回调函数,会遍历数组所有的项,回调函数接受三个参数,分别为value,index,self;forEach没有返回值 no map() ES5 同forEach,同时回调函数返回数据,组成新数组由map返回 no filter() ES5 同forEach,同时回调函数返回布尔值,为true的数据组成新数组由filter返回 no every() ES5 同forEach,同时回调函数返回布尔值,全部为true,由every返回true no some() ES5 同forEach,同时回调函数返回布尔值,只要由一个为true,由some返回true no reduce() ES5 归并,同forEach,迭代数组的所有项,并构建一个最终值,由reduce返回 no reduceRight() ES5 反向归并,同forEach,迭代数组的所有项,并构建一个最终值,由reduceRight返回 no -
==与===的区别
===绝对相等,类型数值
==类型可自动转化
-
计时器
1.在JavaScript中,我们可以在设定的时间间隔之后来执行代码,而不是在函数被调用后立即执行。
2.计时器类型:
(1)一次性计时器:仅在指定的延迟时间之后触发一次。
(2)间隔性触发计时器:每隔一定的时间间隔就触发一次
3.方法描述
setTimeout() 指定的延迟时间之后来执行代码
clearTimeout() 取消setTimeout的设置
setInterval() 每隔指定的时间执行代码
clearInterval() 取消setInterval的设置
-
正则表达式
-
一、正则表达式概述
正则表达式(Regular Expression) 是用于匹配字符串中字符串组合的模式,在js中,正则表达式是对象(js万物皆对象) 用于:创建密码 提交表单,匹配字符串,过滤敏感词,提取特定的字符串。用于搜索 前端目前主要利用正则表达式来完成表单的验证 通俗来说就是匹配信息主要有精准匹配和模糊匹配两种
-
二、正则表达式的创建
两种方式:
1.RegExp 创建 Var regexp = new RegExp(/123/)
2.利用正则表达式自变量来创建(最常用的方法) Var rg = /123/
创建完成肯定要检查字符串是否符合正则表达式。 测试正则表达式text 检测字符是否符合正则表达式 会返回true和false。其参数是测试字符串regexobj .test(str) str是我们写的字符串的内容 -
三、正则表达式内容具体含义
因为我也是初学者,就 尽可能用通俗的语言去写,没有使用倒专业名词,请见谅。
边界符(一般用于精准匹配)
^以它开始 $以它结束
量词符
*重复零次或更多次
+重复一次或更多次
?重复零次或一次
{n}重复n次
{n,}重复n次或更多次
{n,m}重复n到m次
- 或者 或|括号总结
中括号字符总结匹配方括号里面的任意字符[] 大括号{ }量词符,里面表示重复次数; 小括号,表示优先级;
常见的字符简写形式
\d就是[0-9] 表示一位数字 英文是digit(数字)
\D[^0-9] 表示除了数字外的任意字符。
\w[0-9a-zA-Z].表示数字,大小写字母和下划线。记忆方式:w是Word的简写字符
\W(大写W)[^0-9a-zA-Z].非单词字符。
\s是[ \t\v\n\r\f]。表示空白符,包括空格、水平制表符、垂直制表符、换行符、回车符、换页符。记忆方式:s是space character的首字母。
\S是[^ \t\v\n\r\f]。 非空白符。
.就是[^\n\r\u2028\u2029]。通配符,表示几乎任意字符。换行符、回车符、行分隔符和段分隔符除外。记忆方式:想想省略号…中的每个点,都可以理解成占位符,表示任何类似的东西。i 执行对大小写不敏感的匹配。 g 执行全局匹配(查找所有匹配而非在找到第一个匹配后停止)。 m 执行多行匹配。 元字符 描述 \d 查找数字。 \s 查找空白字符。 \b 匹配单词边界。 \uxxxx 查找以十六进制数 xxxx 规定的 Unicode 字符。 [abc] 查找方括号之间的任何字符。 [0-9] 查找任何从 0 至 9 的数字。 (x|y) 查找任何以 | 分隔的选项。 -
四、常见的正则验证代码
验证字母:/^[a-zA-Z]+$/
验证长度为3的字符:/^.{3}$/
验证由26个英文字母组成的字符串:/^[A-Za-z]+$/
验证日期YYYY-MM-DD:/^(\d{1,4})(-|\/)(\d{1,2})\2(\d{1,2})$/
验证邮编:/^\d{6}$/
验证整数:/^[-+]?\d*$/
验证小数:/^[-+]?\d+(.\d+)?$/
验证中文:/^[\u0391-\uFFE5]+$/
验证邮箱:/^\w+([-+.]\w+)@\w+([-.]\w+).\w+([-.]\w+)*$/
验证手机号:/^1[3456789]\d{9}$/
验证身份证:/^\d{6}(18|19|20)?\d{2}(0[1-9]|1[12])(0[1-9]|[12]\d|3[01])\d{3}(\d|X)$/
-
五、js中常用的正则表达式
// 验证输入的内容是否是空 isNull:function(idStr){ var str = document.getElementById(idStr).value.trim(); var regex = /\S/; if(!regex.test(str)){ alert("文本框不能为空,请输入内容!"); } } // 验证输入的字符是否是英文字母 isLetter:function(idStr){ var str = document.getElementById(idStr).value.trim(); var regex = /^[a-zA-Z]+$/; if(!regex.test(str)){ alert("请输入正确的英文字母!"); } } // 验证日期格式是否为YYYY-MM-DD格式 isDate:function(idStr){ var str = document.getElementById(idStr).value.trim(); var regex = /^(\d{1,4})(-|\/)(\d{1,2})\2(\d{1,2})$/; var r = str.match(regex); // 使用match方法获取指定字符串的值 if(r==null){ alert("请输入正确的日期格式!"); } } // 验证日期格式是否为YYYY-MM-DD hh:mm:ss格式 isDateTime:function(idStr){ var str = document.getElementById(idStr).value.trim(); var regex = /^(\d{1,4})(-|\/)(\d{1,2})\2(\d{1,2}) (\d{1,2}):(\d{1,2}):(\d{1,2})$/; var r = str.match(regex); // 使用match方法获取指定字符串的值 if(r==null){ alert("请输入正确的日期格式!"); } } // 验证整数 isInteger:function(idStr){ var str = document.getElementById(idStr).value.trim(); var regex = /^[-+]?\d*$/; if(!regex.test(str)){ alert("请输入正确的整数!"); } } // 验证双精度 isDouble:function(idStr){ var str = document.getElementById(idStr).value.trim(); var regex = /^[-+]?\d+(.\d+)?$/; if(!regex.test(str)){ alert("请输入正确的小数!"); } } // 验证中文 isChinese(idStr){ var str = document.getElementById(idStr).value.trim(); var regex = /^[\u0391-\uFFE5]+$/; if(!regex.test(str)){ alert("请输入正确的中文!"); } } // 验证邮箱 isEmail(idStr){ var str = document.getElementById(idStr).value.trim(); var regex = /^\w+([-+.]\w+)*@\w+([-.]\w+)*.\w+([-.]\w+)*$/; if(!regex.test(str)){ alert("请输入正确的邮箱格式!"); } } // 验证手机号 isPhone(idStr){ var str = document.getElementById(idStr).value.trim(); var regex = /^1[3456789]\d{9}$/; if(!regex.test(str)){ alert("请输入正确的手机号!"); } } // 验证身份证 isIdCard(idStr){ var str = document.getElementById(idStr).value.trim(); var regex = /^\d{6}(18|19|20)?\d{2}(0[1-9]|1[12])(0[1-9]|[12]\d|3[01])\d{3}(\d|X)$/; if(!regex.test(str)){ alert("请输入正确的身份证号码!"); } } //注:正则表达式里面不许要加引号,不管是字符串型还是数字型
-
-
原型原型链
-
JS异步同步
JavaScript 中的异步操作函数往往通过回调函数来实现异步任务的结果处理。
Promise
学习异步时,对函数里面的 resolve() 不太理解,后来上网查了查,知道了他的作用:
Promise 对象代表一个异步操作,有三种状态:Pending(进行中)、Resolved(已完成,又称 Fulfilled)和 Rejected(已失败)。
通过回调里的 resolve(data) 将这个 promise 标记为 resolverd,然后进行下一步 then((data)=>{//do something}),resolve 里的参数就是你要传入 then 的数据。new Promise(function (resolve, reject) { var a = 0; var b = 1; if (b == 0) reject("Divide zero"); else resolve(a / b); }).then(function (value) { console.log("a / b = " + value); }).catch(function (err) { console.log(err); }).finally(function () { console.log("End"); });
-
DOM对象获取
-
通过 id 找到 HTML 元素
var x=document.getElementById("intro");
-
通过标签名查找 HTML 元素
var x=document.getElementById("main"); var y=x.getElementsByTagName("p");
-
通过类名找到 HTML 元素
var x=document.getElementsByClassName("intro");
-
-
伪数组
1,function内的arguments 。
2,通过document.forms,Form.elements,Select.options,document.getElementsByName() ,
document.getElementsByTagName() ,childNodes/children 等方式获取的集合(HTMLCollection,NodeList)等。
3,特殊写法的对象 ,如
Js代码 收藏代码
var obj={};
obj[0] = “一”;
obj[1] = “二”;
obj[2] = “三”;
obj.length = 3;
它们不具有数组的一些方法如push, pop, shift, join等。有时候需要将这些伪数组转成真正的数组,这样可以使用push, pop等方法。
function log(){ var args = Array.prototype.slice.call(arguments); //为了使用unshift数组方法,将argument转化为真正的数组 args.unshift('(app)'); console.log.apply(console, args); };
-
ES6
-
let、const和block作用域
let创建块级作用域
const创建块级作用域,声明常量
const 声明的常量类似于指针,它指向某个引用,也就是说这个「常量」并非一成不变的
-
let 关键词声明的变量不具备变量提升(hoisting)特性
-
let 和 const 声明只在最靠近的一个块中(花括号内)有效
-
当使用常量 const 声明时,请使用大写变量,如:CAPITAL_CASING
-
const 在声明时必须被赋值
-
-
箭头函数
去掉function在括号后面添加=>
var getPrice = function() { return 4.55; }; // Implementation with Arrow Function var getPrice = () => 4.55;
-
函数参数默认值
传入参数时就可以设置默认值
let getFinalPrice = (price, tax=0.7) => price + price * tax; getFinalPrice(500); // 850
-
Spread/Rest操作符( …Arr)
将数组展开
function foo(...args) { console.log(args); } foo( 1, 2, 3, 4, 5); // [1, 2, 3, 4, 5]
-
对象词法扩展
function getCar(make, value) { return { // 简写变量 make, // 等同于 make: make value, // 等同于 value: value // 属性可以使用表达式计算值 ['make' + make]: true, // 忽略 `function` 关键词简写对象函数 depreciate() { this.value -= 2500; } }; } let car = getCar('Barret', 40000); // output: { // make: 'Barret', // value: 40000, // makeBarret: true, // depreciate: [Function: depreciate] // }
-
二进制和八进制字面量
数字前面添加 0o 或者0O 即可将其转换为八进制值
let oValue = 0o10; console.log(oValue); // 8 let bValue = 0b10; // 二进制使用 `0b` 或者 `0B` console.log(bValue); // 2
-
对象和数组解构
function foo() { return [1,2,3]; } let arr = foo(); // [1,2,3] let [a, b, c] = foo(); console.log(a, b, c); // 1 2 3 function bar() { return { x: 4, y: 5, z: 6 }; } let {x: x, y: y, z: z} = bar(); console.log(x, y, z); // 4 5 6
-
对象超类(没看懂)
ES6 允许在对象中使用 super 方法:
var parent = { foo() { console.log("Hello from the Parent"); } } var child = { foo() { super.foo(); console.log("Hello from the Child"); } } Object.setPrototypeOf(child, parent); child.foo(); // Hello from the Parent // Hello from the Child
-
模板语法和分隔符
-
${ … } 用来渲染一个变量
-
` 作为分隔符
let user = 'Barret'; console.log(Hi ${user}!); // Hi Barret!
-
-
for…of VS for…in
for…in:遍历键名,会遍历对象的整个原型链,性能差。
for…of:后者遍历键值,只遍历当前对象不会遍历原型链,将异步循环变成同步循环。
在ES5中可以使用forEach循环数组,但无法中途跳出break命令或者return。而使用for…of循环可以与break、continue、return配合使用,跳出循环。
for…in用来遍历对象而生,不适用数组。
for…of可以用来遍历数组、类数组对象、字符串、set、Map等。
-
Map 和 WeakMap
-
Map
-
Map 的特点
-
Map 默认情况下不包含任何键,所有键都是自己添加进去的。不同于
Object
原型链上有一些默认的键。 -
Map 的键可以是「任意类型」数据,就连函数都可以。
-
Map 的键值对个数可以「轻易」通过
size
属性获取,Object
需要手动计算。 -
Map 在频繁增删键值对的场景下「性能」要比
Object
好。
-
-
什么时候用 Map
-
要添加的键值名和
Object
上的默认键值名冲突,又不想改名时,「用 Map」 -
需要
String
和Symbol
以外的数据类型做键值时,「用 Map」 -
键值对很多,有需要计算数量时,「用 Map」
-
需要频繁增删键值对时,「用 Map」
-
-
Map 实例属性和方法
-
set
set方法设置键名key对应的键值为
value
,然后会返回整个Map
结构,如果设置的key已经存在,则会更新value
值,否则会新生成该键方法一:
const dataMap = new Map(); dataMap.set('name','小黑');
方法二:
const longMap = new Map().set(1,'a').set(2,'b'); console.log(longMap);
-
get
通过get方法读取key对应的键值,如果传入的键值不存在,则会返回
undefined
const dataMap = new Map(); dataMap.set('name','小黑'); console.log(dataMap.get('name'));
-
has
判断传入的键是否存在当前
Map
对象中,该方法返回一个布尔值const dataMap = new Map(); dataMap.set('name','小黑'); console.log(dataMap.has('name')); //true console.log(dataMap.has('sex')); // false
-
delete
删除传入的键,返回
true
,如果删除失败,则返回falseconst dataMap = new Map( ); dataMap. set( 'name' ,'小黑' ); //在删除之前查询是否存在该键 console.log(dataMap.has('name'));// true //删除该键 dataMap.delete('name') //再次查看是否存在该键,发现已移除 console.log( dataMap.has('name'));// false
-
-
遍历方法
可以采用for…of循环和forEach两种方法。由于Map实例会维护键值对的插入顺序,因此可以根据插入顺序进行遍历采用「for…of」
for…of可以遍历有iterator接口的数据结构
-
keys():返回键名的遍历器
-
values():返回键值的遍历器
-
entries():返回键值对的遍历器
-
forEach():使用回调函数遍历每个成员
-
-
Map类型转化
Map 转为数组
let map = newMap() let arr = [...map]
数组转为 Map
let map = newMap(arr)
Map 转为对象
let obj = {} for (let [k, v] of map) { obj[k] = v } //对象转为 Map for( let k ofObject.keys(obj)){ map.set(k,obj[k]) }
-
-
WeakMap
WeakMap
是 ES6 中新增的一种集合类型,叫做“弱映射”。它和Map是兄弟关系,与Map的区别就在于这个「弱字」,API 还是Map的那套(只有set get has delete)这其实描述的是 JS 中「垃圾回收」程序对待“弱映射”中键的方式
-
WeakMap的特点
-
WeakMap 只能将对象作为键名
只接受对象作为键名(null 除外),不接受其他类型的值作为键名
-
WeakMap 的键名引用的对象是弱引用
WeakMap 保持了对键名所引用的对象的弱引用,即垃圾回收机制不将该引用考虑在内。只要所引用的对象的其他引用都被清除,垃圾回收机制就会释放该对象所占用的内存。也就是说,一旦不再需要,WeakMap 里面的键名对象和所对应的键值对会自动消失,不用手动删除引用。
-
不可遍历
正因为WeakMap对键名所引用的对象是弱引用关系,因此WeakMap内部成员是会「却决于垃圾回收机制有没有执行」,运行前后成员个数很可能是不一样的,而垃圾回收机制的执行又是「不可预测」的,因此不可遍历
-
-
-
Map 和 WeakMap 的区别
-
Map 的键可以是任意类型,WeakMap 只接受对象作为键(null除外),不接受其他类型的值作为键
-
Map 的键实际上是跟内存地址绑定的,只要内存地址不一样,就视为两个键;WeakMap 的键是弱引用,键所指向的对象可以被垃圾回收,此时键是无效的
-
Map 可以被遍历, WeakMap 不能被遍历
-
-
-
Set 和 WeakSet
-
Set
Set是ES6 提供的新的数据结构。它类似于数组,只有属性值,并且成员的值都是唯一的,没有重复的值。
-
WeakSet
WeakSet 结构与 Set 类似,weakSet的成员值是唯一的,并且 WeakSet 的成员只能是对象,而不能是其他类型的值
-
传递参数的讲究
Set、WeakSet传递的参数必须具备迭代接口,比如:数组,字符串,arguments等,迭代接口就是指在原型上有:Symbol(Symbol.iterator)
-
Set 与 WeakSet 之间的区别
-
与Set相比,WeakSet 只能是对象的集合,而不能是任何类型的任意值。
-
WeakSet持弱引用:集合中对象的引用为弱引用。 如果没有其他的对 WeakSet中对象的引用,那么这些对象会被当成垃圾回收掉。 这也意味着WeakSet中没有存储当前对象的列表。 WeakSet 是不可枚举的。
-
ES6之深入Set 与 WeakSet的知识讲解_huangyangquan3的博客-CSDN博客_weakset和set区别
-
-
类
类是用于创建对象的模板。
我们使用 class 关键字来创建一个类,类体在一对大括号 {} 中,我们可以在大括号 {} 中定义类成员的位置,如方法或构造函数。
每个类中包含了一个特殊的方法 constructor(),它是类的构造函数,这种方法用于创建和初始化一个由 class 创建的对象。
class ClassName { constructor() { ... } }
使用类
定义好类后,我们就可以使用 new 关键字来创建对象:
class People { constructor(name, sex) { this.name = name; this.sex = sex; } } let site = new People("小黑", "男");
创建对象时会自动调用构造函数方法 constructor()。
类表达式
类表达式是定义类的另一种方法。类表达式可以命名或不命名。命名类表达式的名称是该类体的局部名称
// 未命名/匿名类 let People = class { constructor(name, sex) { this.name = name; this.sex = sex; } }; console.log(People.name); // output: "People" // 命名类 let People = class People2 { constructor(name, sex) { this.name = name; this.sex = sex; } }; console.log(People.name); // 输出: "People2"
构造方法
构造方法是一种特殊的方法:
-
构造方法名为 constructor()。
-
构造方法在创建新对象时会自动执行。
-
构造方法用于初始化对象属性。
-
如果不定义构造方法,JavaScript 会自动添加一个空的构造方法。
-
-
Symbol
什么是Symbol
JavaScript标准中规定对象的key只能是 String 或 Symbol 类型,区别在于 String 类型的key可以重复而 Symbol 类型的key是唯一的。Symbol 的本质是表示一个唯一标识。每次创建一个Symbol,它所代表的值都不可能重复,该值的内部实现可以视为一段数字(类似:3423498431987719455…)。所以理论上 Symbol 的存在只有一个意义:用于必须使用唯一值的场景。
创建Symbol
创建 Number、String等基本类型的实例有两种方法:通过构造函数(或者叫工厂函数)和文字语法糖。比如:
// 构造函数
const num = Number(3);
const str = String(‘hi’);// 语法糖
const num = 3;
const str = ‘hi’;显然使用语法糖更加简洁。但是 Symbol 只能通过构造函数 Symbol() 进行创建:
const sym = Symbol();
或者,我们可以传入一个字符串参数(descriptor)用于描述该Symbol:
const sym = Symbol('cat');
注意:传入的参数对 Symbol 值的产生并无影响,因为就算每次传入的参数都一样,生成的Symbol值也是不等的。该参数的作用仅用于描述被创建的Symbol,以便debug时可以识别出Symbol的含义。 所以,下列等式结果为 false:
Symbol(‘cat’) === Symbol(‘cat’) // false
Symbol.for(key)和 Symbol() 类似,Symbol.for(key) 也可以创建一个Symbol,不一样的是:创建的 Symbol 是全局的(在全局Symbol表中注册),而如果全局已经存在相同 key 的Symbol,则直接返回该Symbol。所以,下列等式结果为 true:
Symbol.for('cat') === Symbol.for('cat') // true
如何使用Symbol
其实 Symbol 本身很简单,但是如何把它用好、且用的恰到好处却使人困惑,因为在平常工作中并没有多少非Symbol不用的场景。但是用对了Symbol会对你的代码质量有不少提升。
-
迭代器(Iterators)
简介
迭代器是一种设计模式,可在容器对象 如 链表、数组上遍历,无需关心容器对象的内存分配的实现细节。简单的理解就是可以一个一个的依次拿到其中的数据,类似一个移动的指针,但是会告诉我们什么时候结束。
js 中的迭代器是什么样子的
在javascript 中迭代器是一个特殊对象,这个迭代器对象有一个next()方法,每次调用都返回一个对象(结果对象)。结果对象有两个属性:一个是value,表示下一个将要返回的值;另一个是done,它是一个布尔类型的值,如果已经迭代到序列中的最后一个值,则它为 true。迭代器还会保存一个内部指针,用来指向当前集合中值的位置,每调用一次next()方法,都会返回下一个可用的值,类似下面这个对象的结构。
{ next: function () { return { value:'', done: true / false } } }
迭代协议
随着javascript 语言的能力进一步提升,新增了一些新的数据类型 如 Map、Set、WeakMap 等,为了这些不同的数据结构,可以统一的迭代,es6 增加了迭代协议这个东西。
迭代协议并不是新的内置实现或语法,而是协议。这些协议可以被任何遵循某些约定的对象来实现。
迭代协议具体分为两个协议:可迭代协议和迭代器协议。
简单的理解就是在js 中任何对象只要满足迭代协议就可以遍历
可迭代协议
要成为可迭代对象, 一个对象必须实现 @@iterator 方法。这意味着对象(或者它原型链上的某个对象)必须有一个键为 @@iterator 的属性,可通过常量 Symbol.iterator 访问该属性:
简单的理解,你想让一个东西可以遍历,那么这个东西要有一个 @@iterator ,这个属性可以通过Symbol.iterator 访问
属性 值 [Symbol.iterator] 一个无参数的函数,其返回值为一个符合迭代器协议的对象。 迭代器协议
迭代器协议定义了产生一系列值(无论是有限个还是无限个)的标准方式。当值为有限个时,所有的值都被迭代完毕后,则会返回一个默认返回值。
只有实现了一个拥有以下语义(semantic)的 next() 方法,一个对象才符合迭代器协议:
属性 值 next 一个无参数函数,返回一个应当拥有以下两个属性的对象: done(boolean) next() 方法必须返回一个对象,该对象应当有两个属性: done 和 value,如果返回了一个非对象值(比如 false 或 undefined),则会抛出一个 异常(“iterator.next() returned a non-object value”)。 迭代过程
当一个对象需要被迭代的时候(比如被写入一个 for…of 循环时),首先,会不带参数调用它的 @@iterator 方法( 此时返回的是结构是这样的 { next: function () {}}),然后使用此方法返回的迭代器获得要迭代的值(其实就是不断的调用这个next()方法)
迭代总结
迭代协议可以总结为,一个东西要遍历,必须满足可迭代协议跟迭代器协议
-
可迭代协议:这个对象必须有@@iterator,可以通过Symbol.iterator 访问
-
迭代器协议:是一个对象,这个对象的next() 函数返回一个对象,这个对象包括两个属性,一个是value,一个是done(boolean,是否是最后一个元素,done 为 true 时 value 可省略)
也就是说 迭代器对象本质上,就是一个指针对象。通过指针对象的next(),用来移动指针。
自定义迭代
对象是没有实现迭代器,所以不能遍历对象,为了可以实现对象的遍历,我们需要在对象上实现上面说的迭代器,通常有两种写法,一种是传统的写法,这种需要自己去控制内部的状态,另外一种是利用生成器函数返回的Generator的迭代器来实现,代码如下:
-
传统写法
let obj = { name: 'joel', adress: 'gz', [Symbol.iterator]: () => { // 这里不要用this, 因为是return fn, this 会丢失 let index = -1, atrrList = Object.keys(obj); const objIterator = { next: () => { let result = '' index++ if (index < atrrList.length) { result = { value: atrrList[index], done: false } } else { result = { done: true } } return result } } return objIterator } } for (const item of obj) { console.log('atrrs:' + item + ',value:' + obj[item]) }
-
生成器函数写法
// 为不可迭代的对象添加迭代器 let obj = { a: 1, b: 2 } obj[Symbol.iterator] = function* () { let keys = Object.keys(obj); //取到key值的长度 let len = keys.length; //定义循环变量 let n = 0; //条件判断 while (n <= len - 1) { yield { k: keys[n], v: obj[keys[n]] }; n++ } } //返回的是个对象的key和value for (let { k, v } of obj) { console.log(k, v); }
-
-
Generators
什么是生成器?
生成器是在函数内部运行的一些代码
-
返回值后,它会自行暂停,
-
调用程序可以要求取消暂停并返回另一个值
这种“返回”不是传统的从函数 return。所以它被赋予了一个特殊的名称——yield。
在 javascript 中,如果想要使用生成器,则需要:
-
定义特殊的生成器函数
-
调用该函数创建一个生成器对象
-
在循环中使用该生成器对象,或直接调用其 next 方法
// File: sample-program.js //function 后面的 * 告诉 javascript 这是一个生成器函数。 function *createGenerator() { for(let i=0;i<20;i++) { yield i } } const generator = createGenerator() console.log(generator.next()) console.log(generator.next())
如果运行这段代码,则会得到以下输出:
$ node sample-program.js
{ value: 0, done: false }
{ value: 1, done: false } -
-
Promises
什么是 Promise
Promise 是抽象的异步处理对象,以及对其进行各种操作的组件。
Javascript 为什么要引入 Promise
有了Promise对象,就可以将异步操作以同步操作的流程表达出来。 这样在处理多个异步操作的时候还可以避免了层层嵌套的回调函数。 此外,Promise对象提供统一的接口,必须通过调用
Promise#then
和Promise#catch
这两个方法来结果,除此之外其他的方法都是不可用的,这样使得异步处理操作更加容易。基本用法
三种办法创建 Promise 实例(对象)
-
构造方法
let promies = new Promise((resolve, reject) => { resolve(); //异步处理 });
-
通过 Promise 实例的方法,Promise#then 方法返回的也是一个 Promise 对象
promise.then(onFulfilled, onRejected);
-
通过 Promise 的静态方法,Promise.resolve(),Promise.reject()
var p = Promise.resolve(); p.then(function(value) { console.log(value); });
Promise 的状态
Fulfilled: has-resolved, 表示成功解决,这时会调用 onFulfilled.
Rejected: has-rejected, 表示解决失败,此时会调用 onRejected.
Pending: unresolve, 表示待解决,既不是resolve也不是reject的状态。也就是promise对象刚被创建后的初始化状态.
-
-
-
函数和方法的区别
函数(function)是一段代码,需要通过名字来进行调用。它能将一些数据(函数的参数)传递进去进行处理,然后返回一些数据(函数的返回值),也可以不返回数据。
方法(method)是通过对象调用的javascript函数。也就是说,方法也是函数,只是比较特殊的函数。
当将函数和对象和写在一起时,函数(function)就变成了方法(method)。只能对象里方法形式,方法里在函数形式写法,不能对象里函数,正确写法:
结果:这是一个 this指向的问题,第一个:{m: ƒ} ,第二个:window
var o={ //对象 m:function(){ //方法 console.log(this); f(); //方法里可以函数 f:function f(){ console.log(this) } } } o.m(); //对象o的m方法,this作为方法被调用,指向调用它的对象。 //作为函数调用指向window,或undefined(严格模式)
-
模块开发
-
commons js 模块化开发
exports导出 (module.exports={ … 导出方法 …})
require 导入 (const m = require(‘./路径’))
-