2022-06-26 前端vue面试题1

# v-if和v-show的区别:

v-if是操作DOM元素,v-show是不操作DOM元素,控制css中样式的显示和隐藏。

v-if的切换消耗大,v-show的初始化消耗大。

v-for为什么不能和v-if同时使用:

v-for的优先级比v-if的优先级高,如果在同一元素上,渲染时,消耗性能,先循环再判断,

如果要避免的话,先在外层套一个template,进行v-if判断,在内部用v-for

如果条件在循环内的话,可用计算属性compted提前过滤出不逊要显示的项目。

# v-for中的key有什么用:

用来更高效的对比虚拟DOM的节点是否相同。

提高渲染效率,如果一个虚拟DOM元素的节点发生变化,不用重新渲染所有DOM,就渲染改变的

DOM元素。

#watch和compated的区别:

watch是对数据data的监听,compated是对数据的计算,都是根据数据的变化来显示,

一般compated能做到的,watch也可以做到,compated有缓存

watch可以监听异步操作,高消耗,watch有deep,和immedate两种监听方式。

#map和forEach的区别:

map返回一个新数组,支持return,forEach不返回新数组,不支持return。

forEach举例:

var array = [10,34,57,43,76]; 

var res = array.forEach(function (item,index,input) { 

      input[index] = item*10; 

}) 

console.log(res);//--> undefined; 

console.log(array);//--> 通过数组索引改变了原数组;

[100,340,570,430,760]

map举例:

var array = [10,34,57,43,76]; 

var res = array.map(function (item,index,input) { 

      return item*10; 

}) 

console.log(res);

console.log(array);不变

each举例:不支持return

$.each(arr,function(index,value){

  xxxx

})

$.each( ["a","b","c"], function(i, v){ 

    alert( i + ": " + v ); 

}); 

#module语法:import和export:

#promise对象aynsc和awiti

promise是一个对象,可以用来传递异步任务的消息。我们知道异步任务的执行时间和执行结果是无法预测的,但是在实际项目中我们想要在异步任务执行之前,就根据不同的执行结果做出相应的处理。所以这时候就需要Promise这个用于获取异步任务消息的对象。

使用场景:

处理异步任务。因为JS是单线程的,使用Promise可以将异步任务以同步的方式展现出来,避免了层层的回调函数。

Promise对象特点:

Promise对象三种状态:

Pending(进行中)、resolved(已完成)、Reject(已失败)。

只有异步任务的结果能唯一确定promise对象的状态。

并且,一旦状态改变了之后,就固定了,任何的操作都无法改变当前状态。

promise的构造函数接受一个函数作为参数。函数的两个参数分别是函数resolve和函数reject。

如果异步任务成功就用resolve方法将promise的状态从pending改为resolved,如果异步任务失败,就用reject改变Promise的状态,从pending改为rejected。

newPromise(resolve,reject)=>{resolve();reject();}

// 一个Promise实例constp=newPromise((resolve,reject)=>{// do somethingif(success){resolve(results)}else{reject(err);}}).then((results)=>{console.log(results);}).catch((err)=>{console.log(err);})

上图是一个Promise实例。P是生成的Promise实例,一般字promise构造函数的内部会包裹一个异步函数。当实例生成之后,可以用then方法分别指定异步函数成功或者失败的时候的回调函数。results就是异步任务成功时候的返回的结果,一般then的回调函数包括两个,第一个是resolve时候的回调函数,第二个是reject时候的回调函数,第二个参数可以省略。

Promise的方法:

p.then((results)={},(err)=>{});

注意Promise新建之后会立刻执行,而then方法会在当前脚本所有同步任务执行完之后才会开始执行。

我来仔细剥离一下这个上面的pro1;

最外层 const pro1 = ()=>{} 可以看出pro1是一个函数。

然后pro1这个函数的返回值是一个Promise对象。

这个promise对象是通过构造函数构造的,他的构造函数参数是一个函数,这个函数是:

(reject,resolve)=>{setTimeout(()=>{console.log('执行异步任务1');resolve('异步任务1执行成功');},2000);}*/// 一般这个函数内部都会包裹一个异步任务    }

promise.all

异步函数(async/await)

用async包裹一个函数,可以把这个函数变成一个异步函数。但是也只是让这个函数具有异步特性,执行上还是同步执行的。

let fun1 = async ()=>{}

async函数的返回值

是一个Promise对象

asyncfunctionfoo(){console.log(1);return3;// 等价于return Promise.resolve(3);}foo().then(console.log);console.log(2);// result: 1 2 3

await

使用await可以暂停异步函数代码的执行。  await只能在async中使用 。

await和async一起使用的时候,起作用的其实只有await,因为只有async的话,他的执行和普通函数没有什么区别

async()=>{// do aawaitP// do b}

以上代码的执行顺序是,进入异步函数之后执行do a 遇到await则暂停异步任务的执行,等待await右侧的p执行完毕之后,恢复异步任务的执行,执行do b。一般情况下这个P是一个Promise

asyncfunctionfoo(){console.log(2);console.log(awaitPromise.resolve(8));console.log(9);}asyncfunctionbar(){console.log(4);console.log(await6);console.log(7);}console.log(1);foo();console.log(3);bar();console.log(5);// result 1 2 3 4 5 6 7 8 9

8个生命周期

beforecreate ,created,beforemount mounted(真实的DOM挂在完成,数据完成素箱数据绑定,可以访问到Dom节点),beforeupdate(数据更新),update(Dom更新),beforedestory,destoryed

vue组件通信

父->子间通信props 子->父通信$emit

兄弟间通信Bus实现跨组件之间通信

vuex是一种状态管理系统

State--this.$store.state.xxx 取值

Getter--this.$store.getter.xxx 取值

Mutation--this.$store.commit("xxx") 赋值

Action--this.$store.dispatch("xxx") 赋值

Module


#set和map的数据结构:

、Set数据结构

1、ES6提供了新的数据类型Set。它类似于数组,但是成员的值都是唯一的,没有重复的值

2、Set的实例

Set本身是一个构造函数,用来生成Set数据结构,Set函数接受一个数组或者具有iterable接口的其他数据结构作为参数,用来初始化

const set = new Set([1,2,3,4,4])

console.log(set);//Set(4) { 1, 2, 3, 4 }

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

const s1 = new Set('hello')

console.log(s1);//Set(4) { 'h', 'e', 'l', 'o' }

console.log([...s1]);//[ 'h', 'e', 'l', 'o' ]

3、Set的用途

// 数组去重

console.log([...new Set([1,2,1,2,2,5,3,2])]);

//[1,2,5,3]

//数组去重的另一种方法

function dedupe(array) {

    return Array.from(new Set(array))

}

console.log(dedupe([1,1,2,2,3,3]));//[1,2,3]

// 字符串去重

console.log([...new Set('helloe')].join(''));

//'helo'

4、Set实例的属性

(1) size 返回实例的成员总数

let s = new Set([1,2,3,4,5])

console.log(s.size);//5

(2)constructor 返回构造函数

let s = new Set([1,2,3,4,5])

console.log(s.constructor);

//[Function: Set]相当于Set()

5、Set实例的操作方法

let s = new Set([1,2,3,4,5])

//1、add(value),添加某个值,返回实例本身

console.log(s.add('a'));//Set(6) { 1, 2, 3, 4, 5, 'a' }

//2、delete(value),删除某个值,返回布尔值,表示删除是否成功

console.log(s.delete(2));//true

//3、has(value),检测该值是否是实例的成员,返回布尔值

console.log(s.has(4));//true

//4、clear(),清空所有成员,没有返回值

s.clear()

console.log(s);//Set(0) {}

6、 Set实例的遍历方法

由于 Set 结构没有键名,只有键值(或者说键名和键值是同一个值),所以keys方法和values方法的行为完全一致。

let s = new Set([1,2,3,4,5])

//1、keys()    返回键名的遍历器

console.log(s.keys());//[Set Iterator] { 1, 2, 3, 4, 5 }

for(let i of s.keys()){

    console.log(i);//1 2 3 4 5

}

//2、values()      返回键值的遍历器

for(let i of s.values()){

    console.log(i);//1 2 3 4 5

}

//3、entries()    返回键值对的遍历器

for (const i of s.entries()) {

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

}

//4、forEach()    遍历Set实例,和数组用法一样

s.forEach((val,index,s)=>console.log(val+'---'+index+'---'+s))

1---1---[object Set]

2---2---[object Set]

3---3---[object Set]

4---4---[object Set]

5---5---[object Set]

二、Map数据结构

ES6提供了Map数据结构。它类似于对象,也是键值对的集合,但是“键”的范围不限于字符串,各种类型的值都可以当作键。Object结构提供了“字符串—值的对应”,Map结构提供了“值—值的对应”

1、创建Map的实例

Map构造函数接受一个数组作为参数,这个数组的元素是一个一个表示键值对的数组

const map = new Map([['name','lisi'],['age',23]])

console.log(map);

//Map(2) { 'name' => 'lisi', 'age' => 23 }

2、Map结构实例的属性

const map = new Map([['name','lisi'],['age',23]])

//1、size    返回实例的成员总数

console.log(map.size);//2

//2、constructor  返回Map构造函数

console.log(map.constructor);//[Function: Map]相当于Map(、 Map结构实例的操作方法

const map = new Map([['name','lisi'],['age',23]])

//1、set(key,value)    给实例添加键值对,返回实例本身,如果键已经存在,对应的键值将被修改

console.log(map.set('height',70));

//Map(3) { 'name' => 'lisi', 'age' => 23, 'height' => 70 }

//2、get(key)  获取key对应的键值,如果找不到key,返回undedined

console.log(map.get('age'));//23

//3、has(key),检测某个键是否存在,返回布尔值

console.log(map.has('age'));//true

//4、delete(key)  删除某个键,返回布尔值

console.log(map.delete('age'));//true

//5、clear() 清除所有成员,没有返回值

map.clear()

console.log(map);

Map(0) {}

4、Map实例的遍历方法

const map = new Map([['name','lisi'],['age',23]])

// 1、keys()    返回键名的遍历器

for(let i of map.keys()){

    console.log(i);

    // name age

}

// 2、values()      返回键值的遍历器

for(let i of map.values()){

    console.log(i);

    // lisi 23

}

// 3、entries()    返回键值对的遍历器

for(let i of map.entries()){

    console.log(i);

    // [ 'name', 'lisi' ]  [ 'age', 23 ]

}

// 4、forEach()    遍历所有成员

map.forEach((value,index,map)=>console.log(value + '---' + index + '---' + map))

// lisi---name---[object Map]  23---age---[object Map]

js中的遍历:

for 循环

普通的for循环,也是最常用到的

for(let i = 0;i

console.log(arr[i]);

}

for in

for in 循环 用于遍历对象的属性

如果用其来遍历数组 key值则为下标

let obj = {

    age: 18, name: "Joker", sayHello() {

        console.log("Hello")

    }

};

for (let key in obj) {

    console.log(`key:${key},value:${obj[key]}`);

}

for of

for of 语句循环遍历可迭代对象的值。such as:数组,字符串,节点列表…

for (let item of arr) {

console.log(item)

}

forEach

ES5数组自带的循环,主要是用来遍历数组,性能比for循环还弱

arr.forEach((item,index,arr)=>{

console.log(`key:${index},value:${item}`)

})

map

用法与forEach类同,但参数中的函数支持返回值

返回值是一个新的数组,其每项就是参数中的函数返回的值

arr.map((value, index, array) => {

return value === 123;

});

filter

用法与forEach类同,但参数中的函数支持返回值

返回值为一个新的数组,如果参数中的函数返回为真 则会将这一项push进新的数组当中,为假或没有返回,则不会

arr.filter((value, key) => {

return value === 123;//[]

return value.indexOf('o') !== -1;//['Joker', 'north']

})

includes

检测数组当中是不是存在某个元素

console.log(arr.includes('Joker'));//true

console.log(arr.includes('111'));//false

console.log(arr.includes('north'));//true

find

寻找第一个符合条件的元素

console.log(arr.find((value, key, arr) => {

    return value.indexOf('o') !== -1;

}));//Joker

findIndex

寻找第一个符合条件元素的索引

console.log(arr.findIndex((value, key, arr) => {

    return value.indexOf('o') !== -1;

}));//0

some

数组中是不是有值符合某个条件

所有值中有一个符合条件就不继续执行,返回true

console.log(arr.some((value, key, arr) => {

return value.indexOf('o') !== -1;

}));//true

every

数组中是不是所有值符合某个条件

所有值中有一个不符合条件就不继续执行,返回false

console.log(arr.every((value, key, arr) => {

return value.indexOf('o') !== -1;

}));//false

都是块级作用域,不支持变量提升,const一般是常量定义。

变量的解构赋值:

以前,为变量赋值,只能直接指定值。

let a = 1;

let b = 2;

let c = 3;

es6允许写法

let [ a, b, c ] = [ 1, 2, 3 ];

本质上,这种写法属于“模式匹配”,只要等号两边的模式相同,左边的变量就会被赋予对应的值。下面是一些使用嵌套数组进行解构的例子。

let [foo, [[bar], baz]] = [1,[[2], 3]]

let [foo, [[bar], baz]] = [1, [[2], 3]];

foo // 1

bar // 2

baz // 3

let [ , , third] = ["foo", "bar", "baz"];

third // "baz"

let [x, , y] = [1, 2, 3];

x // 1

y // 3

let [head, ...tail] = [1, 2, 3, 4];

head // 1

tail // [2, 3, 4]

let [x, y, ...z] = ['a'];

x // "a"

y // undefined

z // []

如果解构不成功,变量的值就等于undefined。

let [ foo ] = []

let [bar, foo] = [1];

另一种情况是不完全解构,即等号左边的模式,只匹配一部分的等号右边的数组。这种情况下,解构依然可以成功。

let [x, y] = [1, 2, 3];

x // 1

y // 2

let [a, [b], d] = [1, [2, 3], 4];

a // 1

b // 2

d // 4

如果等号的右边不是数组(或者严格地说,不是可遍历的结构,参见《Iterator》一章),那么将会报错。

// 报错

let [foo] = 1;

let [foo] = false;

let [foo] = NaN;

let [foo] = undefined;

let [foo] = null;

let [foo] = {};

上面的语句都会报错,因为等号右边的值,要么转为对象以后不具备 Iterator 接口(前五个表达式),要么本身就不具备 Iterator 接口(最后一个表达式)。

对于 Set 结构,也可以使用数组的解构赋值。

let [x, y, z] = new Set(['a', 'b', 'c']);

x // "a"

默认值

let [foo = true] = [];

foo // true

let [x, y = 'b'] = ['a']; // x='a', y='b'

let [x, y = 'b'] = ['a', undefined]; // x='a', y='b'

注意,ES6 内部使用严格相等运算符(===),判断一个位置是否有值。所以,只有当一个数组成员严格等于undefined,默认值才会生效。

let [x = 1] = [undefined];

x // 1

let [x = 1] = [null];

x // null

上面代码中,如果一个数组成员是null,默认值就不会生效,因为null不严格等于undefined。

如果默认值是一个表达式,那么这个表达式是惰性求值的,即只有在用到的时候,才会求值。

function f() {

  console.log('aaa');

}

let [x = f()] = [1];

x = 1; 而 函数f 没有去执行

上面的代码中,因为X能取到值,所以函数f根本不会执行,上面的代码其实等价于下面的代码

let x;

if ([1][0] === undefined) {

  x = f();

} else {

  x = [1][0];

}

默认值可以引用解构赋值的其他变量,但该变量必须已经声明。

let [x = 1, y = x] = [];    // x=1; y=1

let [x = 1, y = x] = [2];    // x=2; y=2

let [x = 1, y = x] = [1, 2]; // x=1; y=2

let [x = y, y = 1] = [];    // ReferenceError: y is not defined

上面最后一个表达式之所以会报错,是因为x用y做默认值时,y还没有声明。

对象的建构赋值

解构不仅可以用于数组,还可以用于对象。

let { foo, bar } = { foo: 'aaa', bar: 'bbb' };

foo // "aaa"

bar // "bbb"

对象的解构与数组有一个重要的不同。数组的元素是按次序排列的,变量的取值由它的位置决定;而对象的属性没有次序,变量必须与属性同名,才能取到正确的值。

let { bar, foo } = { foo: 'aaa', bar: 'bbb' };

foo // "aaa"

bar // "bbb"

let { baz } = { foo: 'aaa', bar: 'bbb' };

baz // undefined

如果解构失败,变量的值等于undefined。

对象的解构赋值,可以很方便地将现有对象的方法,赋值到某个变量。

let {log, sin, cos, PI }  = Math;

const { log } = console;

log('hello')

上面代码的例一将Math对象的对数、正弦、余弦三个方法,赋值到对应的变量上,使用起来就会方便很多。例二将console.log赋值到log变量。

如果变量名与属性名不一致,必须写成下面这样。

let { foo: a } = { foo: 'aaa' }

a // "aaa"

let obj = { first: 'hello', last: 'world' };

let { first: f, last: l } = obj;

f // 'hello'

l // 'world'

这实际上说明,对象的解构赋值是下面形式的简写(参见《对象的扩展》一章)。

let { foo: foo, bar: bar } = { foo: 'aaa', bar: 'bbb' };

也就是说,对象的结构赋值的内部机制,是先找同名属性,然后再赋值给对应的变量,真正赋值的是后者,而不是前者

let {foo : baz } = { foo: 'aaa', bar: 'bbb'}

console.log(baz) // aaa

console.log(foo)  error: foo is not defined

上面的代码中 foo 是匹配的模式, baz 才是变量, 真正被赋值的是baz,而不是模式 foo

与数组一样,解构也可以用于嵌套解构的对象

let obj = {

  p: [

    'Hello',

    { y: 'World' }

  ]

};

let { p: [x, { y }] } = obj;

x // "Hello"

y // "World"

注意,这时p是模式,不是变量,因此不会被赋值。如果p也要作为变量赋值,可以写成下面这样。

let obj = {

  p: [

    'Hello',

    { y: 'World' }

  ]

};

let { p: [x, { y }] } = obj;

x // "Hello"

y // "World"

注意 这里的p是模式,不是变量,因此不会被赋值,如果p也作为变量赋值,可以写成下面这样

let obj = {

p: [

'hello',

{ y: 'world' }

]

}

let { p, p: [ x, { y } ] } = obj;

x // hello

y //world

p // [ 'hello' , {y: 'wrold' } ]

下面一个例子

const node = {

  loc: {

    start: {

      line: 1,

      column: 5

    }

  }

};

let { loc, loc: { start }, loc: { start: { line }} } = node;

line // 1

loc  // Object {start: Object}

start // Object {line: 1, column: 5}

上面代码有三次解构赋值,分别是对loc、start、line三个属性的解构赋值。注意,最后一次对line属性的解构赋值之中,只有line是变量,loc和start都是模式,不是变量。

下面是嵌套赋值的例子

let obj = {};

let arr = [];

({ foo: obj.prop, bar: arr[0] } = { foo: 123, bar: true });

obj // {prop:123}

arr // [true]

如果解构模式是嵌套的对象,而且子对象所在的父属性不存在,那么将会报错。

// 报错

let {foo: {bar}} = {baz: 'baz'};

上面代码中,等号左边对象的foo属性,对应一个子对象。该子对象的bar属性,解构时会报错。原因很简单,因为foo这时等于undefined,再取子属性就会报错。

注意,对象的解构赋值可以取到继承的属性

const obj1 = {};

const obj2 = { foo: 'bar' };

Object.setPrototypeOf(obj1, obj2);

const { foo } = obj1;

foo // "bar"

默认值

var {x = 3} = {};

x // 3

var {x, y = 5} = {x: 1};

x // 1

y // 5

var {x: y = 3} = {};

y // 3

var {x: y = 3} = {x: 5};

y // 5

var { message: msg = 'Something went wrong' } = {};

msg // "Something went wrong"

默认值生效的条件是,对象的属性值严格等于undefined。

var {x = 3} = {x: undefined};

x // 3

var {x = 3} = {x: null};

x // null

上面代码中,属性x等于null,因为null与undefined不严格相等,所以是个有效的赋值,导致默认值3不会生效。

注意点

(1)如果要将一个已经声明的变量用于解构赋值,必须非常小心。

// 错误的写法

let x;

{x} = {x: 1};

// SyntaxError: syntax error

上面的代码写法错误 因为javascript 引擎会将 {x} 理解成一个代码块,从而发生语法错误,只有不将大括号写在行首,避免js将其解释为代码块,才能解决这个问题

let x;

({x} = { x: 11})

上面代码将整个解构赋值语句,放在一个圆括号里面,就可以正确执行。关于圆括号与解构赋值的关系,参见下文。

由于数组本质是特殊的对象,因此可以对数组进行对象属性的解构。

let arr = [1, 2, 3];

let {0 : first, [arr.length - 1] : last} = arr;

first // 1

last // 3

上面代码对数组进行对象解构。数组arr的0键对应的值是1,[arr.length - 1]就是2键,对应的值是3。方括号这种写法,属于“属性名表达式”(参见《对象的扩展》一章)。

字符串解构

字符串也可以解构赋值。这是因为此时,字符串被转换成了一个类似数组的对象。

const [a, b, c, d, e] = 'hello';

a // "h"

b // "e"

c // "l"

d // "l"

e // "o"

类似数组的对象都有一个length属性,因此还可以对这个属性解构赋值。

let {length : len} = 'hello';

len // 5

函数参数结构

function add([x, y]){

  return x + y;

}

add([1, 2]); // 3

上面代码中,函数add的参数表面上是一个数组,但在传入参数的那一刻,数组参数就被解构成变量x和y。对于函数内部的代码来说,它们能感受到的参数就是x和y。

下面是另一个例子

[[1, 2], [3, 4]].map(([a, b]) => a + b);

// [ 3, 7 ]

函数参数的解构也可以使用默认值

function move({x = 0, y = 0} = {}) {

  return [x, y];

}

move({x: 3, y: 8}); // [3, 8]

move({x: 3}); // [3, 0]

move({}); // [0, 0]

move(); // [0, 0]

上面代码中,函数move的参数是一个对象,通过对这个对象进行解构,得到变量x和y的值。如果解构失败,x和y等于默认值

function move({x, y} = { x: 0, y: 0 }) {

  return [x, y];

}

move({x: 3, y: 8}); // [3, 8]

move({x: 3}); // [3, undefined]

move({}); // [undefined, undefined]

move(); // [0, 0]

上面代码是为函数move的参数指定默认值,而不是为变量x和y指定默认值,所以会得到与前一种写法不同的结果。

undefined就会触发函数参数的默认值。

[1, undefined, 3].map((x = 'yes') => x);

// [ 1, 'yes', 3 ]

用途

交换变量的值

let x = 1;

let y = 2;

[x, y] = [y, x];

上面代码交换变量x和y的值,这样的写法不仅简洁,而且易读,语义非常清晰。

从函数返回多个值

函数只能返回一个值,如果要返回多个值,只能将它们放在数组或对象里返回。有了解构赋值,取出这些值就非常方便。

// 返回一个数组

function example() {

  return [1, 2, 3];

}

let [a, b, c] = example();

// 返回一个对象

function example() {

  return {

    foo: 1,

    bar: 2

  };

}

let { foo, bar } = example();

函数参数的定义

解构赋值可以方便地将一组参数与变量名对应起来。

// 参数是一组有次序的值

function f([x, y, z]) { ... }

f([1, 2, 3]);

// 参数是一组无次序的值

function f({x, y, z}) { ... }

f({z: 3, y: 2, x: 1});

提取 JSON 数据

解构赋值对提取 JSON 对象中的数据,尤其有用。

let jsonData = {

  id: 42,

  status: "OK",

  data: [867, 5309]

};

let { id, status, data: number } = jsonData;

console.log(id, status, number);

// 42, "OK", [867, 5309]

函数参数的默认值

jQuery.ajax = function (url, {

  async = true,

  beforeSend = function () {},

  cache = true,

  complete = function () {},

  crossDomain = false,

  global = true,

  // ... more config

} = {}) {

  // ... do stuff

};

遍历 Map 结构

任何部署了 Iterator 接口的对象,都可以用for...of循环遍历。Map 结构原生支持 Iterator 接口,配合变量的解构赋值,获取键名和键值就非常方便。

const map = new Map();

map.set('first', 'hello');

map.set('second', 'world');

for (let [key, value] of map) {

  console.log(key + " is " + value);

}

// first is hello

// second is world

如果只想获取键名,或者只想获取键值,可以写成下面这样。

// 获取键名

for (let [key] of map) {

  // ...

}

// 获取键值

for (let [,value] of map) {

  // ...

}

输入模块的指定方法

加载模块时,往往需要指定输入哪些方法。解构赋值使得输入语句非常清晰。

const { SourceMapConsumer, SourceNode } = require("source-map");

例子

  function move({x = 0, y = 1} = {}) {  // 默认赋值 x: 0, y: 1

    console.log([x, y])  //

  }

  move({ x:111 });  // [111, 1]

  move(); // [0, 1]

  move({}); // [0, 1]

function f({x, y} = {x: 0, y: 0}) { //

  console.log([x, y])

}

f();  // [0,0]

f({}); // [undefined, undefined]

你可能感兴趣的:(2022-06-26 前端vue面试题1)