前端面试记录2

vue中组件传参

在 Vue.js 中,组件之间的参数传递主要有两种方式:通过 Props通过事件。下面将详细介绍这两种方法以及其他一些相关概念。

1. 使用 Props 进行传参

Props 是父组件向子组件传递数据的主要方式。父组件可以在子组件的标签上定义属性,通过这些属性将数据传递给子组件。

示例代码

<!-- Parent.vue --> <template> <div> <h1>Parent Component</h1> <Child :message="parentMessage" /> </div> </template> <script> import Child from './Child.vue'; export default { components: { Child, }, data() { return { parentMessage: 'Hello from Parent', }; }, }; </script>

<!-- Child.vue --> <template> <div> <h2>Child Component</h2> <p>{{ message }}</p> <!-- 显示从父组件接收到的 props --> </div> </template> <script> export default { props: { message: { type: String, required: true, }, }, }; </script>

2. 使用自定义事件进行传参

当需要从子组件向父组件发送数据时,可以使用自定义事件。子组件使用 $emit 方法触发事件,父组件监听这个事件。

示例代码

<!-- Parent.vue --> <template> <div> <h1>Parent Component</h1> <Child @sendMessage="handleMessage" /> </div> </template> <script> import Child from './Child.vue'; export default { components: { Child, }, methods: { handleMessage(childMessage) { console.log('Received from child:', childMessage); }, }, }; </script>

<!-- Child.vue --> <template> <div> <h2>Child Component</h2> <button @click="sendMessage">Send Message to Parent</button> </div> </template> <script> export default { methods: { sendMessage() { const message = 'Hello from Child'; this.$emit('sendMessage', message); // 触发自定义事件并传递参数 }, }, }; </script>

3. 插槽(Slots)

Vue 还提供了插槽的机制,允许父组件向子组件传递内容(不仅限于数据)。这在构建可重用组件时非常有用。

示例代码

<!-- Parent.vue --> <template> <div> <h1>Parent Component</h1> <Child> <p>This is content passed from Parent</p> </Child> </div> </template> <script> import Child from './Child.vue'; export default { components: { Child, }, }; </script>

<!-- Child.vue --> <template> <div> <h2>Child Component</h2> <slot></slot> <!-- 渲染父组件传入的内容 --> </div> </template> <script> export default {}; </script>

总结

  • Props:用于从父组件向子组件传递数据。
  • 自定义事件:用于从子组件向父组件发送消息。
  • 插槽:用于在组件中插入来自父组件的内容。

选择合适的方法取决于你的具体需求。在 Vue 的单向数据流模型中,通常是父组件向子组件传递数据,而子组件通过事件向父组件发送消息。

箭头函数和普通函数

在 JavaScript 中,箭头函数(Arrow Function)和普通函数(Function Declaration / Function Expression)都是定义函数的方式,但它们之间存在一些关键的区别。以下是对这两种函数的详细比较:

1. 语法

普通函数
  • 函数声明

    function add(a, b) { return a + b; }
  • 函数表达式

    const add = function(a, b) { return a + b; };
箭头函数

const add = (a, b) => { return a + b; }; // 当只有一个参数时,可以省略括号 const square = x => x * x; // 如果函数体只有一行,可以省略大括号和 return const add = (a, b) => a + b;

2. this 的行为

  • 普通函数:在普通函数中,this 的值是动态的,取决于调用函数的上下文。

    function Person() { this.age = 0; setInterval(function() { this.age++; // `this` 指向全局对象,而不是 Person 实例 console.log(this.age); }, 1000); } const p = new Person(); // 输出: NaN
  • 箭头函数:箭头函数不绑定自己的 this,它会捕获外层上下文的 this 值,因此在使用箭头函数时,this 的值是静态的。

    function Person() { this.age = 0; setInterval(() => { this.age++; // `this` 指向 Person 实例 console.log(this.age); }, 1000); } const p = new Person(); // 正确输出: 1, 2, 3, ...

3. 使用场景

  • 普通函数

    • 当需要动态绑定 this
    • 在构造函数或方法中使用。
    • 需要使用 arguments 对象(普通函数有自己的 arguments 对象,但箭头函数没有)。
  • 箭头函数

    • 更简洁的语法,特别是在回调函数中。
    • 当你需要保持外层上下文的 this 时。
    • 用于简化函数表达式的书写。

4. 不能用作构造函数

  • 普通函数 可以用作构造函数:

    function Person(name) { this.name = name; } const alice = new Person('Alice');
  • 箭头函数 不能用作构造函数,会抛出错误:

    const Person = (name) => { this.name = name; // 错误: Cannot use 'new' with an arrow function }; const alice = new Person('Alice'); // TypeError: Person is not a constructor

5. 不能使用 yield

  • 箭头函数不能用作 Generator 函数:
    const genFunc = () => { yield 1; // 语法错误 };

总结

特性普通函数箭头函数
语法function()() => {}
this 绑定动态绑定静态绑定
是否可作为构造函数
arguments 对象没有
能否使用 yield可以不可以

根据具体的需求选择合适的函数形式,通常在需要更简洁、保持外部 this 时,使用箭头函数。在需要更复杂逻辑或者构造函数时,使用普通函数。

箭头函数可以作为钩子函数吗

在 Vue.js 中,钩子(Hooks) 是指某些特定的生命周期事件或功能,可以让开发者在组件的不同阶段执行代码。虽然通常我们使用普通函数来定义这些钩子,但实际上,箭头函数也可以用作钩子。不过,在使用箭头函数作为钩子时需特别小心,因为它们的 this 绑定和普通函数不同。

使用普通函数作为钩子

这是最常见的方式。Vue 的生命周期钩子如 mounted, created, updated 等通常使用普通函数来定义,以确保 this 指向当前组件实例。

export default { data() { return { message: 'Hello, Vue!' }; }, created() { console.log(this.message); // this 指向当前组件实例 }, mounted() { console.log('Component is mounted'); } };

使用箭头函数作为钩子

虽然理论上可以使用箭头函数作为钩子,但这会导致 this 绑定的问题。因为箭头函数不绑定自己的 this,它会从上层作用域中捕获 this,这通常并不是你想要的行为。在 Vue 组件中,这意味着 this 将不会指向组件的实例。

错误示例

export default { data() { return { message: 'Hello, Vue!' }; }, created: () => { console.log(this.message); // this 指向外部上下文,而不是 Vue 实例 }, mounted: () => { console.log('Component is mounted'); // 同样会出错 } };

在上面的示例中,this.message 将是 undefined,因为 this 并没有指向 Vue 实例。

正确的做法

如果需要在 Vue 中使用箭头函数(例如在回调中),请确保你不会将它用于生命周期钩子。相反,可以在方法、计算属性等其他地方使用箭头函数,而对于钩子,始终使用普通函数:

export default { data() { return { message: 'Hello, Vue!' }; }, created() { setTimeout(() => { console.log(this.message); // 在这里可以安全地使用箭头函数 }, 1000); }, methods: { someMethod: () => { console.log(this.message); // 这里的 this 仍然是外部上下文,应该避免这种写法 } } };

总结

  • 钩子函数:应始终使用普通函数来定义 Vue 生命周期钩子,以确保 this 正确指向组件实例。
  • 箭头函数:可以在需要保持上下文的地方使用(例如回调函数),但要小心它们的 this 行为。

 构造函数

在 JavaScript 中,构造函数是一种用于创建对象的特殊函数。通过构造函数,可以定义对象的属性和方法,并使用 new 关键字实例化这些对象。下面将详细介绍构造函数的概念、用法及示例。

1. 构造函数的定义

构造函数通常是一个普通的函数,它的名称以大写字母开头,以便与其他函数区分。当你调用一个构造函数并使用 new 关键字时,它会创建一个新对象并返回。

语法

function ConstructorName(parameters) { // 属性定义 this.property1 = value1; this.property2 = value2; // 方法定义 this.method1 = function() { // 方法逻辑 }; }

2. 使用构造函数

使用构造函数来创建对象时,需要使用 new 关键字。使用 new 时,会发生以下几个步骤:

  1. 创建一个新对象。
  2. 将新对象的 __proto__ 属性指向构造函数的 prototype
  3. 执行构造函数中的代码(为新对象添加属性)。
  4. 返回新对象(如果构造函数没有显式返回其他对象,则返回新创建的对象)。
示例

// 定义构造函数 function Person(name, age) { this.name = name; // 设置属性 this.age = age; // 设置属性 } // 为构造函数的原型添加方法 Person.prototype.sayHello = function() { console.log(`Hello, my name is ${this.name} and I am ${this.age} years old.`); }; // 使用构造函数创建对象 const alice = new Person('Alice', 30); const bob = new Person('Bob', 25); // 调用方法 alice.sayHello(); // Hello, my name is Alice and I am 30 years old. bob.sayHello(); // Hello, my name is Bob and I am 25 years old.

3. 构造函数的特点

  • 大写开头:构造函数的名称通常以大写字母开头,以便于与其他普通函数区分。
  • this关键字:在构造函数内部,this 指向新创建的对象。
  • 原型(Prototype):构造函数的原型可以用于共享方法和属性,这样所有实例都可以访问同一份方法,从而节省内存。

4. 实现继承

构造函数还可以用于实现继承。通过将子构造函数的原型设置为父构造函数的实例,可以实现基于原型链的继承。

示例

// 定义一个父构造函数 function Animal(name) { this.name = name; } Animal.prototype.speak = function() { console.log(`${this.name} makes a noise.`); }; // 定义一个子构造函数 function Dog(name) { Animal.call(this, name); // 调用父构造函数 } // 继承父类的方法 Dog.prototype = Object.create(Animal.prototype); Dog.prototype.constructor = Dog; // 添加子类特有的方法 Dog.prototype.bark = function() { console.log(`${this.name} barks!`); }; const fido = new Dog('Fido'); fido.speak(); // Fido makes a noise. fido.bark(); // Fido barks!

5. ES6 中的类(Class)

在 ES6 中,引入了 class 关键字,使得定义构造函数和继承变得更加简洁和易读。虽然底层实现仍然是基于构造函数和原型,但语法上更接近于其他面向对象编程语言。

示例

class Animal { constructor(name) { this.name = name; } speak() { console.log(`${this.name} makes a noise.`); } } class Dog extends Animal { bark() { console.log(`${this.name} barks!`); } } const rover = new Dog('Rover'); rover.speak(); // Rover makes a noise. rover.bark(); // Rover barks!

总结

  • 构造函数 是一种用于创建对象的特殊函数。
  • 利用构造函数,可以定义对象的属性和方法,并通过 new 关键字实例化对象。
  • 可以通过原型链实现继承。
  • ES6 引入了 class 语法,使得定义构造函数和继承变得更加方便。

 

改变this指向 的方法

在 JavaScript 中,this 关键字的指向是动态的,通常取决于函数的调用上下文。有时我们需要改变 this 的指向,以达到特定的目的。下面介绍几种常见的方法来改变 this 的指向。

1. 使用 call() 方法

call() 方法可以调用一个函数,并指定 this 的值和参数。它接受第一个参数作为 this 的值,其余参数为调用函数时传递的参数。

示例

function greet() { console.log(`Hello, my name is ${this.name}`); } const person = { name: 'Alice' }; greet.call(person); // Hello, my name is Alice

2. 使用 apply() 方法

apply() 方法与 call() 类似,但它接收一个数组作为第二个参数,用于传递参数。

示例

function introduce(age) { console.log(`My name is ${this.name} and I am ${age} years old.`); } const person = { name: 'Bob' }; introduce.apply(person, [30]); // My name is Bob and I am 30 years old.

3. 使用 bind() 方法

bind() 方法创建一个新函数,该函数在调用时会将 this 关键字设置为提供的值,即使这个新函数在其他

数组方法

JavaScript 中有许多用于操作数组的方法,这些方法能够简化常见的数组操作。以下是一些常用的数组方法及其示例:

1. push()

向数组末尾添加一个或多个元素,并返回新数组的长度。

const fruits = ['apple', 'banana']; fruits.push('orange'); // ['apple', 'banana', 'orange']

2. pop()

从数组末尾移除一个元素,并返回该元素。

const fruits = ['apple', 'banana', 'orange']; const lastFruit = fruits.pop(); // 'orange' console.log(fruits); // ['apple', 'banana']

3. shift()

从数组开头移除一个元素,并返回该元素。

const fruits = ['apple', 'banana', 'orange']; const firstFruit = fruits.shift(); // 'apple' console.log(fruits); // ['banana', 'orange']

4. unshift()

向数组开头添加一个或多个元素,并返回新数组的长度。

const fruits = ['banana', 'orange']; fruits.unshift('apple'); // ['apple', 'banana', 'orange']

5. splice()

可以删除、替换或添加数组中的元素。

const fruits = ['apple', 'banana', 'orange']; fruits.splice(1, 1, 'kiwi'); // 从索引1开始删除1个元素并添加'kiwi' // 结果: ['apple', 'kiwi', 'orange']

6. slice()

返回数组的指定部分,生成一个新数组,而不修改原数组。

const fruits = ['apple', 'banana', 'orange']; const citrus = fruits.slice(1, 3); // ['banana', 'orange']

7. forEach()

对数组的每个元素执行提供的函数。

const fruits = ['apple', 'banana', 'orange']; fruits.forEach((fruit) => { console.log(fruit); }); // 输出: // apple // banana // orange

8. map()

创建一个新数组,其结果是调用提供的函数处理每个元素后的返回值。

const numbers = [1, 2, 3]; const doubled = numbers.map((number) => number * 2); // [2, 4, 6]

9. filter()

创建一个新数组,其中包含所有通过测试的元素。

const numbers = [1, 2, 3, 4, 5]; const evens = numbers.filter((number) => number % 2 === 0); // [2, 4]

10. reduce()

对数组中的每个元素执行一个 reducer 函数,最终计算出一个单一的值。

const numbers = [1, 2, 3, 4]; const sum = numbers.reduce((accumulator, current) => accumulator + current, 0); // 10

11. find()

返回数组中满足提供的测试函数的第一个元素,如果没有找到则返回 undefined

const numbers = [1, 2, 3, 4]; const found = numbers.find((number) => number > 2); // 3

12. includes()

判断数组是否包含某个值,返回布尔值。

const fruits = ['apple', 'banana', 'orange']; const hasBanana = fruits.includes('banana'); // true

13. indexOf()

返回数组中首次出现某个值的索引,如果不存在则返回 -1。

const fruits = ['apple', 'banana', 'orange']; const index = fruits.indexOf('banana'); // 1

14. join()

将数组的所有元素连接成一个字符串,并返回这个字符串。

const fruits = ['apple', 'banana', 'orange']; const fruitString = fruits.join(', '); // 'apple, banana, orange'

15. sort()

对数组进行排序,并返回数组本身。

const numbers = [4, 2, 3, 1]; numbers.sort(); // [1, 2, 3, 4](注意:默认按字符顺序排序)

16. reverse()

颠倒数组中元素的顺序,并返回数组本身。

const fruits = ['apple', 'banana', 'orange']; fruits.reverse(); // ['orange', 'banana', 'apple']

原型链

在 JavaScript 中,原型链是实现对象继承的一种机制。它允许一个对象通过其原型访问另一个对象的属性和方法。以下是关于原型链的详细解释及示例。

1. 原型和构造函数

每个 JavaScript 对象都有一个内部属性 [[Prototype]],指向另一个对象,称为它的原型(通常可以通过 __proto__ 属性访问)。当试图访问一个对象的属性时,JavaScript 引擎首先会查找该对象本身是否有这个属性,如果没有,它会在原型上查找,然后继续沿着原型链向上查找,直到找到该属性或到达 null

示例

function Person(name) { this.name = name; } Person.prototype.sayHello = function() { console.log(`Hello, my name is ${this.name}`); }; const alice = new Person('Alice'); alice.sayHello(); // Hello, my name is Alice

在这个示例中:

  • Person 是一个构造函数。
  • sayHello 方法被添加到 Person.prototype 上,这样所有实例都可以共享这个方法。

2. 原型链的工作原理

当你创建一个 Person 实例,例如 alice,它的 [[Prototype]] 指向 Person.prototype。如果你调用 alice.sayHello(),JavaScript 会首先检查 alice 是否有 sayHello 方法。如果没有,它将查找 alice.__proto__,也就是 Person.prototype,并找到该方法。

3. 示例:多个层级的原型链

你可以通过继承实现更复杂的原型链结构。

function Animal(type) { this.type = type; } Animal.prototype.makeSound = function() { console.log(`${this.type} makes a sound`); }; function Dog(name) { Animal.call(this, 'Dog'); // 调用父类构造函数 this.name = name; } // 设置 Dog 的原型为 Animal 的实例 Dog.prototype = Object.create(Animal.prototype); Dog.prototype.constructor = Dog; Dog.prototype.bark = function() { console.log(`${this.name} barks!`); }; const dog = new Dog('Buddy'); dog.makeSound(); // Dog makes a sound dog.bark(); // Buddy barks!

在这个示例中:

  • Dog 继承了 Animal
  • Dog.prototype 被设为 Animal 的实例,从而形成了原型链。

4. 检查原型链

你可以使用 instanceofisPrototypeOf 来检查原型关系。

console.log(dog instanceof Dog); // true console.log(dog instanceof Animal); // true console.log(Animal.prototype.isPrototypeOf(dog)); // true

5. 总结

原型链在 JavaScript 中是非常重要的概念,它支持对象间的继承和共享行为。理解原型链的工作原理可以帮助你更好地设计和组织你的代码。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值