JS知识整理(持续更新)

JS知识整理

1.多行字符串可以使用\n和反引号... 来表示,如下:

`abc
def
g`;

2.模板字符串使用${}来表示,如:

var name = '小明';
var age = 20;
var message = `你好, ${name}, 你今年${age}岁了!`;
alert(message);

3.若对象的属性名不是合法字符串,就需要使用引号括起来。访问这个属性也无法使用.操作符,必须用[‘xxx’]来访问。

4.对象的in方法可以检查是否包含某个属性,但不保证是不是继承得来;利用hasOwnProperty方法可以区分。

5.for … in对Array的循环得到的索引是String而不是Number。

6.Map是一组键值对的结构,初始化Map需要一个二维数组,或者直接初始化一个空Map。Map具有以下方法:

var m = new Map(); // 空Map
m.set('Adam', 67); // 添加新的key-value
m.set('Bob', 59);
m.has('Adam'); // 是否存在key 'Adam': true
m.get('Adam'); // 67
m.delete('Adam'); // 删除key 'Adam'
m.get('Adam'); // undefined

7.Set和Map类似,也是一组key的集合,但不存储value。由于key不能重复,所以,在Set中,没有重复的key;要创建一个Set,需要提供一个Array作为输入,或者直接创建一个空Set,Set的方法有add和delete。

8.Array、Map和Set都属于iterable类型,具有iterable类型的集合可以通过新的for … of循环来遍历;更好的方式是直接使用iterable内置的forEach方法,它接收一个函数,每次迭代就自动回调该函数:

var a = ['A', 'B', 'C'];
a.forEach(function (element, index, array) {
    // element: 指向当前元素的值
    // index: 指向当前索引
    // array: 指向Array对象本身
    alert(element);
});

9.apply,call和bind的区别:apply和call一样,作用于函数,用于改变函数上下文的this指向,其中,apply的第二个参数传入一个数组包含所有参数,而call的第二个参数开始则是把原参数一个个传入;bind和call类似,第一个参数传入目标对象,第二个参数开始是原参数一个个传入,但不同的是,bind返回的是一个函数。

10.js是单线程的,这意味着在很多情况下,js只能等一个函数执行完后再执行下一个函数,这样,在我们使用回调函数时,我们触发了异步任务,这时的主线程会把异步任务交给别的工作线程完成,自己继续执行函数栈里的函数,等到所有函数执行完毕后,如果收到异步任务完成的结果,再执行回调函数。

11.数组的map方法和reduce方法:map方法使得数组中的所有元素都执行传入的函数arr.map(String),这行代码意思是把数组元素转化成字符串;Array的reduce()把一个函数作用在这个Array的[x1, x2, x3…]上,这个函数必须接收两个参数,reduce()把结果继续和序列的下一个元素做累积计算,如:

[x1, x2, x3, x4].reduce(f) = f(f(f(x1, x2), x3), x4)

12.在使用箭头函数时要注意:

a.不可以当作构造函数,也就是说,不可以使用new命令,否则会抛出一个错误。
b.函数体内的this对象,就是定义时所在的对象,而不是使用时所在的对象。
c.不可以使用arguments对象,该对象在函数体内不存在。如果要用,可以用 rest 参数代替。
d.不可以使用yield命令,因此箭头函数不能用作 Generator 函数。

个人理解,使用箭头函数时,函数本身并没有this,而是继承自父的上下文。

13.this代表函数运行时生成的一个内部对象,根据函数使用的场合不同,this的值也不同,但总的来说,指向调用函数的那个对象;

14.let和const不存在变量提升,并且规定了暂时性死区,在块级作用域内不能重复定义同一个变量,有了let引入的块级作用域后,原来广泛应用的立即执行函数表达式(IIFE)不再必要了:

// IIFE 写法
(function () {
  var tmp = ...;
  ...
}());

// 块级作用域写法
{
  let tmp = ...;
  ...
}

值得注意的是,使用let、classs、const声明的变量不再是全局对象window的属性。

15.const常量实际上保证的,并不是变量的值不得改动,而是变量指向的那个内存地址不得改动,这意味着当你声明一个常量数组或对象时,可以读写,但不能把它重新指向新的对象或数组;要彻底冻结一个对象使用Object.freeze()方法:

//将一个对象彻底冻结
var constantize = (obj) =>{
    Object.freeze(obj);
    Object.keys(obj).forEach((key,i)=>{
        if(typeof obj[key]==='object'){
            Object.freeze(obj[key]);
        }
    })
}

16.js实现ASCII码和字符的转化使用String.fromCharCode()String.fromCodePointcharCodeAtcodePointAt方法,其中后者是ES6新方法,可识别4字节字符;codePointAt方法的参数,是字符在字符串中的位置(从0开始),开始能够正确识别4字符单位,后面和charCodeAt方法返回结果一样:

example

**要注意的是,codePointAt方法并没有修正字符串下标的问题,如上图所示,要取到a,只能根据所以2,这个问题可以使用for of方法。
**

17.字符串的标签模板,模板字符串可以跟在函数名后面,该函数会被调用来处理这个模板字符串,如果模板字符串中含有变量,则会把模板字符串按照下面方式传入:

let a = 5;
let b = 10;

tag`Hello ${ a + b } world ${ a * b }`;
// 等同于
tag(['Hello ', ' world ', ''], 15, 50);

第一个参数为出去变量后的字符串分割后的数组,后面跟的参数是变量。

18.正则表达式中

  1. \d用来表示匹配数字;.用来匹配除了换行符的任意字符;\w用来匹配字母、数字、下划线;\s用来匹配空格;上面的3个的写\D、\W、\S表示匹配相反;^用来匹配以……开头;$用来匹配以……结尾;
  2. 后面接匹配的数量,*表示任意个;+表示大于等于1个;?表示0或者1个;{n}表示n个字符,{n,m}表示n-m个字符。
  3. 使用[]表示精确匹配,使用?表示非贪婪匹配。
  4. 使用test方法测试是否匹配,使用exec方法返回匹配的值,若使用()分组,则返回一个数组,第一个值为全匹配值,后面跟分组匹配值。

19.在ES5中,定义正则表达式时有两种方法,第一种是直接使用/(字符串)/的方法定义,第二种是使用new Reg构造一个正则对象,这种方法使用时需要传入两个参数,第一个是正则字符串,第二个是修饰符,表示如何匹配,常见的有i、g、u、y、m

  1. i修饰符:表示忽略大小写匹配
  2. g修饰符:表示全局匹配
  3. y修饰符:也表示全局匹配,但是它只能进行粘连匹配,即每次匹配的对象必须从剩余的第一个位置开始
  4. u修饰符:代表unicode模式,用来处理字符值大于0xFFFF的字符,也就是4字节字符的一些匹配情况。

正则对象新增了sticky属性表示使用使用了y修饰符;新增flag属性返回使用的修饰符。

20.ES6 提供了二进制和八进制数值的新的写法,分别用前缀0b(或0B)和0o(或0O)表示;Number.isFinite()对于非数值一律返回false, Number.isNaN()只有对于NaN才返回true,非NaN一律返回false;

ES6 在Number对象上面,新增一个极小的常量Number.EPSILON。根据规格,它表示1与大于1的最小浮点数之间的差。对于64位浮点数来说,大于1的最小浮点数相当于二进制的1.00..001,小数点后面有连续51个零。这个值减去1之后,就等于2的-52次方。这个常量被用来处理可接受的误差范围。

Javascript中整数的范围是2的-53次方到2的53次方之间,所以上下限在ES6中使用两个新定义的常量最大安全整数和最小安全整数来表示;

  1. Math.trunc方法用于去除一个数的小数部分,返回整数部分;
  2. Math.cbrt方法用于计算一个数的立方根。
  3. JavaScript的整数使用32位二进制形式表示,Math.clz32方法返回一个数的32位无符号整数形式有多少个前导0
  4. ES2016 新增了一个指数运算符(**)

21.函数的length属性,将返回没有指定默认值的参数个数。也就是说,指定了默认值后,length属性将失真;如果设置了默认值的参数不是尾参数,那么length属性也不再计入后面的参数了,rest同理也不记入;
如果将一个匿名函数赋值给一个变量,ES5 的name属性,会返回空字符串,而 ES6 的name属性会返回实际的函数名。
ES6 中只要使用尾递归,就不会发生栈溢出,相对节省内存;尾递归的实现,往往需要改写递归函数,确保最后一步只调用自身。做到这一点的方法,就是把所有用到的内部变量改写成函数的参数。ES6 的尾调用优化只在严格模式下开启,正常模式是无效的。

22.函数柯里化:将函数的多个参数形式转化成单参数形式:

function currying(fn, n) {
  return function (m) {
    return fn.call(this, m, n);
  };
}

蹦床函数(trampoline)可以将递归执行转为循环执行:

function trampoline(f) {
  while (f && f instanceof Function) {
    f = f();
  }
  return f;
}

23.ES2017新增…运算符,可以把一个数组转化成函数的参数传入函数中

let arr=[1,2,3];
f(...arr);

24.Array.from方法用于将两类对象转为真正的数组:类似数组的对象(array-like object)和可遍历(iterable)的对象(包括ES6新增的数据结构Set和Map),该方法有三个参数,第一个参数是用于转化的类数组对象,第二个参数类似map方法,对转化的对象中的每个元素执行该函数,返回执行后的数组,第三个参数是指定用于绑定的map方法的this对象;Array.of方法用于将一组值,转换为数组。

fill方法用于空数组的初始化非常方便。数组中已有的元素,会被全部抹去:

let arr= new Array(10);
arr.fill(0);
//[0,0,0,0,0,0,0,0,0,0]

ES6 提供三个新的方法——entries(),keys()和values()——用于遍历数组。它们都返回一个遍历器对象,可以用for…of循环进行遍历,唯一的区别是keys()是对键名的遍历、values()是对键值的遍历,entries()是对键值对的遍历。

25.Object.is就是部署这个算法的新方法。它用来比较两个值是否严格相等,与严格比较运算符(===)的行为基本一致,不同之处只有两个:一是+0不等于-0,二是NaN等于自身。
对象的每个属性都有一个描述对象(Descriptor),用来控制该属性的行为。Object.getOwnPropertyDescriptor方法可以获取该属性的描述对象。

this关键字总是指向函数所在的当前对象,ES6 又新增了另一个类似的关键字super,指向当前对象的原型对象,super关键字表示原型对象时,只能用在对象的方法之中,用在其他地方都会报错。

26.ES6引入了一个新的原始数据类型,symbol,代表独一无二的值,symbol值由symbol函数生成,函数可以接受参数,用于描述symbol实例,symbol值不能和其他值一起运算,但是可以转化成字符串和boolean值,但不能转化成数值;(待续)

27.Proxy用于修改某些操作的默认行为,等同于在语言层面进行修改,属于元编程,即对编程语言编程;Proxy 可以理解成,在目标对象之前架设一层“拦截”,外界对该对象的访问,都必须先通过这层拦截,因此提供了一种机制,可以对外界的访问进行过滤和改写。

var obj = new Proxy({}, {
  get: function (target, key, receiver) {
    console.log(`getting ${key}!`);
    return Reflect.get(target, key, receiver);
  },
  set: function (target, key, value, receiver) {
    console.log(`setting ${key}!`);
    return Reflect.set(target, key, value, receiver);
  }
});

obj.count = 1
//  setting count!
++obj.count
//  getting count!
//  setting count!
//  2

28.当我们在使用ajax传输JSON数据时,常常需要在JSON对象和JSObject对象之间转化,用到的函数有:

let JsObj = JSON.parse(JsonData);
let JsonObj = JSON.stringify(JsObj);

29.事件委托,大概解释为利用事件冒泡的原理,在父元素上绑定监听事件,监听所有子元素的行为,冒泡到父元素,然后父元素根据event.target获取到事件触发子元素,事件委托可以有效提升性能,因为它避免了在子元素数量巨大时重复绑定相同的事件。

  //获取的父元素
  var oUl = document.getElementById("ul1");
  //设置事件委托,ev为event,即触发事件的Event对象
  oUl.onclick = function(ev){
    var ev = ev || window.event;
    var target = ev.target || ev.srcElement;
    if(target.nodeName.toLowerCase() == 'li'){
            alert(123);
         alert(target.innerHTML);
    }
  }

30.GET和POST的区别

  1. 语义上来说,get是用来获取服务器数据的,人们看到请求是get。默认这个操作不会修改服务器数据,get一般是使用url传递参数,所以无法传输大量数据,而且数据是写在url上的,明文显示,而且能够保存在浏览器缓存中。
  2. post是用来修改提交数据的,人们看到是post就知道服务器的数据被修改了,post的数据是放在请求的消息主体中的,所以post能够传输很大的数据量,相对于get来说在某种程度上是无限制的,post请求因为是把数据放在消息主体中,所以无法缓存在浏览器中。
  3. 这样看来,get和post的区别似乎是上面的这些,但其实,上面的这些区别都是表象的,根据http协议和浏览器的限制而体现出的一些不同,比如说post比get更安全,这个说法是因为get把数据放在url中明文显示,而post把数据放在消息主体中,可放在消息主体中同样可以被抓包获取,因为post信息也是明文显示的;其实最大的区别是get请求是幂等的,对于同一个get请求,请求多次返回的结果都是一样的,这可能会导致在网络不好的环境中重复操作导致副作用;而post请求不是幂等的,这也会引发跨站请求漏洞,需要token来避免。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值