js面试---ES6

1、let、const、var的区别

        块级作用域:let和const具有块级作用域,var不存在块级作用域。块级作用域解决了内层变量可能覆盖外层变量,以及用来计数的循环变量泄露为全局变量的问题。

        变量提升:var存在变量提升,let和const不存在变量提升(只能在声明后使用,否则会报错)

        给全局添加属性:浏览器的全局对象是window,Node的全局对象是global。var声明的变量为全局变量,并且会将该变量添加为全局对象的属性,但let和const不会。

        重复声明:var可以重复声明变量,let和const不可以。

        暂时性死区:在使用let、const命令声明变量之前,该变量都是不可用的。这在语法上,称为暂时性死区。var声明变量,不存在暂时性死区。

        初始值设置:var和let在声明变量时可以不用设置初始值,const在声明变量时必须设置初始值。

        指针指向:let和const都是ES6新增语法,let创建的变量是可以更改指针指向的,而const声明的变量是不允许改变指针指向的。

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

        const保证的不是变量的值不能改变,而是变量指向的那个内存地址不能改动。对于基本数据类型的数据,其值就保存在变量指向的那个内存地址,因此等同于常量。

        但对于引用类型的数据,变量指向数据的内存地址,保存的是一个指针,const只能保证这个指针是固定不变的,至于它指向的数据结构是不是不可变的,就完全不能控制了。

3、可以new一个箭头函数吗

        箭头函数没有自己的prototype,也没有自己的this指向,不能使用arguments参数,所以不能new一个箭头函数。

        new操作符的实现步骤:

                a、创建一个对象

                b、将构造函数的作用域赋给新对象(即将对象的__proto__属性指向构造函数的prototype属性)

                c、指向构造函数中的内容,构造函数中的this指向该对象(即为这个对象添加属性的方法)

                d、返回新对象

        箭头函数无法执行第2、3步。

4、箭头函数与普通函数的区别

        a、箭头函数比普通函数更简洁:如果不需要参数,一个空括号即可;如果只有一个参数,可以省略括号;如果有多个参数,用逗号分隔;如果函数体的返回值只有一句话,可以省略大括号;如果函数体不需要返回值,且只有一句话,在关键句前加一个void关键字即可。

let fn = () => void doesNotReturn();

        b、箭头函数没有自己的this:箭头函数在自己作用域的上一层继承this,所以箭头函数中this的指向在它定义时已经确定了,后续不会改变。

        c、 call()、apply()、bind()等方法不能改变箭头函数的this的指向

        d、箭头函数不能作为构造函数使用

        e、箭头函数没有自己的arguments

        f、箭头函数没有prototype

        g、箭头函数不能用作Generator函数,不能用yield关键字

5、扩展运算符的作用及使用场景

        a、对象扩展运算符:用于取出参数对象中的所有可遍历属性,拷贝到当前对象中

        扩展运算符对对象实例的拷贝属于浅拷贝。

let bar = { a: 1, b: 2 };
let baz = { ...bar }; // { a: 1, b: 2 }

        如果用户自定义的属性,放在 扩展运算符后面,则后面的属性会覆盖前面的属性。

let bar = {a: 1, b: 2};
let baz = {...bar, ...{a:2, b: 4}};  // {a: 2, b: 4}

        b、数组扩展运算符

        可以将数组转为用逗号分隔的参数序列,且每次只能展开一层数组。

console.log(...[1, 2, 3])
// 1 2 3
console.log(...[1, [2, 3, 4], 5])
// 1 [2, 3, 4] 5

        将数组转换为参数序列:

function add(x, y) {
  return x + y;
}
const numbers = [1, 2];
add(...numbers) // 3

        复制数组:

const arr1 = [1, 2];
const arr2 = [...arr1];  // [1, 2]

        合并数组:

const arr1 = ['two', 'three'];
const arr2 = ['one', ...arr1, 'four', 'five'];  // ["one", "two", "three", "four", "five"]

        与结构复制结合起来生成数组:

const [first, ...rest] = [1, 2, 3, 4, 5];
first // 1
rest  // [2, 3, 4, 5]

        如果将扩展运算符用于数组赋值,只能放在参数的最后一位,否则会报错。 

        将字符串转换为数组:

[...'hello']    // [ "h", "e", "l", "l", "o" ]

        使用Math函数获取数组中的特定值:

const numbers = [9, 4, 7, 1];
Math.min(...numbers); // 1
Math.max(...numbers); // 9

6、 Proxy可以实现什么功能

        在vue3中,使用Proxy替换Object.defineProperty来实现数据响应式。

        Proxy是ES6新增功能,可以用来自定义对象中的操作。

let p = new Proxy(target, handler)

        target代表要添加代理的对象,handler用来自定义对象中的操作。

        以下是一个简单的例子: 

let onWatch = (obj, setBind, getLogger) => {
  let handler = {
    get(target, property, receiver) {
      getLogger(target, property)
      return Reflect.get(target, property, receiver)
    },
    set(target, property, value, receiver) {
      setBind(value, property)
      return Reflect.set(target, property, value)
    }
  }
  return new Proxy(obj, handler)
}
let obj = { a: 1 }
let p = onWatch(
  obj,
  (v, property) => {
    console.log(`监听到属性${property}改变为${v}`)
  },
  (target, property) => {
    console.log(`'${property}' = ${target[property]}`)
  }
)
p.a = 2 // 监听到属性a改变
p.a // 'a' = 2

 7、如何提取高度嵌套的对象里的指定属性

const school = {
   classes: {
      stu: {
         name: 'Bob',
         age: 24,
      }
   }
}

        方法一:逐层解构

const { classes } = school
const { stu } = classes
const { name } = stu
name // 'Bob'

        方法二:嵌套解构

const { classes: { stu: { name } }} = school
       
console.log(name)  // 'Bob'

        在解构出来的变量名右侧,通过冒号+{目标属性名}这种形式,进一步解构它,一直解构到拿到目标数据为止。

8、对...参数的理解

        扩展运算符被用在函数形参上时,可以把一个分离的参数序列整合成一个数组:

function mutiple(...args) {
  let result = 1;
  for (var val of args) {
    result *= val;
  }
  return result;
}
mutiple(1, 2, 3, 4) // 24

        传入 mutiple 的是四个分离的参数,但是如果在 mutiple 函数里尝试输出 args 的值,会发现它是一个数组。 

function mutiple(...args) {
  console.log(args)
}
mutiple(1, 2, 3, 4) // [1, 2, 3, 4]

        除解构等外,还可以把函数的多个入参收敛进一个数组里。这一点经常用于获取函数的多余参数,或者像上面这样处理函数参数个数不确定的情况。

9、ES6中模板语法

         模板语法使字符串的拼接变得更加简单:

var name = 'css'   
var career = 'coder' 
var hobby = ['coding', 'writing']
var finalString = `my name is ${name}, I work as a ${career} I love ${hobby[0]} and ${hobby[1]}`

        模板字符串允许用${}的方式嵌入变量,使字符串的拼接更加简单、易读。模板字符串中,空格、缩进、换行都会被保留;且还可以在${}在进行一些简单的计算。

function add(a, b) {
  const finalString = `${a} + ${b} = ${a+b}`
  console.log(finalString)
}
add(1, 2) // 输出 '1 + 2 = 3'

10、ES6中的字符串处理方法

        存在性判定:includes、startsWith、endsWith

        includes:判断字符串与子串的包含关系

const son = 'haha' 
const father = 'xixi haha hehe'
father.includes(son) // true

         startsWith:判断字符串是否以某个字符开头

const father = 'xixi haha hehe'
father.startsWith('haha') // false
father.startsWith('xixi') // true

         endsWith:判断字符串是否以某个字符结尾

const father = 'xixi haha hehe'
father.endsWith('hehe') // true

        自动重复:可以使用repeat方法来使同一个字符串输出多次(被连续复制多次)

const sourceCode = 'repeat for 3 times;'
const repeated = sourceCode.repeat(3) 
console.log(repeated) // repeat for 3 times;repeat for 3 times;repeat for 3 times;
上一篇:CSS基础之伪元素选择器(如果想知道CSS的伪元素选择器知识点,那么只看这一篇就足够了!)


下一篇:基础 IO (Linux学习笔记)