(ES6)前端八股文修炼Day2

1. let const var 的区别

  • var:

var 是在 ES5 中引入的声明变量的关键字。

具有函数作用域,而不是块作用域,这意味着使用 var 声明的变量在函数内部是可见的。

变量可以被重复声明,而且变量的值可以在声明前使用,这可能会导致一些意外的行为。

使用 var声明的变量可以被提升(hoisted),即变量的声明会被提升到作用域的顶部。

  • let:

let 是在 ES6(ES2015)中引入的声明变量的关键字。

具有块级作用域,只在声明它的块(如 {})内部有效,不会污染外部作用域。

变量不能被重复声明,如果尝试重复声明会导致语法错误。

let 声明的变量不会被提升,不存在变量提升的情况。

  • const:

const 也是在 ES6 中引入的声明变量的关键字。

具有块级作用域,类似于 let,不能重复声明,不存在变量提升。

声明一个常量,值在声明后不能被修改。

声明时必须进行初始化,而且初始化后就不能再修改常量的值。

  • 示例比较:
javascript 复制代码
var x = 10;
if (true) {
    var x = 20;
    console.log(x); // 输出: 20
}
console.log(x); // 输出: 20

// 使用 let
let y = 10;
if (true) {
    let y = 20;
    console.log(y); // 输出: 20
}
console.log(y); // 输出: 10

// 使用 const
const z = 10;
// z = 20; // 会导致错误,常量值无法修改

在实际开发中,推荐优先使用 const,除非变量的值需要被修改才使用 let。避免使用 var,因为它存在一些不利于代码维护和调试的特性。希望这个解释对你有帮助!如果有任何其他问题,请随时告诉我。

2.const 对象的属性可以修改吗?

在 JavaScript 中,使用 const 声明的变量是常量,这意味着变量的引用不可变,但并不意味着变量所引用的对象是不可变的。对于对象(包括数组)来说,使用 const 声明的变量可以修改对象的属性,但不能重新赋值一个新的对象给这个变量。

下面是一个示例来说明这一点:

javascript 复制代码
const person = {
    name: 'Alice',
    age: 30
};

// 修改对象属性是允许的
person.age = 31;
console.log(person); // 输出: { name: 'Alice', age: 31 }
// 重新赋值一个新对象会导致错误
// person = { name: 'Bob', age: 25 }; // 这行会导致错误

在上面的示例中,虽然 person 是用 const 声明的,我们仍然可以修改 person 对象的属性,如更改 age 的值。但是,尝试将一个新对象赋值给 person 会导致错误,因为常量变量的引用是不可变的。

3.new一个箭头函数的会怎么样?箭头函数与普通函数的区别?箭头函数的this指向哪⾥?

在 JavaScript 中,箭头函数和普通函数有一些重要的区别,其中包括在使用 new 关键字时的行为以及 this 的指向:

  1. 使用 new 关键字:

    • 普通函数可以使用 new 关键字来创建一个新的对象实例,这时候函数内部的 this 会指向新创建的实例。
    • 箭头函数不能用 new 关键字来创建实例,因为箭头函数没有自己的 this,它会继承外层作用域的 this
  2. 箭头函数与普通函数的区别:

    • 箭头函数没有自己的 thisargumentssupernew.target,它们都由外围最近一层非箭头函数决定。
    • 箭头函数不能用作构造函数,不能使用 new 关键字。
    • 箭头函数没有原型(prototype)属性。
  3. 箭头函数的 this 指向:

    • 箭头函数的 this 指向在函数定义时确定,取决于箭头函数外围作用域的 this
    • 普通函数的 this 则在函数被调用时才确定,取决于函数的调用方式(比如作为方法调用、函数调用、构造函数调用等)。

下面是一个示例来说明箭头函数的 this 指向和普通函数的区别:

javascript 复制代码
function NormalFunction() {
    this.value = 42;
    setTimeout(function() {
        console.log(this.value); // 输出 undefined,普通函数的 this 指向全局对象或 undefined
    }, 1000);
}

const ArrowFunction = () => {
    this.value = 42;
    setTimeout(() => {
        console.log(this.value); // 输出 42,箭头函数的 this 指向外围作用域的 this
    }, 1000);
};

new NormalFunction(); // 输出 undefined
new ArrowFunction(); // 输出 42

在上面的示例中,setTimeout 内部的箭头函数能够访问到外围作用域的 this,而普通函数的 this 则不同,因为普通函数内部的 this 取决于调用方式。

4. 扩展运算符的作用及使用场景

扩展运算符(Spread Operator)是 ES6 中引入的一个功能强大的语法,用三个点(...)表示。它可以将一个可迭代对象(比如数组、对象等)拆分为独立的元素,或将多个参数展开为单独的参数。扩展运算符的作用和使用场景有以下几个方面:

  1. 在数组中的使用:

    • 将数组展开为独立的元素:

      javascript 复制代码
      const arr1 = [1, 2, 3];
      const arr2 = [4, 5, ...arr1, 6, 7];
      console.log(arr2); // 输出: [4, 5, 1, 2, 3, 6, 7]
    • 复制数组:

      javascript 复制代码
      const originalArray = [1, 2, 3];
      const copyArray = [...originalArray];
    • 合并数组:

      javascript 复制代码
      const arr1 = [1, 2];
      const arr2 = [3, 4];
      const combinedArray = [...arr1, ...arr2];
  2. 在函数调用中的使用:

    • 将数组作为参数传递给函数:

      javascript 复制代码
      const numbers = [1, 2, 3];
      function sum(a, b, c) {
          return a + b + c;
      }
      console.log(sum(...numbers)); // 输出: 6
  3. 在对象中的使用:

    • 浅拷贝对象:

      javascript 复制代码
      const obj1 = { a: 1, b: 2 };
      const obj2 = { ...obj1 }; // 浅拷贝 obj1 到 obj2
    • 合并对象:

      javascript 复制代码
      const obj1 = { a: 1 };
      const obj2 = { b: 2 };
      const mergedObj = { ...obj1, ...obj2 };
  4. 在函数参数中的使用:

    • 用于传递不定数量的参数:

      javascript 复制代码
      function sum(...args) {
          return args.reduce((acc, val) => acc + val, 0);
      }
      console.log(sum(1, 2, 3)); // 输出: 6

扩展运算符为 JavaScript 的数据处理提供了更灵活和方便的方式,可以简化代码并提高可读性。它在处理数组、对象、函数参数等方面都有很好的应用场景。希望这个解释对你有帮助!如果有任何其他问题,请随时告诉我。

5. Proxy

Proxy 是 ES6 中引入的一个非常强大且灵活的功能,它可以用来拦截并定义对象上的基本操作,从而可以实现各种功能,例如:

  1. 属性访问控制 :通过 getset 拦截器,可以控制对对象属性的访问和赋值操作,实现属性的隐藏、验证等功能。

  2. 函数调用控制 :通过 apply 拦截器,可以控制对函数的调用操作,可以在函数调用前后执行额外逻辑。

  3. 数组操作的控制 :可以通过拦截数组的操作,例如 pushpopsplice 等,实现对数组的监控、验证等功能。

  4. 动态扩展属性 :可以通过 get 拦截器动态生成属性,实现虚拟属性或计算属性。

  5. 数据验证 :可以在 set 拦截器中对属性值进行验证,确保数据的合法性。

  6. 数据绑定:可以实现数据的双向绑定,当对象数据发生变化时自动更新相关内容。

  7. 缓存 :可以利用 Proxy 实现缓存功能,避免重复计算,提高程序性能。

  8. 日志记录:可以在拦截器中记录对象操作的历史,用于调试和监控。

  9. 实现观察者模式:可以在属性访问和赋值时触发相应操作,实现观察者模式。

  10. 实现权限控制:可以根据需要拦截对象的操作,实现权限控制和安全性增强。

总的来说,Proxy 提供了一种对对象进行拦截和自定义操作的机制,可以实现很多复杂的功能和行为定制。

下面我将简要介绍 Proxy 如何实现观察者模式:

  1. 创建观察者模式的实现:

    • 首先,需要创建一个被观察者对象和一个存储观察者的数组。

    • 使用 Proxy 对被观察者对象进行封装,设置一个 observers 数组来存储观察者。

    • 通过 set 拦截器,在被观察者对象的属性发生变化时,通知所有观察者。

  2. 示例代码:

    javascript 复制代码
    // 创建一个被观察者对象
    const subject = new Proxy({ value: 0, observers: [] }, {
        set(target, key, value, receiver) {
            const result = Reflect.set(target, key, value, receiver);
            if (key === 'value') {
                target.observers.forEach(observer => observer());
            }
            return result;
        }
    });
    
    // 创建观察者
    const observer1 = () => console.log('Observer 1 updated: ', subject.value);
    const observer2 = () => console.log('Observer 2 updated: ', subject.value);
    
    // 添加观察者
    subject.observers.push(observer1, observer2);
    
    // 修改被观察者的值,触发通知
    subject.value = 1; // Observer 1 updated: 1, Observer 2 updated: 1

在上面的示例中,我们创建了一个简单的观察者模式,使用 Proxy 对被观察者对象进行拦截,在属性值发生变化时通知所有观察者。这样,观察者模式就得以实现。

6.提取高度嵌套对象里的指定属性

要提取高度嵌套对象里的指定属性,可以使用递归和对象解构来实现。下面是一个示例,演示如何提取高度嵌套对象中的指定属性:

javascript 复制代码
// 定义一个高度嵌套的对象
const nestedObject = {
    level1: {
        level2: {
            level3: {
                key: 'value'
            }
        }
    }
};

// 递归函数用于提取指定属性
const extractPropertyValue = (obj, property) => {
    for (let key in obj) {
        if (key === property) {
            return obj[key];
        } else if (typeof obj[key] === 'object') {
            return extractPropertyValue(obj[key], property);
        }
    }
};

// 指定要提取的属性名
const propertyToExtract = 'key';

// 提取指定属性值
const extractedValue = extractPropertyValue(nestedObject, propertyToExtract);
console.log(extractedValue); // 输出: 'value'

在上面的示例中,我们定义了一个高度嵌套的对象 nestedObject,然后编写了一个递归函数 extractPropertyValue,该函数接收一个对象和要提取的属性名,在对象中查找指定属性,并返回其值。通过调用这个函数,我们成功提取了高度嵌套对象中的指定属性值。

这种方法可以应用于任意层级的嵌套对象,通过递归地遍历对象的属性,找到目标属性并返回其值。

7.对对象与数组的解构的理解

对象和数组的解构是 JavaScript 中一种强大且方便的语法,用于快速提取数组或对象中的值并赋给变量,以便后续使用。下面我将简要介绍对象解构和数组解构的基本概念:

对象解构:
  • 基本语法: 使用花括号 {} 来指定要提取的对象属性,并将属性值赋给相应的变量。

    javascript 复制代码
    const person = { name: 'Alice', age: 30 };
    const { name, age } = person;
    console.log(name); // 输出: 'Alice'
    console.log(age); // 输出: 30
  • 给变量起别名: 可以使用冒号 : 为提取的属性值指定变量名。

    javascript 复制代码
    const { name: personName, age: personAge } = person;
    console.log(personName); // 输出: 'Alice'
    console.log(personAge); // 输出: 30
数组解构:
  • 基本语法: 使用方括号 [] 来指定要提取的数组元素,并将值赋给相应的变量。

    javascript 复制代码
    const numbers = [1, 2, 3];
    const [first, second, third] = numbers;
    console.log(first); // 输出: 1
    console.log(second); // 输出: 2
  • 忽略某些元素: 可以使用逗号 , 来跳过不需要的数组元素。

    javascript 复制代码
    const [,, third] = numbers;
    console.log(third); // 输出: 3

对象和数组解构可以简化代码,提高可读性,并且方便地从复杂的数据结构中提取所需的值。当结合递归和其他技术时,对象和数组解构可以变得非常强大。

8.Rest参数

Rest 参数是 ES6 中引入的一个新特性,用于捕获函数参数中的剩余参数,将其表示为一个数组。这样可以处理不定数量的参数,而不需要显式地定义参数个数。下面是关于 rest 参数的一些基本概念和示例:

Rest 参数的基本语法
  • 在函数定义时,使用三个点号 ... 加上一个参数名来表示 rest 参数,通常放在参数列表的最后。
javascript 复制代码
function sum(...numbers) {
    return numbers.reduce((acc, curr) => acc + curr, 0);
}

console.log(sum(1, 2, 3, 4, 5)); // 输出: 15

在这个示例中,...numbers 表示将所有传入函数的参数作为一个数组 numbers 来存储。

Rest 参数的应用场景:
  • 处理不定数量的参数: Rest 参数允许函数接受任意数量的参数,无需提前定义参数个数。
javascript 复制代码
function multiply(multiplier, ...numbers) {
    return numbers.map(num => num * multiplier);
}

console.log(multiply(2, 1, 2, 3, 4)); // 输出: [2, 4, 6, 8]
  • 替代 arguments 对象: Rest 参数可以替代传统的 arguments 对象,更直观地操作参数。
javascript 复制代码
function logArguments(...args) {
    console.log(args);
}

logArguments('a', 'b', 'c'); // 输出: ['a', 'b', 'c']

Rest 参数通常用于函数定义中,方便处理不定数量的参数,提高代码的灵活性和可读性。

9.对 rest 参数的理解ES6中模板语法与字符串处理

ES6 中的模板字符串是一种更灵活、更强大的字符串处理方式,可以在字符串中插入变量、表达式,并支持多行字符串的定义。下面我将介绍 ES6 中模板字符串的基本语法和常见用法:

模板字符串的基本语法:

  • 使用反引号 ``(通常位于键盘左上角,与波浪符号~同一个键)来定义模板字符串。
javascript 复制代码
const name = 'Alice';
const greeting = `Hello, ${name}!`;
console.log(greeting); // 输出: 'Hello, Alice!'
  • 在模板字符串中,使用 ${} 来插入变量或表达式,可以是任意有效的 JavaScript 表达式。

多行字符串的定义:

  • 模板字符串可以跨越多行,而无需使用 \n 换行符。
javascript 复制代码
const multiLine = `
    This is a
    multi-line
    string.
`;
console.log(multiLine);
// 输出:
//     This is a
//     multi-line
//     string.

标签模板字符串:

  • 可以使用标签函数对模板字符串进行处理,这种技术称为标签模板字符串。
javascript 复制代码
function customTag(strings, ...values) {
    console.log(strings);
    console.log(values);
}

const value1 = 10;
const value2 = 20;
customTag`The values are: ${value1} and ${value2}`;
// 输出:
//     ["The values are: ", " and ", ""]
//     [10, 20]

模板字符串提供了一种更简洁、更直观的方式来处理字符串内容,特别是在需要插入变量或多行文本时非常有用。标签模板字符串则扩展了这一概念,允许自定义对模板字符串的处理方式。

相关推荐
musk12126 分钟前
electron 打包太大 试试 tauri , tauri 安装打包demo
前端·electron·tauri
翻滚吧键盘35 分钟前
js代码09
开发语言·javascript·ecmascript
万少1 小时前
第五款 HarmonyOS 上架作品 奇趣故事匣 来了
前端·harmonyos·客户端
OpenGL1 小时前
Android targetSdkVersion升级至35(Android15)相关问题
前端
rzl021 小时前
java web5(黑马)
java·开发语言·前端
Amy.Wang1 小时前
前端如何实现电子签名
前端·javascript·html5
今天又在摸鱼2 小时前
Vue3-组件化-Vue核心思想之一
前端·javascript·vue.js
蓝婷儿2 小时前
每天一个前端小知识 Day 21 - 浏览器兼容性与 Polyfill 策略
前端
百锦再2 小时前
Vue中对象赋值问题:对象引用被保留,仅部分属性被覆盖
前端·javascript·vue.js·vue·web·reactive·ref
jingling5552 小时前
面试版-前端开发核心知识
开发语言·前端·javascript·vue.js·面试·前端框架