zoukankan      html  css  js  c++  java
  • JavaScript 中 几 个需要掌握基础的问题

    1.如何从数组中移除一个特定的项

    思路:首先,使用indexOf查找要删除的数组元素的索引(index),然后使用splice方法删除该索引所对应的项。

    splice()是一个非纯函数,通过删除现有元素和/或添加新元素来更改数组的内容。

    const array = [2, 5, 9]
    
    const index = array.indexOf(5)
    if (index > -1) {
      array.splice(index, 1)
    }
    
    console.log(array)
    // [ 2, 9 ]

    splice的第二个参数是要删除的元素数量。注意,splice会在适当的位置修改数组,并返回一个包含已删除元素的新数组。

    接着,我们可以来完善一下。下面有两个函数,第一个函数仅删除一个匹配项(即从[2,5,9,1,5,8,5]中删除第一个匹配项5),而第二个函数则删除所有匹配项:

    // 仅删除第一个匹配项
    function removeItemOnce (arr, value) {
      let index = arr.indexOf(value)
      if (index > -1) {
        arr.splice(index, 1)
      }
      return arr
    }
    
    // 删除所有匹配项
    function removeItemAll (arr, value) {
      let i = 0
      while(i < arr.length) {
        if (arr[i] === value) {
          arr.splice(i, 1)
        } else {
          ++i
        }
      }
    }

    删除数组中索引i处的元素:

    array.splice(i, 1)

    如果你想从数组中删除值为number的每个元素,可以这样做:

    for (let i = array.length - 1; i>=0; i--) {
      if (array[i] === number) {
        array.splice(i, 1)
      }
    }

    如果你只想使索引i处的元素不再存在,但又不想更改其他元素的索引:

    delete array[i]

    2. 如何使用 jQuery 或纯 JS 将用户从一个页面重定向到另一个页面

    jQuery 不是必需的,window.location.replace(…)最适合模拟 HTTP 重定向。window.location.replace(...)优于使用window.location.href,因为replace()不会将原始页面保留在会话历史记录中,这意味着用户将不会陷入永无休止回退按钮。

    如果要模拟单击链接,可以使用location.href,如果要模拟HTTP重定向,请使用location.replace

    //模拟HTTP重定向
    window.location.replace("http://stackoverflow.com")
    
    // 模拟单击链接
    window.location.href = "http://stackoverflow.com"

    你还可以这样做:

    $(location).attr('href', 'http://stackoverflow.com')

    3.JavaScript 闭包是如何工作的

    闭包是一个函数和对该函数外部作用域的引用(词法环境),词法环境是每个执行上下文(堆栈)的一部分,并且是标识符(即局部变量名称)和值之间的映射。

    JavaScript 中的每个函数都维护对其外部词法环境的引用。此引用用于配置调用函数时创建的执行上下文。不管何时调用函数,该引用使函数内的代码能够查看在函数外声明的变量。

    在下面的代码中,inner与调用foo时创建的执行上下文的词法环境一起形成一个闭包,并对外部隐藏了变量secret

    function foo() {
      const secret = Math.trunc(Math.random()*100)
      return function inner() {
        console.log(`The secret number is ${secret}.`)
      }
    }
    const f = foo() // secret 不能从foo 外部直接访问
    f() // 访问 secret 的唯一办法就是调用 f

    换句话说,在JavaScript中,函数带有对私有状态的引用,只有它们(以及在相同的词法环境中声明的任何其他函数)可以访问该私有状态。这个状态对函数的调用者是不可见的,这为数据隐藏和封装提供了一种优秀的机制。

    请记住,JavaScript中的函数可以像变量一样传递,这意味着这些功能和状态的对可以在程序中传递:类似于在c++中传递类的实例。

    如果JavaScript没有闭包,则必须在函数之间显式传递更多状态,从而使参数列表更长,代码更冗余。

    所以,如果你想让一个函数总是能够访问私有状态,你可以使用一个闭包,我们经常想把状态和函数联系起来。例如,在Java或c++中,当你向类添加私有实例变量和方法时,这是将状态与功能关联起来。

    在 C 语言和大多数其他编程语言中,函数返回后,由于堆栈被销毁,所有的局部变量都不再可访问。在JavaScript中,如果在另一个函数中声明一个函数,那么外部函数的本地变量在返回后仍然可以访问。这样,在上面的代码中,secret在从foo返回后仍然对函数对象内部可用。

    闭包在需要与函数关联的私有状态时非常有用。这是一个非常常见的场景,JavaScript直到2015年才有类语法,它仍然没有私有字段语法,闭包满足了这一需求。

    私有实例变量

    在下面的事例中,函数 toString 隐藏了 Car 类的一些细节。

    function Car(manufacturer, model, year, color) {
      return {
        toString() {
          return `${manufacturer} ${model} (${year}, ${color})`
        }
      }
    }
    const car = new Car('Aston Martin','V8 Vantage','2012','Quantum Silver')
    console.log(car.toString())

    函数式编程

    在下面的代码中,函数inner隐藏了fnargs

    function curry(fn) {
      const args = []
      return function inner(arg) {
        if(args.length === fn.length) return fn(...args)
        args.push(arg)
        return inner
      }
    }
    
    function add(a, b) {
      return a + b
    }
    
    const curriedAdd = curry(add)
    console.log(curriedAdd(2)(3)()) // 5

    4. use strict 在 JavaScript 中做了什么,背后的原因是什么

    引用一些有趣的部分:

    严格模式是ECMAScript 5中的一个新特性,它允许我们将程序或函数放置在严格的操作上下文中。这种严格的上下文会防止某些操作被执行,并引发更多异常。

    严格模式在很多方面都有帮助:

    • 它捕获了一些常见的编码漏洞,并抛出异常。
    • 当采取相对不安全的操作(例如访问全局对象)时,它可以防止错误或抛出错误。
    • 它禁用令人困惑或考虑不周到的特性。

    另外,请注意,我信可以将“strict mode”应用于整个文件,也可以仅将其用于特定函数。

    // Non-strict code...
    
    (function(){
      "use strict";
    
      // Define your library strictly...
    })();
    
    // Non-strict code... 

    如果是在混合使用旧代码和新代码的情况,这可能会有所帮助。它有点像在Perl中使用的“use strict”。通过检测更多可能导致损坏的东西,帮助我们减少更多的错误。

    现在所有主流浏览器都支持严格模式。

    在原生ECMAScript模块(带有importexport语句)和ES6类中,严格模式始终是启用的,不能禁用。

    5.如何检查字符串是否包含子字符串?

    ECMAScript 6 引入了string .prototype.include

    const string = "foo";
    const substring = "oo";
    
    console.log(string.includes(substring));

    不过,IE 不支持 includes。在 CMAScript 5或更早的环境中,使用String.prototype.indexOf。如果找不到子字符串,则返回-1:

    var string = "foo";
    var substring = "oo";
    
    console.log(string.indexOf(substring) !== -1);

    为了使其在旧的浏览器中运行,可以使用这种polyfill

    if (!String.prototype.includes) {
      String.prototype.includes = function(search, start) {
        'use strict';
        if (typeof start !== 'number') {
          start = 0;
        }
    
        if (start + search.length > this.length) {
          return false;
        } else {
          return this.indexOf(search, start) !== -1;
        }
      };
    }

    6. JS 的比较中应使用哪个等于运算符(== vs ===)?

    严格相等运算符(===)的行为与抽象相等运算符(==)相同,除非不进行类型转换,而且类型必须相同才能被认为是相等的。

    ==运算符会进行类型转换后比较相等性。 ===运算符不会进行转换,因此如果两个值的类型不同,则===只会返回false。

    JavaScript有两组相等运算符:===!==,以及它们的孪生兄弟==!=。如果这两个操作数具有相同的类型和相同的值,那么===的结果就是 true,而!==的结果就是 false

    下面是一些事例:

    '' == '0'           // false
    0 == ''             // true
    0 == '0'            // true
    
    false == 'false'    // false
    false == '0'        // true
    
    false == undefined  // false
    false == null       // false
    null == undefined   // true
    
    ' 	
     ' == 0     // true

    上面有些看起来会挺困惑的,所以尽量还是使用严格比较运算符(===)。对于引用类型,=====操作一致(特殊情况除外)。

    var a = [1,2,3];
    var b = [1,2,3];
    
    var c = { x: 1, y: 2 };
    var d = { x: 1, y: 2 };
    
    var e = "text";
    var f = "te" + "xt";
    
    a == b            // false
    a === b           // false
    
    c == d            // false
    c === d           // false
    
    e == f            // true
    e === f           // true

    特殊情况是,当你将一个字符串字面量与一个字符串对象进行比较时,由于该对象的toStringvalueOf方法,该对象的值与相字面量的值一样。

    考虑将字符串字面量与由String构造函数创建的字符串对象进行比较:

    "abc" == new String("abc")    // true
    "abc" === new String("abc")   // false

    在这里,==操作符检查两个对象的值并返回true,但是===看到它们不是同一类型并返回false。哪一个是正确的?这取决于你想要比较的是什么。

    我们的建议是完全绕开该问题,只是不要使用String构造函数来创建字符串对象。

    使用==运算符(等于)

    true == 1; //true, 因为 true 被转换为1,然后进行比较
    "2" == 2;  //true, 因为 “2” 被转换成 2,然后进行比较

    使用===操作符

    true === 1; //false
    "2" === 2;  //false

    7.如何在另一个JavaScript文件中包含一个JavaScript文件?

    旧版本的JavaScript没有importincluderequire,因此针对这个问题开发了许多不同的方法。

    但是从2015年(ES6)开始,JavaScript已经有了ES6模块标准,可以在Node中导入模块。为了与旧版浏览器兼容,可以使用Webpack和Rollup之类的构建工具和/或Babel这样的编译工具。

    ES6 Module

    从v8.5开始,Node.js就支持ECMAScript (ES6)模块,带有--experimental-modules标志,而且至少Node.js v13.8.0没有这个标志。要启用ESM(相对于Node.js之前的commonjs风格的模块系统[CJS]),你可以在 package.json中使用“type”:“module”。或者为文件提供扩展名.mjs。(类似地,如果默认为ESM,则用 Node.js 以前的CJS模块编写的模块可以命名为.cjs。)

    使用package.json

    {
        "type": "module"
    }

    在 module.js: 中

    export function hello() {
      return "Hello";
    }

    main.js:

    import { hello } from './module.js';
    let val = hello();  // val is "Hello";

    使用.mjs,会有对应的module.mjs

    export function hello() {
      return "Hello";
    }

    main.mjs 中

    import { hello } from './module.mjs';
    let val = hello();  // val is "Hello";

    自Safari 10.1,Chrome 61,Firefox 60 和 Edge 16 开始,浏览器就已经支持直接加载ECMAScript模块(不需要像Webpack这样的工具)。无需使用Node.js的.mjs扩展名; 浏览器完全忽略模块/脚本上的文件扩展名。

    <script type="module">
      import { hello } from './hello.mjs'; // Or it could be simply `hello.js`
      hello('world');
    </script>
    
    // hello.mjs -- or it could be simply `hello.js`
    export function hello(text) {
      const div = document.createElement('div');
      div.textContent = `Hello ${text}`;
      document.body.appendChild(div);
  • 相关阅读:
    Ajax基础:3.Json
    Head First Design Patterns State Pattern
    Head First Design Patterns Template Method Pattern
    Articles For CSS Related
    Head First Design Patterns Decorator Pattern
    代码审查工具
    How To Be More Active In A Group
    Head First Design Patterns Factory Method Pattern
    Head First Design Patterns Composite Pattern
    Tech Articles
  • 原文地址:https://www.cnblogs.com/ZXH-null/p/13819492.html
Copyright © 2011-2022 走看看