js知识点总结

125 阅读9分钟

js数组的map和forearch的区别

foreach()方法会针对每一个元素执行提供的回调函数,该方法没有返回值 map()方法不会改变原数组的值,会新生成一个数组并返回,新数组中的值为原数组调用回调函数处理之后的值,并且元素为空的话会直接返回,不会调用后续的回调函数,不会对空数组进行检测。

localStorage sessionStorage cookies 有什么区别?

共同点:

cookie,sessionStorage, localStorage 这三者都可以被用来在浏览器端存储数据,而且都是字符串类型的键值对。

区别:

1.在于sessionStorage, localStorage属于WebStorage,创建它们的目的便于客户端存储数据。 而Cookie早在网景公司的浏览器中就开始支持,最初目的是为了保持HTTP的状态。 cookie是网站为了标识用户身份而存储在用户本地终端上的数据(通常经过加密)。cookie始终在同源的http请求中携带(即使不需要)都会在浏览器和服务器端间来回传递。session storage和local storage不会自动把数据发给服务器,仅在本地保存;

2.存储大小:cookie数据大小不会超过4K,session storage和local storage虽然也有存储大小的限制,但比cookie大得多,可以达到5M或者更多;

3.有期时间:local storage存储持久数据,浏览器关闭后数据不丢失,除非自动删除数据。session storage数据在当前浏览器窗口关闭后自动删除。cookie 设置的cookie过期时间之前一直有效,即使窗口或者浏览器关闭;

补充:应用场景

考虑到每个 HTTP 请求都会带着 Cookie 的信息,所以 Cookie 当然是能精简就精简啦,比较常用的一个应用场景就是判断用户是否登录。针对登录过的用户,服务器端会在他登录时往 Cookie 中插入一段加密过的唯一辨识单一用户的辨识码,下次只要读取这个值就可以判断当前用户是否登录啦。曾经还使用 Cookie 来保存用户在电商网站的购物车信息,如今有了 localStorage,似乎在这个方面也可以给 Cookie 放个假了~ 而另一方面 localStorage 接替了 Cookie 管理购物车的工作,同时也能胜任其他一些工作。比如HTML5游戏通常会产生一些本地数据,localStorage 也是非常适用的。如果遇到一些内容特别多的表单,为了优化用户体验,我们可能要把表单页面拆分成多个子页面,然后按步骤引导用户填写。这时候 sessionStorage 的作用就发挥出来了。 需要注意的是,不是什么数据都适合放在 Cookie、localStorage 和 sessionStorage 中的。使用它们的时候,需要时刻注意是否有代码存在 XSS 注入的风险。因为只要打开控制台,你就随意修改它们的值,也就是说如果你的网站中有 XSS 的风险,它们就能对你的 localStorage 肆意妄为。所以千万不要用它们存储你系统中的敏感数据。

function foo(){ }();为什么不是 IIFEIIFE (Immediately Invoked Function Expressions)代表立即执行函数

因为以function关键字开头的语句会被解析为函数声明(function declaration),而函数声明是不允许直接运行的。
只有当解析器把这句话解析为函数表达式(function expression),才能够直接运行,那如何将function foo () {}()改为函数表达式呢, 方法就是用括号括起来,即(function foo (){}();) 请牢记!任何不是以function开头的函数都属于函数表达式:所以下面这个也是函数表达式

var add = function(){
       console.log(111)
   }()

JavaScript中的:==、===

==:相等运算符:用来比较两个值是否相等,如果相等会返回 true,否则返回 false。

使用 == 来做相等运算,如果比较的两个值的类型不同,则会自动进行类型转换,将其转换为相同类型然后再比较。

console.log(undefined == null); // true
console.log('2' ==2); // true

===:全等运算符:用来判断两个值是否全等,它不做自动的类型转换,如果两个值的类型不同,直接返回false。
console.log("123" === 123);//false
console.log(undefined === null);//false

null、undefined和未声明变量之间有什么区别

未声明变量:当你没有提前使用 var、letconst 声明变量,就为一个变量赋值时,该变量是未声明变量(undeclared variables)。未声明变量会脱离当前作用域,成为全局作用域下定义的变量。在严格模式下,给未声明的变量赋值,会抛出 ReferenceError 错误。和使用全局变量一样,使用未声明变量也是非常不好的做法,应当尽可能避免。要检查判断它们,需要将用到它们的代码放在 try/catch 语句中。

function foo() { x = 1; // 在严格模式下,抛出 ReferenceError 错误 } foo(); console.log(x); // 1

当一个变量已经声明,但没有赋值时,该变量的值是 undefined。如果一个函数的执行结果被赋值给一个变量,但是这个函数却没有返回任何值,那么该变量的值是 undefined。要检查它,需要使用严格相等(===);或者使用 typeof,它会返回 'undefined' 字符串。请注意,不能使用非严格相等(==)来检查,因为如果变量值为 null,使用非严格相等也会返回 true

var foo; console.log(foo); // undefined 
console.log(foo === undefined); // true 
console.log(typeof foo === 'undefined'); // true 
console.log(foo == null); // true. 错误,不要使用非严格相等! 
function bar() {} var baz = bar(); console.log(baz); // undefined

null 只能被显式赋值给变量。它表示空值,与被显式赋值 undefined 的意义不同。要检查判断 null 值,需要使用严格相等运算符。请注意,和前面一样,不能使用非严格相等(==)来检查,因为如果变量值为 undefined,使用非严格相等也会返回 true

var foo = null; 
console.log(foo === null); // true 
console.log(foo == undefined); // true. 错误,不要使用非严格相等!

什么是闭包(closure),为什么使用闭包?

闭包(closure)是一个函数以及其捆绑的周边环境状态(lexical environment,词法环境)的引用的组合。 换而言之,闭包让开发者可以从内部函数访问外部函数的作用域。 在JavaScript 中,闭包会随着函数的创建而被同时创建。
为什么使用闭包?

  • 利用闭包实现数据私有化或模拟私有方法。这个方式也称为模块模式(module pattern)。
  • 部分参数函数(partial applications)柯里化(currying).

闭包导致内存溢出的例子:外部函数返回一个内部函数,内部函数引用了外部函数的变量,当外部函数执行完毕后,它的活动变量不会被销毁,是因为内部函数的作用域链中仍然有对这些变量的引用

// 标准的闭包函数
function A(){
      var i=0;
      return function b(){
              return (++i);
      };
};
//外部函数A执行完毕了,但是i并不会被销毁,是因为返回的匿名函数中包含i,并且匿名函数并没有被调用而是被变量v引用的,由于v为全局变量会一直存在,那么匿名函数和其中的变量i也就会一直存在。
var v=A();
v();    //1
v();    //2


//箭头函数体的闭包( i=0 是默认参数)
var Add = (i=0) => {return (() => (++i) )};
var v = Add();
v();           //1
v();           //2

//因为仅有一个返回,return 及括号()也可以省略
var Add = (i=0)=> ()=> (++i);

请说明.forEach循环和.map()循环的主要区别,它们分别在什么情况下使用?

为了理解两者的区别,我们看看它们分别是做什么的。

forEach

  • 遍历数组中的元素。
  • 为每个元素执行回调。
  • 无返回值。
const doubled = a.forEach((num, index) => {
  // 执行与 num、index 相关的代码
});

// doubled = undefined

map

  • 遍历数组中的元素
  • 通过对每个元素调用函数,将每个元素“映射(map)”到一个新元素,从而创建一个新数组。
const doubled = a.map((num) => {
  return num * 2;
});

// doubled = [2, 4, 6]

.forEach 和 .map() 的主要区别在于 .map() 返回一个新的数组。如果你想得到一个结果,但不想改变原始数组,用 .map()。如果你只需要在数组上做迭代修改,用 forEach

匿名函数的典型应用场景是什么?

匿名函数可以在 IIFE 中使用,来封装局部作用域内的代码,以便其声明的变量不会暴露到全局作用域。

(function () {
  // 一些代码。
})();

匿名函数可以作为只用一次,不需要在其他地方使用的回调函数。当处理函数在调用它们的程序内部被定义时,代码具有更好地自闭性和可读性,可以省去寻找该处理函数的函数体位置的麻烦。

setTimeout(function () {
  console.log('Hello world!');
}, 1000);

匿名函数可以用于函数式编程或 Lodash(类似于回调函数)。

const arr = [1, 2, 3];
const double = arr.map(function (el) {
  return el * 2;
});
console.log(double); // [2, 4, 6]

.call和.apply有什么区别?

.call.apply 都用于调用函数,第一个参数将用作函数内 this 的值。然而,.call 接受逗号分隔的参数作为后面的参数,而 .apply 接受一个参数数组作为后面的参数。一个简单的记忆方法是,从 call 中的 C 联想到逗号分隔(comma-separated),从 apply 中的 A 联想到数组(array)。

function add(a, b) {
  return a + b;
}

console.log(add.call(null, 1, 2)); // 3
console.log(add.apply(null, [1, 2])); // 3

请说明Function.prototype.bind的用法。

Function 实例的 bind()  方法创建一个新函数,当调用该新函数时,它会调用原始函数并将其 this 关键字设置为给定的值,同时,还可以传入一系列指定的参数,这些参数会插入到调用新函数时传入的参数的前面。

const module = {
  x: 42,
  getX: function () {
    return this.x;
  },
};

const unboundGetX = module.getX;
console.log(unboundGetX()); // The function gets invoked at the global scope
// Expected output: undefined

const boundGetX = unboundGetX.bind(module);
console.log(boundGetX());
// Expected output: 42

请尽可能详细地解释 Ajax。

Ajax(asynchronous JavaScript and XML)是使用客户端上的许多 Web 技术,创建异步 Web 应用的一种 Web 开发技术。借助 Ajax,Web 应用可以异步(在后台)向服务器发送数据和从服务器检索数据,而不会干扰现有页面的显示和行为。通过将数据交换层与表示层分离,Ajax 允许网页和扩展 Web 应用程序动态更改内容,而无需重新加载整个页面。实际上,现在通常将 XML 替换为 JSON,因为 JavaScript 对 JSON 有原生支持优势。