javaScript常用知识点

208 阅读8分钟

1. this指向问题

在绝大多数情况下,函数的调用方式决定了this的值。this不能在执行期间被赋值,并且在每次函数被调用时this的值也可能会不同。

  1. this指向的对象称为函数的上下文对象context;
  2. this的指向取决于函数被调用方式
  3. this的指向不是函数声明是绑定的,而是在函数运行过程中动态绑定的。
       1.全局环境输出this,指向谁,(window)
       2.全局函数输出this,指向谁  (window)
       3.对象的方法输出this,指向谁 (this 放在方法中指向调用这个方法的对象)
       4.dom事件输出this,指向谁 (DOM 对象)
       5.构造函数中的this,指向谁 (用来创建对象)
       6.new关键字做了什么
         new 会创建对象,将构造函数中的this指向创建的this 指向fn
       7.箭头函数中的this指向谁 (没有this)
       普通函数谁调用指向谁,箭头函数在哪里定义指向谁
       箭头函数外指向谁就指向谁

2. 说说你对闭包的理解。

使用闭包主要是为了设计私有的方法和变量。闭包的优点是可以避免全局变量的污染;缺点是闭包会常驻内存,增加内存使用量,使用不当很容易造成内存泄漏。在JavaScript中,函数即闭包,只有函数才会产生作用域闭包有3个特性

  • 函数嵌套函数。

  • 在函数内部可以引用外部的参数和变量

  • 参数和变量不会以垃圾回收机制回收

3. 如何实现浏览器内多个标签页之间的通信?

  • 调用 localstorge、 cookie等数据存储通信方式

4. call()和apply()的区别和作用是什么?

作用:

1 .作用都是在函数执行的时候,动态改变函数的运行环境(执行上下文)。 2 .call和 apply的第一个参数都是改变运行环境的对象。 3 .call()和apply()都是function 原型上的方法 用来改变this指向 4 .和它功能相似的还有bind()改变this指向,但bind()并没有立即执行,只是预先处理改变 this

区别:

call从第二个参数开始,每一个参数会依次传递给调用函数;apply的第二个参数是数组,数组的每一个成员会依次传递给调用函数。 call()比apply()性能更好些

	// call可以改变this指向,主要作用可以实现继承
      let o = {
        name: "andy",
      };
      function fn(a, b) {
        console.log(this);
        console.log(a + b);
      }
      fn.call(o, 3, 5);
      
    // apply 可以调用函数,改变this指向,第二个参数必须是数组形式
      let arr = [1, 2, 3, 4, 5];
      let max = Math.max.apply(Math, arr);
      console.log(max); //5
      
    // 1.bind() 方法不会调用函数,但是能改变函数内部的this指向
    // 2.返回由指定的this值和初始化参数改造的原函数拷贝
    // 3.返回的是原函数改变this之后的新函数
    // 4.如果有的函数我们不需要立即调用,但是又想改变函数内部的this指向此时用bind

5. 请解释一下 JavaScript的同源策略。

同源策略指的是协议、域名、端口相同。同源策略是一种安全协议。指一段脚本只能读取来自同一来源的窗口和文档的属性 同源策略是为了保证用户信息的安全,防止恶意的网站窃取数据,最初的同源策略是指不同网站下的cookie设置。

同源策略是浏览器给予Ajax技术的限制,服务器端是不存在同源政策的限制的。

6. 如何判断一个对象是否属于某个类?

使用 instanceof关键字,判断一个对象是否是类的实例化对象;使用 constructor属性,判断一个对象是否是类的构造函数。

7. 什么是事件代理(事件委托)?

事件代理( Event Delegation),又称为事件委托,是 JavaScript中绑定事件的常用技巧。顾名思义,“事件代理”就是把原本需要绑定的事件委托给父元素,让父元素负責事件监听。事件代理的原理是DOM元素的事件冒泡。使用事件代理的好处是可以提高性能。

8.说明如何使用 JavaScript提交表单。

document .form [0] .submit();

9. 哪些关键字用于处理异常?

   try {
      // 执行代码
    } catch {
      // 捕获异常
    }

10. 数据类型

在这里插入图片描述

11. 暂时性死区

var 命令会发生“变量提升”现象,即变量可以在声明之前使用,值为undefined。 let命令改变了语法行为,它所声明的变量一定要在声明后使用,否则报错。

12. 请求的发送方法:

AJAX概述:

AJAX 可以使网页实现异步更新,可以在不重新加载整个网页的情况系,对网页某个部分进行更新 XMLHttpRequest 是 AJAX 的基础

请求发送:

    /*
      创建 XMLHttpRequest 对象使用 xhr.open(method,url,async) 方法发送到请求服务器,
      一般传递三个参数:
        method:发送请求的类型
        url:发送的地址
        async:true(异步)或者false(同步)
    */
    const xhr = new XMLHttpRequest();
    /*
      定义请求方法和路径
      get 方式:请求参数在URL后边拼接,send()方法为空参
      post 方式:请求参数在send()方法中定义
    */
    xhr.open("GET", "http://localhost:8000/home");
    // 请求发送
    xhr.send();
    /*指定回调函数,由回调函数处理请求后的响应问题*/
    xhr.onreadystatechange = function () {
      // 请求完成且响应正常
      if (xhr.readyState === 4 && xhr.status === 200) {
        // 成功处理
        let res = xhr.responseText
      }
    }

13. 把字符串中的字母大小写互换

    let str = 'FIRSTNAME是张,lastname是三'
    str = str.replace(/[a-zA-Z]/g, content => {
      // content是每一次正则匹配的结果
      //验证方式把字母转换为大写后看和之前是否一样,如果一样之前就是大写
      return content.toUpperCase() === content ? content.toLowerCase() : content.toUpperCase()
    })
    console.log(str)

14. 字符串中的查找

	  let str = "abcdefghijklmn";
      let test = "gh";
      ~(function () {
        // 遍历查找
        // function myIndexOf(test) {
        //   let lenT = test.length;
        //   let lenS = this.length;
        //   let res = -1;
        //   // 判断被检测的test子符串长度是否大于str子符串长度
        //   if (lenT > lenS) {
        //     return -1;
        //   }
        //   for (let i = 0; i < lenS - lenT; i++) {
        //     if (this.substr(i, lenT) === test) {
        //       res = i;
        //       break;
        //     }
        //   }
        //   return res;
        // }

        // 正则
        function myIndexOf(test) {
        // console.log(this, "str字符串");
          let reg = new RegExp(test);
          let res = reg.exec(this);
          return res === null ? -1 : res.index;
        }
        String.prototype.myIndexOf = myIndexOf;
      })();
      console.log(str.myIndexOf(test));

15. 数组扁平化

//使用 Infinity,可展开任意深度的嵌套数组
// flat会去除空项
var arr4 = [1, 2, [3, 4, [5, 6, [7, 8, [9, 10]]]]];
arr4.flat(Infinity);
// [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
var arr = [1, 2, [3, 4]];

// 展开一层数组
arr.flat();
// 等效于
arr.reduce((acc, val) => acc.concat(val), []);
// [1, 2, 3, 4]

// 使用扩展运算符 ...
const flattened = arr => [].concat(...arr);

16. 多维数组去重

    // 先把数组展开再去重
     let arr = [1, 2, [1, 2, 3], [3, 5, [5, 8, [4, 5]]]];
      arr = new Set(
        arr
          .toString()
          .split("")
          .map((item) => Number(item))
      );
      console.log(arr);

17. 数组中求最大值

 	  function getMax(arr) {
        let max = arr[0];
        for (let i = 0; i <= arr.length; i++) {
          if (arr[i] > max) {
            max = arr[i];
          }
        }
        return max;
      }
      let res = getMax([2, 5, 6, 48, 8]);
      console.log(res);
     // 方法2 利用内置对象Math和es6的展开运算符
     console.log(Math.max(...[2, 5, 6, 48, 8]));

18. 函数判断是否是闰年

      function isRunYear(year) {
        let flag = false;
        if ((year % 4 === 0 && year % 100 !== 0) || year % 400 === 0) {
          flag = true;
        }
        return flag;
      }

      console.log(isRunYear(2020));

19. 作用域链

  • 写在函数内部的是局部作用域
  • 如果函数中还有函数,那么在这个作用域中又诞生了一个作用域
  • 根据在内部函数可以访问外部函数变量的这种机制,用链式查找决定哪些数据能被内部函数访问,就称为作用域链

20. 预解析

javaScript代码是由浏览器中 javaScript 解析器来执行的,javaScript 解析器在运行 javaScript 代码的时候分为两步: 预解析和代码执行

  1. 预解析:会把所有 var 和 function 提升到当前作用域中的最前面

  2. 预解析分为两步: 变量提升:把所有的变量声明提升到当前作用域最前面, 不提升赋值操作 函数提升:把所有的函数声明提升到当前作用域最前面, 不调用函数

  3. 代码执行:按照代码的书写顺序从上往下执行

//案列1
      var num = 10;
      fun();
      function fun() {
        console.log(num); // undefined
        var num = 20;
      }
//案列2
      var num = 10;
      function fun() {
        console.log(num);// undefined
        var num = 20;
        console.log(num);//20
      }
      fun();
//案列3
      var a = 10;
      fun();
      function fun() {
        var b = 9;
        console.log(a);// undefined
        var a = "123";
        console.log(b);//9
      }
 //案例4
      fun();
      console.log(c); //9
      console.log(b); //9
      console.log(a); // 报错
      function fun() {
        var a = (b = c = 9);
        // 相当于 var a=9,b=9,c=9 b和c直接赋值没有var当全局变量看
        console.log(a); //9
        console.log(b); //9
        console.log(c); //9
      }
      

21. 暂时性死区

var 命令会发生“变量提升”现象,即变量可以在声明之前使用,值为undefined。 let命令改变了语法行为,它所声明的变量一定要在声明后使用,否则报错。

22. new关键字执行过程

  1. 在内存中创建一个新的空对象
  2. 让this指向这个新的对象
  3. 执行构造函数里面的代码,给这个新对象添加属性和方法
  4. 返回这个新对象(所以构造函数里不需要return)

23. 从一个数组中随机出一个不重复的N个项的数组

      function getList(array) {
        let len = array.length;
        let t = null;
        let i = null;
        while (len) {
          i = Math.floor(Math.random() * len--);
          t = array[len];
          array[len] = array[i];
          array[i] = t;
        }
        return array;
      }
	  let currentList=[1,2,3,4,5,6,7,8,9,10];
      let newCurrentList = JSON.parse(JSON.stringify(currentList));
      let res = getList(newCurrentList);
      console.log(res.slice(0, 5));

24.数组的插入排序

       function insertSort(arr) {
        var len = arr.length;
        for (var i = 1; i < len; i++) {
          var temp = arr[i];
          var j = i - 1; //默认已排序的元素
          while (j >= 0 && arr[j] > temp) {
            //在已排序好的队列中从后向前扫描
            arr[j + 1] = arr[j]; //已排序的元素大于新元素,将该元素移到一下个位置
            j--;
          }
          arr[j + 1] = temp;
        }
        return arr;
      }
      const arr = [4, 9, 2, 6, 7, 5];
      console.log(insertSort(arr))

25.数组的二分插入排序(效率比插入排序高)

      function binaryInsertSort(arr) {
        var len = arr.length;
        for (var i = 1; i < len; i++) {
          var key = arr[i],
            left = 0,
            right = i - 1;
          while (left <= right) {
            //在已排序的元素中二分查找第一个比它大的值
            var mid = parseInt((left + right) / 2); //二分查找的中间值
            if (key < arr[mid]) {
              //当前值比中间值小  则在左边的子数组中继续寻找
              right = mid - 1;
            } else {
              left = mid + 1; //当前值比中间值大   在右边的子数组继续寻找
            }
          }
          for (var j = i - 1; j >= left; j--) {
            arr[j + 1] = arr[j];
          }
          arr[left] = key;
        }
        return arr;
      }
      console.log(binaryInsertSort(arr));