• JavaScript原生


    文章目录







    0. DOM事件和监听 DOM方法汇总

    JavaScript DOM事件和监听相关

    JavaScript DOM的方法汇总(重要)


    1. JS与html的结合方式-外部JS和内部JS

    js的入口函数:

    window.onload= function() { } 
    
    // 获取body元素
    var bodyEle = document.body;
    
    // 获取html元素
    var htmlEle = document.documentElement;
    
    JavaScript与HTML可以通过以下几种方式结合:
    
    1. 内联方式(Inline):
    将JavaScript代码直接写入HTML标签中的"onclick""onload"等事件属性中。
    
    2. 内部嵌入式(Internal Embedded):
    在HTML文件中使用<script>标签将JavaScript代码包含在页面内,通常放在<head><body>元素内。
    
    在 `` 或者 `` 的JavaScript:
    您可以在 HTML 文档中放入不限数量的脚本。
    脚本可位于 HTML``` `部分中,或者同时存在于两个部分中。
    通常的做法是把函数放入 ` `部分中,或者放在页面底部。这样就可以把它们安置到同一处位置,不会干扰页面的内容。
    
    3. 外部链接式(External Linked):
    将JavaScript代码单独保存为.js文件,在HTML文件中使用<script src="filename.js"></script>引入外部脚本。
    
    4. 事件处理程序(Event Handlers):
    通过监听用户操作或者浏览器事件来触发特定的函数执行相应的逻辑。
    
    5. DOM操作(Document Object Model):
    利用JavaScript对文档对象模型进行增删改查,实现动态修改页面内容和样式。
    
    6. AJAX交互(Asynchronous JavaScript and XML):
    利用JavaScript异步发送HTTP请求获取数据并更新网页内容,实现无需刷新页面的动态交互效果。
    
    • 注意:
    1. < script>可以定义在html 页面的任何地方。但是定义的位置会影响执行顺序。
    2. < script>可以定义多个。

    例子:

    test.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    
        <!--    内部JS-->
        <script>
            alert("HelloWorld");
        </script>
    
        <!--    外部JS-->
        <script src="JS/a.js"></script>
    
    </head>
    <body>
    </body>
    </html>
    

    a.js

    alert("我是外部的JS文件");
    

    2. JS注释

    单行注释: //注释内容
    多行注释: / * 注释内容 * /
    '
    运行

    3. JS数据类型,它们的区别:

    一共8种

    • 原始数据类型(基本数据类型) :
    1. number :数字。 整数 / 小数 / NaN (not a number一 个不是数字的数字类型)。
    2. string:字符串。 字符串 “abc”、 "a”、 ’ abc’。
    3. boolean: true和false。
    4. null :一 个对象为空的占位符。
    5. undefined :未定义。如果一个变量没有给初始化值,则会被默认赋值为undefined。
    6. Symbol(ES新增)
    7. BigInt(ES10新增)
    • 引用数据类型:object

    3.1 基本数据类型、引用类型区别

    基本数据类型:

    • 基本数据类型存储在栈空间,
    • 基本数据类型直接访问,
    • 基本数据类型 复制原始的副本值给新变量

    引用数据类型

    • 引用数据类型存在堆空间,
    • 引用数据类型访问引用地址,
    • 根据引用地址寻找堆中实体
    • 复制引用地址给新的变量
        <script>
            var a = [0, 1, 2, 3, 4, 5, 6]
            var b = a //传地址
            var c = a[0]  //传值
            console.log('b=' + b);
            console.log('c=' + c);
    
            // 改变数值
            b[4] = 6
            c = 7
    
            console.log('------------------');
            console.log('a=' + a);
            console.log('b=' + b);
            console.log('c=' + c); //c改变不影响引用类型
        </script>
    
    

    3.2 null与undefined的区别

    基本数据类型中null和undefined的区别以及应用://都是代表没有值

    在这里插入图片描述

    null表示“没有对象”,该处不应该有值
    undefined表示“缺少值”,该处应该有值,但是还没有定义
    转为数值也不同,null转为数值为0,undefined转为数值NaN(不是一个数字)

    console.log(Number(null));//0
    console.log(Number(undefined));//nan
    '
    运行

    什么时候会有null:
    1、作为函数的参数,表示该函数的参数不是对象
    2、作为对象原型链的终点为NULL

    console.log(Object.getPrototypeOf(Object.prototype));//null
    '
    运行

    Object.getPrototypeOf(object)方法返回指定对象的原型(内部[[Prototype]]属性的值)。
    给定对象的原型。如果没有继承属性,则返回 null 。

    什么时候会出现undefined:
    1、变量被声明了。但是没有赋值,就等于undefined

    var a
    log a //undefined
    

    2、调用函数时,应该提供的参数没有提供,该参数就等于undefined

            function fun1(a) {
                console.log(a);
            }
            fun1()//undefined
    '
    运行

    3、对象没有赋值的属性,该属性的值为undefined

            var obj = {}
            console.log(obj.name);
    '
    运行

    4、函数没有返回值时,默认返回undefined

            function fun1(a) {
                console.log(a);
            }
            var b = fun1(1)
            console.log(b);//undefined
    '
    运行

    Symbol

    Symbol 指的是独一无二的值。每个通过 Symbol() 生成的值都是唯一的。
    一个Symbol值能作为对象属性的标识符;
    这是该数据类型仅有的目的。

    let var_symbol = Symbol();
    let other_symbol = Symbol();
    console.log(var_symbol === other_symbol);
    // false
    console.log(typeof var_symbol);
    // symbol
    console.log(var_symbol.constructor === Symbol)
    // true
    '
    运行

    那么,如何使用 Symbol 创建两个可以相等的变量呢?

    let var_symbol = Symbol.for('symbol');
    let other_symbol = Symbol.for('symbol');
    console.log(var_symbol === other_symbol)
    // true
    '
    运行

    Symbol.for(key) 方法会根据给定的键 key(字符串),来从运行时的 symbol 注册表中找到对应的 symbol,如果找到了,则返回它,否则,新建一个与该键关联的 symbol,并放入全局 symbol 注册表中。

    BigInt

    BigInt 是一种数字类型的数据,它可以表示任意精度格式的整数。而在其他编程语言中,可以存在不同的数字类型,例如:整数、浮点数、双精度数或大斐波数。

    JavaScript 所有数字都保存成 64 位浮点数,这给数值的表示带来了两大限制。一是数值的精度只能到 53 个二进制位(相当于 16 个十进制位),大于这个范围的整数,JavaScript 是无法精确表示的,这使得 JavaScript 不适合进行科学和金融方面的精确计算。二是大于或等于2的1024次方的数值,JavaScript 无法表示,会返回Infinity

    // 超过 53 个二进制位的数值,无法保持精度
    Math.pow(2, 53) === Math.pow(2, 53) + 1 // true
     
    // 超过 2 的 1024 次方的数值,无法表示
    Math.pow(2, 1024) // Infinity
    '
    运行

    ES2020 引入了一种新的数据类型 BigInt,来解决这个问题。BigInt 只用来表示整数,没有位数的限制,任何位数的整数都可以精确表示。

    为了与 Number 类型进行区分,BigInt 类型的数据必须添加后缀n。

    12 	// 普通Number
    12n // BigInt
     
    // BigInt 的运算
    1n + 2n // 3n
    
    // 与Number 类型进行运算
    1 + 1n // Uncaught TypeError
    

    BigInt 与普通整数是两种值,它们之间并不相等。

    12n === 12 // false
    '
    运行

    由于 BigInt 与 Number 完全属于两种类型,并且不会进行隐式转换,所以没有办法进行混合运算。想要运算的话,必须将两种数据类型转换为同一张后,方可进行计算:

    BigInt(number) // 将一个 Number 转换为 BigInt
    Number(bigint) // 将一个 BigInt 转换为 Number
    

    typeof 运算符对于 BigInt 类型的数据返回 bigint。

    typeof 12n // 'bigint'
    '
    运行

    由于 BigInt 并不是一个构造函数,所以,不能使用 new BigInt() 的方式来构建实例

    new BigInt() 
    // Uncaught TypeError: BigInt is not a constructor at new BigInt
    

    另外,当你创建一个 BigInt 的时候,参数必须为整数,否则或报错

    BigInt(1.2) 
    // Uncaught RangeError: The number 1.2 cannot be converted to a BigInt because it is not an integer
    

    4. JS变量的定义与使用

    变量:一小块存储数据的内存空间
    Java语言是强类型语言,而JavaScript是弱类型语言。


    • 强类型:
      在开辟变量存储空间时,定义了空间将来存储的数据的数据类型。只能存储固定类型的数据。
    • 弱类型:在开辟变量存储空间时,不定义空间将来的存储数据类型,可以存放任意类型的数据。

    语法:

    var 变量名 = 初始化值;
    
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>变量</title>
        <script>
    
            //定义变量
            var a = 3;
            alert(a);
    
            a="abc";
            alert(a);
    
            //定义number类型
            var num = 1;
            var num2 = 1.2;
            var num3 = NaN;
    
            //输出到页面上
            document.write(num+"---"+typeof(num)+"
    "
    ); document.write(num2+"
    "
    ); document.write(num3+"
    "
    ); //定义stirng类型 var str = "abc"; var str2 = 'edf'; document.write(str+"
    "
    ); document.write(str2+"
    "
    ); //定义boolean var flag = true; document.write(flag+"
    "
    ); // 定义null var obj = null; var obj2 = undefined; var obj3; document.write(obj+"
    "
    ); document.write(obj2+"
    "
    ); document.write(obj3+"
    "
    ); </script> </head> <body> </body> </html>

    5. JS数据检测方式有哪些

    typeof、typeof NaN是什么结果?

    在这里插入图片描述

    在这里插入图片描述

    • Q:null为基本类型,为啥类型检测为object?
      A:null为空对象的指针,为基本类型,不为引用类型。

    • Q:typeof NaN是什么结果?
      A:number。NaN表示是否属于number类型的一种状态,是或否,不是一种确切的值。JS中number除了浮点型和整数型,还有一个特殊的存在NaN

    const a = 'abc';
    console.log(Number(a)); //NaN
    
    // nan为一个不确切的值范围
    console.log(NaN === NaN);//false
    console.log(NaN !== NaN);//true
    '
    运行

    intanceof

    object instanceof constructor
    不能判断基本数据类型,能判断原型链
    当typeof都为object时,使用intanceof来判断类型,查找原型链

    instanceof 运算符用于检测构造函数的 prototype 属性是否出现在某个实例对象的原型链上。
    prototype 返回对象类型原型的引用

    不能检测null和undefined
    在这里插入图片描述
    在这里插入图片描述

    constructor

    不能检测null和undefined
    在这里插入图片描述
    在这里插入图片描述

    Object.prototype.toString.call()

    在这里插入图片描述
    在这里插入图片描述

    6.原型和原型链

    原型

    在这里插入图片描述
    在这里插入图片描述

    在这里插入图片描述

    在这里插入图片描述
    在这里插入图片描述

    在这里插入图片描述

    找不到方法时,就去隐式原型上去找方法


    在这里插入图片描述

    在这里插入图片描述

    Student.prototypes1.__proto__相等

    在这里插入图片描述

    面试题

    Function.prototype.a = {};
    Object.prototype.b = {};
    
    var F = function(){}
    var f = new F();
    // f里有方法a和方法b吗?
    console.log(f);
    // 只有方法b a存在于Function原型对象中
    '
    运行

    在这里插入图片描述

    JS new一个对象的过程

    在这里插入图片描述


    原型链

    原型链查找属性 作用域链查找变量
    前提场景:Teacher继承Person类,Person类包含一个Teacher类没有的drink方法
    在这里插入图片描述

    在这里插入图片描述
    在这里插入图片描述

    Person.prototype.__proto__ = Object.prototype;  
    // 系统底层会执行类似代码建立默认继承关系
    

    检测是否为本身还是在原型上
    在这里插入图片描述
    intanceof
    对象构造函数的prototype原型属性,是否出现在对象的原型链上,存在intanceof就为true

    在这里插入图片描述

    Object原型链

    在这里插入图片描述

    相关Object和Function原型链的难点

    1. 所有对象都继承自Object
    2. 而Object本身是个构造函数,那么他属于Function
      1. Object的原型再__proto__ 就到顶了,值为null。
      Object.prototype.__proto__; // null
      
      1. Object构造函数constructor指向Function,Object构造函数多了个constructor ,值为Function
      Object.constructor; // ƒ Function() { [native code] }1
      
      1. Function构造函数的显示、隐式原型都指向自身原型
      Function.__proto__ === Function.prototype; // { /* Function原型对象 */  }
      
      1. 任何原型对象的__proto__ 即是向上查找父级原型
      Person.protype.__proto === Object.prototype;
      

    在这里插入图片描述
    在这里插入图片描述

    原型的修改与重写

    在这里插入图片描述

    7. intanceof的原理

    instanceof 的内部机制是通过判断对象的原型链中是不是能找到类型的 prototype。
    使用 instanceof判断一个对象是否为数组,instanceof 会判断这个对象的原型链上是否会找到对应的 Array 的原型,找到返回 true,否则返回 false
    在这里插入图片描述

    8. 判断数组的方法

    Object.prototype.toString.call()

    每一个继承 Object 的对象都有 toString 方法,如果 toString 方法没有重写的话,会返回 [Object type]

    除了 Object 类型的对象外,其他类型直接使用 toString 方法时,会直接返回都是内容的字符串,所以我们需要使用call或者apply方法来改变toString方法的执行上下文

    const an = ['Hello','An'];
    an.toString(); // "Hello,An"
    Object.prototype.toString.call(an); // "[object Array]"
    '
    运行

    slice包头不包尾
    slice() 方法返回一个新的数组对象,这一对象是一个由 begin 和 end 决定的原数组的浅拷贝(包括 begin,不包括end)。原始数组不会被改变。

    console.log(Object.prototype.toString.call([]).slice(8, -1));//Array
    '
    运行

    通过原型链判断

    // 对象隐式原型等于构造函数的显式原型
    console.log([].__proto__ === Array.prototype);//true
    '
    运行

    ES6 api判断 Array.isArray([])

    console.log(Array.isArray([]));
    '
    运行

    intanceof判断

    console.log([] instanceof Array)
    '
    运行

    Array.prototype.isPrototypeOf([]);

    判断Array的prototype是否在对象的原型链上面

    Array.prototype.isPrototypeOf([]);
    '
    运行

    9. JS中 + 操作符什么时候用于字符串的拼接

    + 操作中一个操作数是字符串,则进行字符串的拼接。否则进行数字加法。
    从左到右依次计算

    console.log(1 + 2 + 1 + 'aa' + 1 + 1);//4aa11
    console.log('aa' + 1 + 2 + 1);//aa121
    '
    运行

    10. JS中Object.is()与比较运算符 =====的区别

    在这里插入图片描述

    11.隐式转换

    隐式转换就是自动转换,通常发生在一些数学运算中。因为 JavaScript 是一种弱类型的语言,在一个表达式中,运算符两边的类型可以不同(比如一个字符串和一个数字相加),JavaScript 解释器会在运算之前将它们的类型进行转换
    在这里插入图片描述

    在这里插入图片描述

    12. 深拷贝与浅拷贝

    JS中深拷贝和浅拷贝的区别
    主要在于复制出来的新对象和原来的对象是否会互相影响,改一个,另一个也会变
    浅拷贝和深拷贝都是对象或数组的复制方式,但它们的实现方式和效果有所不同。

    • 浅拷贝:

      • 仅仅是指向被复制的内存地址,如果原地址发生改变,那么浅拷贝出来的对象也会相应的改变
        新旧对象共享内存,修改其中一个,另一个也会受到影响

      • 浅拷贝的引用类型被改变 会改变元数据的引用地址

      • 浅拷贝是指只复制对象的第一层属性,如果对象的属性值是引用类型,则只复制其引用地址。

      • 浅拷贝在复制时,只复制对象或数组本身以及第一层的属性或元素。

      • 如果被复制的对象或数组中包含了引用类型的属性或元素,那么这些引用类型的属性或元素会共享同一个内存地址。因此,在修改其中一个对象或数组时,会影响到其他对象或数组。

        示例代码:

        在这里插入图片描述

        上面代码中,使用Object.assign()方法进行浅拷贝后,修改obj2.b.c的值也会影响到原始对象obj1。

    • 深拷贝:
      在内存中开辟一块新的地址用于存放复制的对象
      新旧对象不会共享内存,修改其中的一个不会影响另一个

      深拷贝是指在复制时,完全复制对象或数组以及所有嵌套的属性或元素,并且新生成的对象与原始对象没有任何关联。
      因此,在修改其中一个对象或数组时,不会对其他任何对象造成影响。

      示例代码:

      在这里插入图片描述

      上面代码中,使用JSON.parse()和JSON.stringify()方法进行深拷贝后,修改obj2.b.c的值不会影响到原始对象obj1。

      需要注意的是,在使用深拷贝时,可能存在无法复制的属性或元素,例如函数、undefined等。另外,对于循环引用的对象或数组,也需要特殊处理以避免出现死循环。

    浅拷贝:通过=直接赋值

    var obj1 = { name: "zs", age: 20 }
    var obj2 = obj1
    console.log(obj1);//{name: 'zs', age: 20}
    
    obj1.age = 22
    console.log(obj1);//22
    console.log(obj2);//22
    '
    运行

    浅拷贝:Object.assign()

    • Object.assign()用于对象的合并,如果第一个参数为{},则可对后面的对象参数进行拷贝
    • Object.assign() 方法将所有可枚举(Object.propertyIsEnumerable() 返回 true)的自有(Object.hasOwnProperty() 返回 true)属性从一个或多个源对象复制到目标对象,返回修改后的对象

    浅拷贝是指只复制对象的第一层属性,如果对象的属性值是引用类型,则只复制其引用地址。下面是一个浅拷贝的例子:
    在这里插入图片描述

    从上面代码可以看到,使用 Object.assign() 方法进行浅拷贝后,修改了克隆对象的属性值后原始对象和克隆对象的 nameage 属性不同,但是它们共享同一个 hobbies 数组。这就是因为在浅拷贝中,只有第一层属性被复制了过来,而对于嵌套在第二层及以下的属性则仍然共享同一个内存地址。

    如果需要深度拷贝整个嵌套结构体,需要使用深拷贝。

    浅拷贝:[].concat()

    在这里插入图片描述

    浅拷贝:slice()

    slice() 方法返回一个新的数组对象,这一对象是一个由 begin 和 end 决定的原数组的浅拷贝(包括 begin,不包括end)。原始数组不会被改变。
    在这里插入图片描述

    浅拷贝:使用Array.from()

    Array.from() 方法对一个类似数组或可迭代对象创建一个新的,浅拷贝的数组实例。
    对数组元素的浅复制,而不是对数组的浅复制

    slice是浅拷贝。它会创建一个新数组,该新数组包含原始数组中的一部分元素。但是,这些元素仍然引用原始数组中的相同对象,因此如果修改原始数组中的对象,则也会反映在新数组中。

    slice操作针对引用类型是浅拷贝。也就是说,在新数组中复制的对象仍然引用原始数组中相同的对象。
    如果修改原始数组中的某个对象,则会反映在新数组中相应位置的对象上。
    但是,对于基本数据类型(如数字、字符串等),slice操作实际上是深拷贝,因为它们被直接存储在数组中而不是通过引用传递。

    console.log(Array.from('foo'));
    // expected output: Array ["f", "o", "o"]
    
    console.log(Array.from([1, 2, 3], x => x + x));
    // expected output: Array [2, 4, 6]
    
    '
    运行
    let a = [1, 2, [1, 2, 3]];
    let b = Array.from(a);
    console.log(a == b);    // false
    
    a[2][1] = 11;
    a[0] = 11;
    
    console.log(a); // [ 11, 2, [ 1, 11, 3 ] ]
    console.log(b); // [ 1, 2, [ 1, 11, 3 ] ]
    console.log(a[2] == b[2]);  // true
    '
    运行

    深拷贝:使用JSON对象实现深拷贝

    JSON.stringify:将js的值(对象或者数组)转为一个JSON字符串
    JSON.parse:用来解析JSON字符串,转换为Object类型

    var obj1 = { name: "zs", age: 20 }
    var obj2 = JSON.parse(JSON.stringify(obj1));
    console.log(obj1);
    console.log(obj2);
    
    obj1.age = 30
    
    console.log(obj1);//30
    console.log(obj2);//20
    '
    运行

    浅拷贝:使用…扩展运算符实现

    扩展运算符是浅拷贝。

    使用扩展运算符可以将一个对象的所有属性复制到另一个对象中。但是,当对象中存在嵌套的引用类型属性时,它们仍然只会被复制引用地址而不是完整的拷贝值。
    在这里插入图片描述

    const list = {
    	//引用对象为浅拷贝
        china: {
            city: '成都'
        }
    }
    
    const listCopy = { ...list };
    
    listCopy.china.city = '上海'
    
    console.log(list);//上海
    console.log(listCopy);//上海
    '
    运行

    需要影响引用类型

    // 浅拷贝
    var obj1 = { name: "zs", age: 20 }
    var obj2 = { ...obj1, age: 30 }
    
    console.log(obj1);//20
    console.log(obj2);//30
    
    obj2.age = 22
    
    console.log(obj1);//20
    console.log(obj2);//22
    '
    运行

    仅对引用类型数据的第一层进行了拷贝,而倘若再深的层次就不会进行拷贝。

    //数组的复制 第一层深拷贝 再深层次浅拷贝
    var arr1 = [1,2,3,4,[5]];
    var arr2 = [...arr1]
    arr1[0]=18;
    arr2[4][0]=100; 
    console.log(arr1);
    console.log(arr2);
    '
    运行

    13.JS中与和或操作符运算返回值

    或:先检测第一个字是否boolean类型,如果不是boolean类型,就强转布尔类型。第一个为真,则返回第一个数。否则返回第二个。

    console.log(1 || 2);//1
    console.log(0 || 2);//2
    '
    运行

    与:第一个操作数为真,返回第二个操作数
    第一个操作数为假,则返回第一个操作数

    console.log(1 && 2);//2
    console.log(0 && 2);//0
    console.log(2 && 0);//0
    '
    运行

    不是返回true和false,返回操作数值。

    14.JS中==操作符的强制类型转换规则

    console.log(1 == '1');//true
    console.log(1 == {});//false
    console.log(true == 3);//false
    console.log(true == 1);//true
    
    var a = {}
    var b = a
    var c = {}
    console.log('a==c:' + (a == c)); //false
    console.log('a==b:' + (a == b)); //true
    console.log('b==c:' + (b == c)); //false
    '
    运行

    15.JS中isNaN和Number.isNaN的区别

    isNaN(value)为了判断一个计算结果value或变量的值value是否为NaN

    isNaN的判断过程:首先进行类型检测,如果传入的参数不是数值类型,第二步将传入的参数转为数值类型,然后再进行是否为NaN的判际NaN。
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

    16.ES6中const定义的对象的属性可以修改吗

    const保证并不是变量的值不能改动,而是变量指向的内存地址不能改动

    // const保证并不是变量的值不能改动,而是变量指向的内存地址不能改动
    const obj = { name: 'lishi', age: 20 };
    console.log(obj);//{name: 'lishi', age: 20}
    obj.name = '李四'
    console.log(obj);//{name: '李四', age: 20}
    '
    运行

    17.ES6中let、const和var的用法以及区别

    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

    18.JS中如何判断对象是一个空对象

    // 引用地址不一样 不能由此判断是否为空对象
    console.log({} === {});//false
    console.log({} == {});//false
    
    // 使用JSON的stringify方法
    var obj = {}
    console.log(JSON.stringify(obj) === '{}');//true
    
    // 使用Object.keys() 枚举自身属性,返回字符串数组
    var obj1 = { name: '1231', age: 333 }
    var obj2 = {}
    console.log(Object.keys(obj1));//['name', 'age']
    console.log(Object.keys(obj2));//[]
    console.log(Object.keys(obj2).length);//0
    '
    运行

    19.ES6 new 一个箭头函数会怎么样

    在这里插入图片描述
    在这里插入图片描述

    20.ES6中扩展运算符的作用

    // 作用一:将数组变为一个以空格分隔的序列
    var arr = [1, 2, 3, 4, 5, 6]
    console.log(...arr);//1 2 3 4 5 6 空格分隔
    
    // 作用二:复制
    //数组的复制
    var arr1 = [1, 2, 3, 4, [5]];
    var arr2 = [...arr1]
    arr1[0] = 18;
    arr2[4][0] = 100;
    console.log(arr1);
    console.log(arr2);//二维深度为浅拷贝
    
    // 对象的复制(深拷贝)
    var obj1 = { name: 'zs', age: 18 }
    var obj2 = { ...obj1 }
    obj1.age = 20;
    console.log(obj1);
    console.log(obj2);
    
    // 作用三:合并
    // 数组的合并
    var arr3 = [1, 2, 3, 4]
    var arr4 = [5, 6, 7]
    console.log([...arr3, ...arr4]); //[1, 2, 3, 4, 5, 6, 7]
    
    //对象的合并
    var o1 = { name: 'lisi' }
    var o2 = { age: 22 }
    console.log({ ...o1, ...o2 });//{name: 'lisi', age: 22}
    '
    运行

    21.ES6的rest参数

    在这里插入图片描述

    22.ES6中对象和数组的解构

    在这里插入图片描述

    23. 什么是DOM 和 BOM

    • DOM : document,文档对象类型,用来获取或者设置文档标签的属性S可以通过DOM获取到有哪些标签,标签有哪些属性,内容有哪些,DOM操作的对象是文档,所以DOM和浏览器没有关系,关注网页本身的内容

    • BOM:browser object model,浏览器对象模型,提供独立于内容而与浏览器窗口进行交互的对象
      管理窗口与窗口之间的通讯,核心对象是window–> location(用F于url相关的操作)、history(用于历史相关的操作),navigator(包含了浏览器相关的信息)BOM是控制浏览器行为的api, DOM是一个页面结构的api

    24. JS中的this关键字

    默认绑定全局this

    // 默认绑定全局this
    function girl() {
        console.log(this);
    }
    girl();//log window
    '
    运行

    隐式绑定

    // 隐式绑定
    var girl = {
        name: '小红',
        age: 22,
        detail: function () {
            console.log(this.name);
            console.log(this.age);
        }
    }
    girl.detail();
    '
    运行

    硬绑定

    // 硬绑定
    var girlName = {
        name: '小红',
        sayName: function () {
            console.log(this.name);
        }
    }
    var girl1 = {
        name: '小白'
    }
    var girl2 = {
        name: '小黄'
    }
    girlName.sayName.call(girl1);//小白
    girlName.sayName.call(girl2);//小黄
    '
    运行

    构造函数绑定

    // 构造函数绑定
    function Lover(name) {
        this.name = name;
        this.sayName = function () {
            console.log(this.name);
        };
    }
    var name = '小白'
    var xiaohong = new Lover('小红')
    xiaohong.sayName();//小红
    '
    运行

    在这里插入图片描述
    输出
    在这里插入图片描述


    在这里插入图片描述
    输出在这里插入图片描述


    在这里插入图片描述
    在这里插入图片描述

    25. 模仿call函数

    call是用来修改this指向的
    每个js函数都Function对象,Function对象是构造函数,构造函数有原型对象Function.prototype,call就是原型对象属性来的

    Function.prototype.myCall = function (obj, ...arr) {
        const newObj = obj || global;
        newObj.p = this;
        const result = newObj.p(...arr);
        delete newObj.p;
        return result;
    };
    
    '
    运行

    26. Ajax 是什么? 如何创建一个 Ajax?

    构造函数XMLHttpRequest可创建一个xhr实例,可调用open、readyState、send方法
    在这里插入图片描述

    原生Ajax五个基本步骤

    参见AJAX的使用
    在这里插入图片描述
    使用promise封装ajax
    详细见 39.ES6使用Promise封装AJAX
    在这里插入图片描述

    27. JS中函数arguments类数组

    // JS中arguments类数组
    // 为什么函数的arguments参数是类数组而不是数组 ? 如何遍历类数组 ?
    
    // 类数组:与数组相似,但是没有数组常见的方法属性
    function func() {
        console.log(arguments);
        for (let i = 0; i < arguments.length; i++) {
            console.log(arguments[i]);
        }
    }
    func(1, 2, 3, 4);
    console.log('------------------------------------------');
    // 1.将数组的方法应用到类数组上
    function fun1() {
        Array.prototype.forEach.call(arguments, (item) => {
            console.log(item);
        })
    }
    fun1(1, 2, 3, 4);
    console.log('------------------------------------------');
    //2.将类数组专为数组 使用Array.from
    function fun2() {
        const arr = Array.from(arguments)
        arr.push(5)
        console.log(arr);
    }
    fun2(1, 2, 3, 4);//[1,2,3,4]
    console.log('------------------------------------------');
    //3.使用展开运算符
    function fun3() {
        const arr1 = [...arguments];
        console.log(arr1);
        arr1.forEach((item) => {
            console.log(item);
        })
    }
    fun3(1, 2, 3, 4);//[1, 2, 3, 4]
    '
    运行

    28. JS中如何判断一个对象属于一个类

    使用instanceof

    //类本身指向是构造函数 类的数据类型是函数
    function Person(name) {
        this.name = name;
    }
    const obj = new Person('李四');
    
    // instanceof:判断构造函数的prototype是否在对象的原型链上(更准确)
    const obj1 = {};
    console.log(obj instanceof Person);//true
    console.log(obj1 instanceof Person);//false
    
    //使用对象属性constructor来判断 指向该对象的构造函数
    console.log(obj.__proto__.constructor);
    // ƒ Person(name) {
    //     this.name = name;
    // }
    '
    运行

    29. JS中foreach和map的区别

    两者返回的值不一样,区别:map分配内存空间存储新数组,并且返回,forEach不会返回

    Array.prototype.forEach()
    foreach()返回undefined
    forEach() 方法对数组的每个元素执行一次给定的函数。

    const array1 = ['a', 'b', 'c'];
    
    array1.forEach(element => console.log(element));
    
    array1.forEach(
        (element, index, arr) => {
            console.log(element);//element数组的遍历 
            console.log(index);//index 索引
            console.log(arr);//arr数组本身
        })
    '
    运行

    Array.prototype.map()
    map()在内存中返回一个新数组
    map() 方法创建一个新数组,这个新数组由原数组中的每个元素都调用一次提供的函数后的返回值组成。

    const array1 = [1, 4, 9, 16];
    
    // pass a function to map
    const map1 = array1.map(x => x * 2);
    
    console.log(map1);
    // expected output: Array [2, 8, 18, 32]
    
    '
    运行

    30. ES6中使用for…of来遍历对象

    // for...of是允许遍历一个含有iterator接口的数据结构(数组、对象等)并且返回各项的值
    // for...of语句在可迭代对象(包括 Array,Map,Set,String,TypedArray,arguments 对象等等)上创建一个迭代循环,调用自定义迭代钩子,并为每个不同属性的值执行语句
    const array1 = ['a', 'b', 'c'];
    
    for (const element of array1) {
        console.log(element);
    }
    // expected output: "a"
    // expected output: "b"
    // expected output: "c"
    
    
    // 需要遍历的对象是类数组对象,使用数组的Array.from转为数组
    var obj = {
        0: 1,
        1: 2,
        2: 3,
        length: 3
    }
    obj = Array.from(obj)
    console.log(obj);
    for (const i of obj) {
        console.log(i);
    }
    
    console.log('----------------------------------------');
    
    // 需要遍历的对象不是类数组,需要给对象添加一个Symbol.iterator属性,指向迭代器
    // iterator遍历过程
    //1、创建一个指针对象,指向当前数据结构的起始位置
    //2、第一次调用指针对象的next方法,可以将指针指向数据结构的第一个成员
    //3、第二次调用指针对象的next方法,指针就指向数据结构的第二个成员
    //4、不断调用指针对象的next方法,直到它指向数据结构的结束位置
    //每一次调用next方法,都会返回数据结构的当前成员的信息,包含value和done两个属性的对象
    // done:是一个布尔值 代表遍历是否结束
    var person = {
        name: '张三',
        age: 12,
        gender: '男',
        height: 188
    }
    person[Symbol.iterator] = function () {
        //拿到对象中所有的key值
        // var key = Object.keys(person)
        let keys = Object.keys(this);
        // 定义下标值
        let index = 0;
        console.log('keys:' + keys);
        return {
            next() {
                if (index < keys.length) {
                    return { value: person[keys[index++]], done: false }
                }
                return { value: undefined, done: true }
            }
        }
    }
    
    for (let value of person) {
        console.log(value);
    }
    
    '
    运行

    31.JS中数组的遍历方法有哪些

    for 循环

    var arr = ['red','green', 'blue'];
    for(var i = 0; i < arr.length; i++){
        console.log(arrStus[i]);
    }
    

    foreach

    // forEach:不会改变原数组 没有返回值
    const forEachResult =
      arr.forEach((element, index, arr) => {
        console.log(element);
        console.log(index);
        console.log(arr);
      });
    
    console.log(forEachResult);//undefined
    

    map

    // map :不会改变原数组 具有返回值
    const mapResult = arr.map(
      (item, index, arr) => {
        console.log(item);
        console.log(index);
        console.log(arr);
        return item * 2
      }
    )
    console.log('mapRES:' + mapResult);//2 4 6
    

    filter

    filter() 方法创建给定数组一部分的浅拷贝,其包含通过所提供函数实现的测试的所有元素。

    const words = ['spray', 'limit', 'elite', 'exuberant', 'destruction', 'present'];
    
    const result = words.filter(word => word.length > 6);
    
    console.log(result);
    // expected output: Array ["exuberant", "destruction", "present"]
    '
    运行
    // filter 过滤数组 返回符合条件的元素数组
    const resultFilter = arr.filter(
      (item) => {
        return item > 1
      }
    )
    console.log(resultFilter);//[2, 3]
    

    for…of

    for…of语句在可迭代对象(包括 Array,Map,Set,String,TypedArray,arguments 对象等等)上创建一个迭代循环,调用自定义迭代钩子,并为每个不同属性的值执行语句

    // for ... of 返回是数组的元素 对象的属性值 不能遍历普通的对象
    for (const value of arr) {
      console.log(value);
    }
    

    reduce

    reduce() 方法对数组中的每个元素按序执行一个由您提供的 reducer 函数,每一次运行 reducer 会将先前元素的计算结果作为参数传入,最后将其结果汇总为单个返回值。

    第一次执行回调函数时,不存在“上一次的计算结果”。如果需要回调函数从数组索引为 0 的元素开始执行,则需要传递初始值。否则,数组索引为 0 的元素将被作为初始值 initialValue,迭代器将从第二个元素开始执行(索引为 1 而不是 0)。

    const array1 = [1, 2, 3, 4];
    
    // 0 + 1 + 2 + 3 + 4
    const initialValue = 0;
    const sumWithInitial = array1.reduce(
     (previousValue, currentValue) => previousValue + currentValue,
     initialValue
    );
    
    console.log(sumWithInitial);
    // expected output: 10
    '
    运行
    // reduce 接收一个函数 作为一个累加器
    // pre 计算之后返回的值
    // item 当前的值
    // 回调函数从数组索引为 0 的元素开始执行
    let result = arr.reduce((pre, item) => {
      // console.log('pre;' + pre);
      // console.log('item:' + item);
      return pre + item
    }, 0)
    console.log(result);
    

    32.浏览器从输入URL到页面加载的全过程

    在这里插入图片描述

    33.ES6中for…of和for…in的区别

    在这里插入图片描述

    34.JS如何判断一个属性是属于实例对象还是继承与构造函数

    在这里插入图片描述

    35.apply和call和bind的作用与区别

    Function.prototype.bind()

    bind() 方法创建一个新的函数,在 bind() 被调用时,这个新函数的 this 被指定为 bind() 的第一个参数,而其余参数将作为新函数的参数,供调用时使用。
    在这里插入图片描述

    Function.prototype.apply()

    apply() 方法调用一个具有给定 this 值的函数,以及以一个数组(或一个类数组对象)的形式提供的参数。
    在这里插入图片描述

    Function.prototype.call()

    call() 方法使用一个指定的 this 值和单独给出的一个或多个参数来调用一个函数。
    在这里插入图片描述

    区别

    在这里插入图片描述

    36. ES6 Promise及解决回调地狱问题

    Promise是什么

    一个 Promise 必然处于以下几种状态之一:
    待定(pending):初始状态,既没有被兑现,也没有被拒绝。
    已兑现(fulfilled):意味着操作成功完成。
    已拒绝(rejected):意味着操作失败。

    特点:状态不受外界的影响,只有异步操作的结果决定当前是哪一种状态
    一旦状态改变就不会再变(pending–>fufilled, pending–>rejected)
    Promise是什么?:Promise是一个构造函数,用来生成Promise实例
    Promise构造函数接受一个函数作为参数,函数带有两个参数,resolve,reject
    在这里插入图片描述

    Promise实例方法

    在这里插入图片描述

    Promise解决回调地狱

    在这里插入图片描述

    37.ES6 Promise.all的理解及应用场景

    将多个Promise对象 包装成一个Promise对象
    Promise.all()
    Promise.all() 方法接收一个 promise 的 iterable 类型(注:Array,Map,Set 都属于 ES6 的 iterable 类型)的输入,并且只返回一个Promise实例
    在这里插入图片描述
    在这里插入图片描述
    应用场景
    在这里插入图片描述


    38.ES6 Promise.race的用法及使用场景

    多个promise包装成一个promise对象。
    看某个实例先返回状态。先返回的实例传给race的回调函数。
    Promise.race()
    Promise.race(iterable) 方法返回一个 promise,一旦迭代器中的某个 promise 解决或拒绝,返回的 promise 就会解决或拒绝。
    在这里插入图片描述

    成功
    在这里插入图片描述

    失败
    在这里插入图片描述

    使用场景
    在这里插入图片描述


    39.ES6 使用Promise封装AJAX

    AJAX实现过程

    在这里插入图片描述
    在这里插入图片描述

    封装例子

    在这里插入图片描述
    在这里插入图片描述

    XMLHttpRequest()

    The XMLHttpRequest() 构造器初始化一个新的 XMLHttpRequest 对象。

    XMLHttpRequest.open()

    XMLHttpRequest.open() 方法初始化一个新创建的请求,或重新初始化一个请求。
    xhrReq.open(method, url, async, user, password);
    在这里插入图片描述

    XMLHttpRequest.send()

    XMLHttpRequest.send() 方法用于发送 HTTP 请求。如果是异步请求(默认为异步请求),则此方法会在请求发送后立即返回;如果是同步请求,则此方法直到响应到达后才会返回。
    在这里插入图片描述

    XMLHttpRequest.onreadystatechange

    在这里插入图片描述

    XMLHttpRequest.readyState

    在这里插入图片描述

    XMLHttpRequest.response

    在这里插入图片描述


    40.DOM添加新元素、删除元素

    添加元素

    创建元素
    使用 JS 可以为一个已有的元素添加一个新的子元素。

    第一步:创建空元素。

    • var elem = document.createElement("标签名");

    • 创建元素后,可以像使用 DOM 树中的任意元素一样,为此元素添加属性或内容。

    • elem.id = "xxx";

    • elem.innerHTML = "xxx";

    注意:元素创建完成后,只是在内存中保存,并没有添加到 DOM 树。

    第二步:将新创建的元素添加到 DOM 树的指定父元素下。

    • 在父元素末尾追加:parent.appendChild(elem);

    • 添加到某个子元素之前:parent.insertBefore(a,child);

    • 替换某个子元素:parent.replaceChild(a,child);

    JS 优化建议:尽量少的操作 DOM 树,同时添加父元素及其子元素的时候,先在内存中将子元素创建完毕并拼到父元素中,再一次性将父元素添加到页面。

    删除一个子元素

    • parent.removeChild(child);

    实例:JavaScript DOM:Node对象、添加子节点、删除子节点

    JavaScript DOM API中append和appendChild的不同点

    JavaScript DOM API中append和appendChild的不同点


    41.封装一个AJAX

    手动封装一个ajax
    在这里插入图片描述

    42.JS中对事件流的理解

    • 事件流:从页面中接收事件的顺序
    • 事件流分为三个阶段:捕获阶段、当前目标阶段、冒泡阶段
    • addEventListenter(事件,回调函数,布尔值(false冒泡,true捕获)默认为false)

    addEventListener(type, listener, useCapture);

    EventTarget.addEventListener() 方法将指定的监听器注册到 EventTarget 上,当该对象触发指定的事件时,指定的回调函数就会被执行。

    捕获阶段

    在这里插入图片描述

    冒泡阶段

    在这里插入图片描述

    JS中阻止事件冒泡和默认行为

    • 阻止默认行为
      preventDefault()方法
      e.preventDefault();
      兼容ie678
      e.returnValue = false

    • 阻止事件冒泡
      e.stopPropagation()
      ie 678 —— e.cancelBubble
      在这里插入图片描述

    43.Array.prototype.sort()

    // 无函数
    sort()
    
    // 箭头函数
    sort((a, b) => { /* … */ } )
    
    // 比较函数
    sort(compareFn)
    
    // 内联比较函数
    sort(function compareFn(a, b) { /* … */ })
    

    降序

    .sort(function (a, b) {
    	return b - a;
    });
    

    升序

    .sort(function (a, b) {
    	return a - b;
    });
    

    44. JS中的防抖

    在这里插入图片描述

    //防抖和节流:限制函数执行的次数
    //JS中实现函数的防抖
    //通过setTimeout的方式,在一定的时间间隔内,将多次触发变成一次触发
    let ipt = document.getElementById('ipt');
    let btn = document.getElementById('btn');
    
    function getValue(e) {
        let val = ipt.value
        console.log(val);
        console.log(e);
        console.log(this);
    }
    btn.onclick = debounce(getValue, 1000);
    
    // 简版
    function debounce(fn, delay) {
        let timer = null;
        return function () {
            clearTimeout(timer)
            timer = setTimeout(fn, delay)
        }
    }
    function debounce(fn, delay) {
        // 定义最开始定时器对象
        let timer = null;
        return function () {
            let that = this;
            if (timer) {//判断定时器是否生成 生成则清除上一个定时器
                clearTimeout(timer);
            }
            // 判断第一次点击 立即执行
            let firstClick = !timer;
            if (firstClick) {
                fn.apply(that, arguments)//改变this指向到btn
            }
            timer = setTimeout(() => {
                timer = null
            }, delay)
        }
    }
    

    45. JS中的节流

    在这里插入图片描述

    // 节流: 减少一段时间的触发频率(时间戳),控制事件发生的频率,控制在2s发生一次
    let ipt = document.getElementById('ipt');
    let btn = document.getElementById('btn');
    
    btn.onclick = throttle(getValue, 2000);
    
    function getValue() {
        let val = ipt.value
        console.log(val);
    }
    
    function throttle(fn, time) {
        let begin = 0;//设置时间的初始值
        return function () {
            // 当前时间戳
            let date = new Date().getTime();
            let that = this;
            if (date - begin > time) {
                fn.apply(that, arguments)
                begin = date;
            }
        }
    }
    //scroll: 每隔一秒计算一次位置信息
    // 搜索框实时搜索,并且发送请求,展示下拉列表,每隔两秒发送一次请求
    
    

    46. 箭头函数的理解

    在这里插入图片描述

    注意点

    • 1:箭头函数内的this是静态的,总是指向定义时所在的对象,而不是调用时。并且this指向是不可以改变的。
      在这里插入图片描述

    • 2.this始终指向函数声明时所在作用域下的this的值。
      在这里插入图片描述

    • 3.箭头函数不能当做构造函数,也就是不可以用new命令,否则报错。
      在这里插入图片描述

    • 4.箭头函数不存在arguments对象,即不能使用伪数组去接收参数,可以使用rest参数代替。
      在这里插入图片描述
      使用场景
      在这里插入图片描述

    47. JS中use strict是什么意思 使用它有什么注意点

    在这里插入图片描述

    48. loaclStorage和sessionStorage

    • loaclStorage:永久存储在本地,适合保存在本地的数据
    • sessionStorage:会话级的存储,敏感账号一次性登录
    保存数据语法
    localStorage.setItem(“key”, “value”);
    sessionStorage.setItem(“key”, “value”);
    
    读取数据语法:
    var lastname = localStorage.getItem(“key”);
    var lastname = sessionStorage.getItem(“key”);
    
    删除数据语法:
    localStorage.removeItem(“key”);
    sessionStorage.removeItem(“key”);
    
    • 相同点
      1.都是保存在浏览器端
      2.不会把数据自动的发送给服务器,仅在本地保存
      3.只能存储字符串,可以将对象JSON.stringfy()编码之后进行存储
    • 不同点
      1.存储大小限制不同:
      sessionStorage存储的大小为5M, localStorage存储大小为20M
      2.数据有效期不同:
      localStorage:始终有效,窗口关闭或者浏览器关闭,一直保存,持久保存数据
      sessionStorage:仅在当前浏览器窗机关闭前有效,会话级存储
      3.作用域不同:
      sessionStorage:在不同的浏览器窗口不会进行共享,只有同一个页面中localStorage:在所有的同源的窗口下可以共享的

    49. JS中内存溢出相关情况

    内存泄漏: 由于疏忽或错误造成程序未能释放已经不再使用的内存
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

    50. 作用域和作用域链

    作用域
    在这里插入图片描述

    在这里插入图片描述
    作用域链:本层找不到 继续查找外层
    原型链查找属性 作用域链查找变量

    在这里插入图片描述

    在这里插入图片描述
    在这里插入图片描述

    51. JS中的闭包

    闭包是指有权访问另外一个函数作用域中的变量的函数
    在这里插入图片描述

    在这里插入图片描述
    在这里插入图片描述

    52. JS中的事件代理

    在这里插入图片描述

    53. JS清空数组的方法

    在这里插入图片描述

    54. JS继承

    继承可使子类有父类的各种属性和方法

    使用原型链继承

    在这里插入图片描述

    构造函数继承

    在这里插入图片描述

    class继承

    在这里插入图片描述

    55. html网页有几种布局

    HTML网页主要有以下几种布局:

    • 流式布局(Fluid Layout):
      根据浏览器窗口大小自动调整页面元素的大小和位置,使得页面适应不同设备屏幕的大小。
    流式布局是一种响应式设计(responsive design)的布局方式,也被称为“弹性布局”或“自适应布局”。它通过设置百分比宽度、最大宽度和最小宽度等属性来实现页面元素的自适应调整,从而能够在不同设备和屏幕大小下呈现出更好的用户体验。
    
    在使用流式布局时,需要遵循以下原则:
    
    使用百分比定义元素宽度;
    针对不同尺寸设备设置不同的样式表;
    注意保证最小宽度和最大宽度之间合理的差距,以免造成排版混乱或无法满足需求。
    
    • 固定宽度布局(Fixed Width Layout):
      指定页面元素的宽度为固定像素值,使得页面在不同分辨率下显示效果一致。但是可能会出现在小屏幕上无法完全显示或者在大屏幕上留有过多空白区域的问题。

    • 响应式布局(Responsive Layout):
      通过CSS Media Query技术实现,根据设备屏幕宽度来自适应地调整样式,使得页面能够在不同尺寸的设备上保持良好的可读性和可用性。

    响应式布局和流式布局都是为了适应不同设备屏幕尺寸而设计的,但它们有以下不同:
    
    1. 响应式布局通过媒体查询来实现针对不同屏幕大小的样式调整,
    而流式布局则是根据相对比例设置元素宽度,当窗口大小改变时会自动适应。
    
    2. 响应式布局通常使用断点(breakpoint)来指定在不同尺寸下使用不同的样式规则,
    而流式布局没有明确定义的断点。
    
    3. 响应式布局可以在某些情况下隐藏或移除某些元素以提高用户体验。
    而流式布局并不能很好地处理这种情况。
    
    • 网格布局(Grid Layout):
      通过CSS Grid技术实现,将页面划分成网格,并且指定每个网格中元素的位置和大小,可以实现更复杂、灵活和美观的页面布局。

    • flex布局

    flex布局是CSS3中新增的一种布局方式,用于更加方便、快捷地实现页面元素的排列和对齐。
    它通过对容器和子元素设置一系列属性来控制元素的尺寸、位置和排列方式。
    
    使用flex布局可以实现以下优点:
    
    1. 灵活性强:可以根据不同设备和屏幕大小动态调整布局;
    2. 可读性好:代码简洁明了,易于理解和维护;
    3. 响应式设计:可以自适应不同设备和屏幕大小,适应多种场景需求。
    
    flex布局包括两个概念:
    容器(flex container)和项目(flex item)。
    容器是指包含要进行排列的所有元素的父级元素,而项目则是指这些被排列的子元素。
    在使用flex布局时,需要对容器和项目分别设置属性来控制其展示效果。
    
    常用的属性有:
    
    - 容器相关属性
      - display: flex; // 将容器设置为一个弹性盒子
      - flex-direction: row/row-reverse/column/column-reverse; // 设置主轴方向
      - justify-content: flex-start/flex-end/center/space-between/space-around; // 主轴上项目的对齐方式
      - align-items: flex-start/flex-end/center/baseline/stretch; // 交叉轴上项目的对齐方式
      - flex-wrap: nowrap/wrap/wrap-reverse; // 是否允许项目换行,以及换行方式
    
    - 项目相关属性
      - flex: none/1/auto; // 项目的放大比例、缩小比例和基准大小
      - order: <integer>; // 控制项目的排列顺序
      - align-self: auto/flex-start/flex-end/center/baseline/stretch; // 自身在交叉轴上的对齐方式
    
    需要注意的是,在使用flex布局时需要考虑到浏览器兼容性问题,
    特别是一些老旧浏览器可能不支持部分flex属性。
    
    

    56. 性能调优

    在前端开发中,性能调优是一个重要的主题。以下是一些常见的技术和实践,可以帮助提高前端应用程序的性能:

    1. 减少 HTTP 请求:将多个 CSS 和 JavaScript 文件合并成单个文件,并使用图像精灵(sprite)来减少页面请求次数。

    2. 压缩文件大小:压缩 HTML、CSS 和 JavaScript 文件以减小文件大小,并加快页面加载速度。

    3. 懒加载:懒加载图片和其他资源,只有当用户滚动到它们所在的位置时才加载它们。这样可以减少页面初始加载时间,并且仅在需要时加载额外内容。

    4. 避免 DOM 操作:避免频繁地更新 DOM 元素,因为这会导致浏览器重新渲染整个页面。相反,尝试使用文档片段或虚拟 DOM 等技术来进行批量操作。

    5. 缓存数据:使用本地存储或浏览器缓存等技术来缓存数据,以便在下一次访问时可以更快地检索数据。

    6. 代码优化:编写高效的代码并避免不必要的计算和循环。此外,在处理大型数据集时,请尽可能使用数组方法而不是循环迭代。

    7. 减少重绘和回流:避免频繁更改页面元素的样式和布局,因为这会导致浏览器重绘和回流。相反,请尝试使用 CSS transform 和 opacity 属性等技术来进行动画和过渡。

    8. 服务端渲染(SSR):使用服务端渲染可以提高首屏加载速度,并减少客户端资源的需求。

    总之,性能调优是一个复杂的过程,需要注意各种因素。对于前端开发人员来说,理解浏览器原理、网络协议和编码最佳实践是必不可少的。

    57. js中new一个对象会进行什么步骤

    当使用new操作符创建一个对象时,会进行以下步骤:

    1. 创建一个空的JavaScript对象
    2. 将这个新对象的原型设置为构造函数的prototype属性(obj.__proto__ = Person.prototype)
    3. 将构造函数中的this关键字绑定到新创建的对象上(Person.call(obj))
    4. 执行构造函数中的代码,给新对象添加属性和方法
    5. 如果构造函数没有返回其他对象,则返回新创建的对象

    例如:

    function Person(name, age) {
      this.name = name;
      this.age = age;
    }
    
    const john = new Person('John', 30);
    '
    运行

    在这个例子中,调用new Person('John', 30)会执行以上步骤,最后生成一个包含nameage属性的新对象,并将其赋值给变量john

    58. 创建对象的方式有哪些

    JavaScript 创建对象的方式主要有以下几种:

    1. 对象字面量(Object Literal)

    通过直接定义键值对来创建一个简单对象。

    在这里插入图片描述

    1. 构造函数(Constructor Function)

    通过使用 new 运算符调用构造函数来创建一个对象,其中构造函数可以接收参数并在内部进行属性赋值和方法定义等操作。

    在这里插入图片描述

    1. Object.create()

    Object.create() 静态方法以一个现有对象作为原型,创建一个新对象。
    在这里插入图片描述

    在这里插入图片描述

    在这里插入图片描述

    1. Class

    ES6 提供了 Class 关键字来定义类,并在类中定义属性和方法。通过使用 new 运算符调用类来创建一个新的对象。

    在这里插入图片描述

    1. assign
      在这里插入图片描述

    2. 使用构造器创建
      在这里插入图片描述

    59. js的事件流

    先捕获,后冒泡,捕获是先父后子,冒泡是先子后父
    在这里插入图片描述
    在这里插入图片描述

    阻止事件流行为,我们可以用
    e.stopPropagation()
    在这里插入图片描述

    60. 事件委托

    将事件处理程序附加到父元素,以处理其子元素的事件;利用事件流中冒泡的机制,将点击事件委托给父元素,这种处理方案被称之为事件委托(代理)

    在这里插入图片描述

    将点击事件监听器添加到了父元素 button-container 上。当任何子元素(按钮)被点击时,事件将冒泡到父元素,然后我们检查被点击的元素是否拥有特定的类名(dynamic-button),以此来判断是否点击了按钮。如果是按钮,则可以执行相关的处理逻辑。

    这种方法可以帮助你避免为每个按钮都单独添加事件监听器,从而提高了代码的效率和可维护性。

    event.target
    触发事件的元素,被点击的具体元素,当可以发生变化

    event.currentTarget
    绑定事件的元素,
    如document.body.onclick = xxx,就永远是document.body

  • 相关阅读:
    作为程序员,哪些技能是必须要掌握的?
    微波雷达感应模块技术,实时智能检测人体存在,静止微小动静感知
    弹性盒布局中的flex属性使用
    Vue 3 中如何迁移从 Vue 2 的项目?
    python使用execjs利用jsdom来执行含有document的js代码方案(上)
    NISP和CISP网络安全高级运维工程师需要掌握的应急响应有什么方向
    【Android -- 开发】一份详细的 Android 知识体系
    【SA8295P 源码分析 (一)】54 - /ifs/bin/startupmgr 程序工作流程分析 及 script.c 介绍
    jvm简介
    使用Docker搭建Redis主从集群
  • 原文地址:https://blog.csdn.net/qq_43472877/article/details/127047633