Key Frontend Development Concepts for Interviews
Vue.js is a progressive JavaScript framework designed for building user interfaces. Its core library focuses on the view layer, making it easy to integrate with existing projects or to power complex single-page applications. Vue is known for its approachability, clear documentation, and solid performance, positioning it as a leading choice alongside React and Angular in the modern frontend landscape.
Essential Frontend Knowledge
Before diving deep into frameworks, a strong foundation in core web technologies is crucial:
- HTML: Understanding semantic tags, attributes, and page structure is fundamental for accessible and well-organized content.
- CSS: Mastery of styling rules, selectors, the box model, and layout techniques (like Flexbox and Grid) is essential for creating visually appealing and responsive interfaces.
- JavaScript: Core concepts such as objects, arrays, expressions, functions, and closures form the backbone of dynamic web applications.
Vue.js Reactive Features
The watch Property
The watch property in Vue allows you to react to changes in data properties. It's particularly useful for asynchronous operations, complex data transformations, or when you need to perform actions based on a data change, such as form validation or fetching external data.
export default {
data() {
return {
userQuery: '',
existingUsernames: ['alice', 'bob', 'charlie'],
validationMessage: ''
};
},
watch: {
// A basic watcher function that executes when 'userQuery' changes.
// The handler receives the new value and the old value.
userQuery(newQuery, oldQuery) {
if (newQuery.length > 0 && this.existingUsernames.includes(newQuery.toLowerCase())) {
this.validationMessage = `Username '${newQuery}' is already taken.`;
} else {
this.validationMessage = '';
}
console.log(`User query changed from '${oldQuery}' to '${newQuery}'`);
},
// Using the object syntax for more control, e.g., 'immediate' execution.
// This variant is often preferred for more complex watch scenarios.
userQuery: {
handler(newQuery, oldQuery) {
// Simulate an API call with a delay
setTimeout(() => {
if (newQuery.length > 0 && newQuery.length < 3) {
this.validationMessage = 'Query must be at least 3 characters.';
} else if (this.existingUsernames.includes(newQuery.toLowerCase())) {
this.validationMessage = `Username '${newQuery}' is unavailable.`;
} else {
this.validationMessage = '';
}
}, 500);
},
// 'immediate: true' executes the handler immediately upon component creation.
immediate: true,
// 'deep: true' for watching nested properties of an object (if userQuery were an object).
// deep: true
}
}
};
computed Properties vs. methods
Both computed properties and methods can encapsulate logic and return a result, but they serve different primary purposes and have distinct performance characteristics:
- Similarities: Both can define functions that perform calculations or transformations.
computedProperties: Are cached based on their reactive dependencies. A computed property will only re-evaluate when one of its dependencies changes. This makes them highly efficient for values that are derived from other reactive data and are frequently accessed. They are accessed like properties (this.computedValue). Computed properties can also havegetandsetfunctions for two-way data binding.methods: Are simply functions that can be called at any time. They do not cache their results and will execute every time they are called or the component re-renders. They are accessed by calling them (this.methodName()). Use methods for event handlers or when you need a function to execute without relying on reactive dependency caching.
Conditional Rendering Directives
v-if vs. v-show
Vue offers two directives for conditionally rendering elements, each with different mechanisms and use cases:
v-if: This directive conditionally renders elements by adding or removing them from the DOM. If the condition is false, the element and its children are completely destroyed and unmounted. This approach incurs higher toggle costs but is efficient when the condition rarely changes.v-show: This directive conditionally displays elements by toggling their CSSdisplayproperty (display: none;). The element remains in the DOM regardless of the condition. This approach has lower toggle costs but higher initial render costs, making it suitable for elements that are frequently toggled.
Consider v-show for frequent toggling and v-if for infrequent toggling or when complete removal from the DOM is desired.
Core JavaScript and Browser APIs
Familiarity with standard JavaScript features and browser APIs is essential for any frontend developer:
confirm('message'): Displays a modal dialog with a specified message, an OK button, and a Cancel button. It returnstrueif the user clicks OK, andfalseotherwise.prompt('message', 'default'): Displays a modal dialog that prompts the user for input. It includes a text field for input and OK/Cancel buttons. It returns the input value as a string (ornullif canceled).Node.insertBefore(newNode, referenceNode): Inserts anewNodebefore areferenceNodeas a child of theNode(parent element).ParentNode.appendChild(childNode): Adds achildNodeto the end of the list of children of a specifiedParentNode.
Component Communication in Vue
Vue provides several patterns for inter-component communication:
-
Parent-to-Child (Props): Parent components pass data down to child components using
props. Apropis a custom attribute that you register on a component. When a value is passed to a prop, it becomes a property on the child component instance.<!-- ParentComponent.vue --> <template> <UserProfileCard :user-data="currentUser"></UserProfileCard> </template> <script> import UserProfileCard from './UserProfileCard.vue'; export default { components: { UserProfileCard }, data() { return { currentUser: { id: 1, name: 'Alex', email: 'alex@example.com' } }; } }; </script> <!-- UserProfileCard.vue --> <template> <div> <h3>{{ userData.name }}</h3> <p>Email: {{ userData.email }}</p> </div> </template> <script> export default { props: { userData: { type: Object, required: true, default: () => ({}) } } }; </script> -
Child-to-Parent (Events with
$emit): Child components communicate up to their parent by emitting custom events. The parent component listens for these events and can react to them.<!-- ChildButton.vue --> <template> <button @click="triggerAction">Perform Action</button> </template> <script> export default { methods: { triggerAction() { this.$emit('child-action', { status: 'completed', data: 'some result' }); } } }; </script> <!-- ParentComponent.vue --> <template> <ChildButton @child-action="handleChildAction"></ChildButton> <p>Last action status: {{ latestActionStatus }}</p> </template> <script> import ChildButton from './ChildButton.vue'; export default { components: { ChildButton }, data() { return { latestActionStatus: 'none' }; }, methods: { handleChildAction(payload) { console.log('Action received from child:', payload); this.latestActionStatus = payload.status; } } }; </script> -
Sibling or Arbitrary Components (Event Bus / Vuex): For communication between components that don't have a direct parent-child relationship:
-
Event Bus: A simple pattern using an empty Vue instance as a central event hub. Components can emit events to the bus, and other components can listen to them.
// eventBus.js import Vue from 'vue'; export const appEventBus = new Vue();<!-- ComponentA.vue --> <template> <button @click="sendMessage">Send Data to Sibling</button> </template> <script> import { appEventBus } from './eventBus'; export default { methods: { sendMessage() { appEventBus.$emit('data-from-a', 'Message from Component A'); } } }; </script> <!-- ComponentB.vue --> <template> <div>Received: {{ receivedMessage }}</div> </template> <script> import { appEventBus } from './eventBus'; export default { data() { return { receivedMessage: 'No message yet' }; }, created() { appEventBus.$on('data-from-a', (data) => { this.receivedMessage = data; console.log('Component B received:', data); }); }, beforeDestroy() { // Important: Remove the event listener to prevent memory leaks appEventBus.$off('data-from-a'); } }; </script> -
Vuex: For larger applications, a dedicated state management library like Vuex is recommended. It provides a centralized store for all component states, ensuring predictable state mutations.
-
Content Distribution with Slots
Vue's slot mechanism allows components to compose flexible and reusable templates. A slot acts as a placeholder within a component's template, which will be filled with content provided by the parent component.
- Default Slots:
<slot></slot>is a placeholder for any content passed to the component without a specific name. - Named Slots:
<slot name="header"></slot>allows parents to target specific slots by theirnameattribute usingtemplatetags withv-slot:slotName(orslot="slotName"in Vue 2). - Scoped Slots: Allow child components to pass data back to the parent component's slot content. This is useful for making reusable components that need to provide specific data to the slot content for rendering.
Vue Directives and Modifiers
-
v-cloak: Prevents the display of uncompiled Mustache tags ({{ }}) during page load, typically by hiding the element until Vue has finished compiling it.<style> [v-cloak] { display: none; } </style> <div v-cloak>{{ message }}</div> -
v-bind: Dynamically binds one or more attributes, or a component prop, to an expression. Shorthand is:attribute="expression". -
Event Modifiers: Vue provides modifiers for event handlers to perform common tasks without manual
eventobject handling:.stop:event.stopPropagation().prevent:event.preventDefault().capture: Adds event listener in capture mode..self: Only trigger handler ifevent.targetis the element itself..once: Listener will only be called once..passive: Improves scrolling performance (especially on mobile)..left,.right,.middle: For mouse button clicks.
Other Vue Directives
-
v-pre: Skips compilation for the element and its children, displaying raw Mustache tags or static content as is.<span v-pre>{{ this content will not be compiled }}</span> <!-- Output: {{ this content will not be compiled }} --> -
v-text: Updates an element'stextContent. It's similar to Mustache interpolation ({{ }}) but directly sets the text content, making it useful for preventing flicker on slow connections. -
v-html: Updates an element'sinnerHTMLwith raw HTML content. Use with caution to prevent XSS vulnerabilities. -
v-else: Used in conjunction withv-ifto provide an "else" block. -
v-else-if: Provides an "else if" block forv-if. -
v-for: Renders a list of items based on an array or object. -
v-on: Attaches event listeners. Shorthand is@event="handler". -
v-model: Creates a two-way data binding on form input elements.
Web Storage: localStorage
localStorage provides a way for web applications to store key-value pairs locally within the browser, persistently across browser sessions. It's part of the Web Storage API.
localStorage.setItem(key, value): Stores avalueunder a specifiedkey. Bothkeyandvaluemust be strings. For storing objects or arrays, useJSON.stringify()to convert them to a string first.localStorage.getItem(key): Retrieves thevalueassociated with akey. The returned value is a string, so for stored objects/arrays, useJSON.parse()to convert it back.localStorage.removeItem(key): Deletes the key-value pair for the specifiedkey.localStorage.clear(): Removes all key-value pairs for the current origin.
Example:
// Store an object
const userSettings = { theme: 'dark', notifications: true };
localStorage.setItem('userPrefs', JSON.stringify(userSettings));
// Retrieve and parse the object
const retrievedSettings = JSON.parse(localStorage.getItem('userPrefs'));
console.log(retrievedSettings.theme); // 'dark'
Custom Directives in Vue
Custom directives allow developers to encapsulate reusable DOM manipulation logic. They are registered globally or locally and expose several lifecycle hooks:
bind: Called once, when the directive is first bound to the element. Good for one-time setup.inserted: Called when the bound element has been inserted into its parent node (but not necessarily in the DOM tree).update: Called when the component containing the directive is updated, but before its children are updated.componentUpdated: Called after the component and its children have been updated.unbind: Called once, when the directive is unbound from the element.
Example: Auto-focus Directive
// Global registration
Vue.directive('autofocus-input', {
inserted: (element) => {
element.focus(); // The element automatically receives focus when inserted into the DOM.
}
});
// Usage in a component template:
// <input v-autofocus-input />
// Local registration within a component
export default {
directives: {
'highlight-text': {
inserted: (el, binding) => {
// 'binding.value' can be used to pass a value to the directive, e.g., v-highlight-text="'blue'"
el.style.backgroundColor = binding.value || 'yellow';
}
}
}
};
// Usage in a component template:
// <span v-highlight-text="'lightblue'">This text will be highlighted.</span>
Component Registration: Global vs. Local
- Global Components: Registered using
Vue.component('ComponentName', definition). Once registered, they can be used anywhere in your application without needing to be imported or registered again in individual components. Best for widely used, generic components (e.g.,BaseButton,AppHeader). - Local Components: Imported and registered within the
componentsoption of a specific Vue component. They are only available within that component and its children. Best for specific, feature-oriented components to maintain better modularity and bundle size.
Vue Single File Components (SFCs) and Architecture
A Vue Single File Component (.vue file) encapsulates a component's template, script, and styles in a single file, facilitating modular development.
-
Structure: Comprises three main blocks:
<template>: Contains the component's HTML structure. Must have a single root element.<script>: Houses the component's JavaScript logic (data, methods, computed properties, lifecycle hooks, etc.).<style>: Cotnains the component's CSS. Thescopedattribute can be used to limit styles to the current component.
-
Props Validation: Enhance component reusability and robustness by defining validation rules for props:
type: (e.g.,String,Number,Boolean,Array,Object).required: (true/false) specifies if the prop is mandatory.default: Provides a default value if the prop is not passed. ForObjectorArraytypes, the default must be returned from a factory function.
-
Dynamic Components: The
<component :is="componentName">tag allows dynamic switching between components based on thecomponentNamevalue. -
keep-alive: A built-in component that can wrap dynamic components or router views to cache them, preventing re-rendering on subsequent visits. This helps maintain component state and improve performance. -
Lifecycle Hooks:
mountedis a common hook for performing DOM manipulations or fetching data immediately after the component is inserted into the DOM. -
MVVM Pattern: Vue adheres to the Model-View-ViewModel (MVVM) architectural pattern. The Model represents the raw data, the View is the DOM, and the ViewModel (Vue instance) acts as a bridge, automatically synchronizing data between the Model and the View via reactive two-way data binding.
Frontend Build and Project Management
CSS Preprocessor Integration (e.g., Stylus)
To use CSS preprocessors like Stylus, Sass, or Less in a Vue CLI project, you typically install the preprocessor and its corresponding webpack loader.
# For Stylus
npm install stylus stylus-loader --save-dev
# Usage in a Vue component
# <style lang="stylus" scoped></style>
Common Frontend Technologies
Beyond Vue's core, a rich ecosystem of tools and libraries enhances development:
- Routing:
vue-routerfor single-page application navigation. - State Management:
vuexfor centralized state management in large applications. - UI Frameworks:
Element UI,Mint UI(for mobile) provide ready-to-use component sets. - Performance:
vue-lazyloadfor lazy loading images. - Scrolling/Swiping:
vue-scroller,better-scroll,swiperfor touch-friendly interfaces. - Date Handling:
moment.js(legacy, consider alternatives likedate-fns) for parsing, validating, manipulating, and formatting dates.
Typical Vue CLI Project Structure
When starting with Vue CLI, a common project structure emerges:
build/&config/: Contains Webpack and build-related configurations (often less frequently modified).config/index.js: Defines development server port and asset paths.
node_modules/: Directory for installed npm packages.src/: The main source code directory.main.js: The application's entry point, where Vue instance is initialized and plugins are registered.App.vue: The root component of the application.api/: Modules for backend API interactions.assets/: Static assets like images, fonts, global styles.components/: Reusable, non-route-specific UI components.filters/: Custom Vue filters.mock/: Mock data or API endpoints for development.pages/orviews/: Route-specific components that represent full pages.router/: Vue Router configuration.store/: Vuex store modules.
public/orstatic/: Directly served static assets..babelrc: Babel configuration for JavaScript transpilation..eslintrc.js: ESLint configuration for code linting.index.html: The main HTML file where the Vue app is mounted.package.json: Project metadata, dependencies, and scripts.
Mobile Web Development Considerations
-
Viewport Configuration: Ensuring proper scaling and responsiveness on various devices.
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=no"> -
300ms Click Delay: Older mobile browsers introduce a 300ms delay between
touchendandclickevents. Libraries likeFastClickcan mitigate this for a snappier user experience.<script src="https://cdnjs.cloudflare.com/ajax/libs/fastclick/1.0.6/fastclick.min.js"></script> <script> if ('addEventListener' in document) { document.addEventListener('DOMContentLoaded', function() { FastClick.attach(document.body); }, false); } </script>
Advanced JavaScript Concepts
Arrow Functions and this Binding
Arrow functions (=>) provide a concise syntax for writing fucntions. Their key characteristic is lexical this binding: they do not have their own this context. Instead, this inside an arrow function refers to the this value of the enclosing lexical scope (where the arrow function is defined), rather than where it's called. In contrast, regular functions (function) have a dynamic this that depends on how they are called.
Closures
A closure is a function that remembers its lexical environment even when it's executed outside that lexical scope. This means a closure can access variables from its parent function's scope even after the parent function has finished executing.
function createItemCounter(initialCount) {
let currentCount = initialCount; // 'currentCount' is the variable captured by the closure
return function increment() {
currentCount++;
return currentCount;
};
}
const widgetCounter = createItemCounter(0);
console.log(widgetCounter()); // 1
console.log(widgetCounter()); // 2
const anotherCounter = createItemCounter(10);
console.log(anotherCounter()); // 11
JavaScript Pre-compilation (Parsing)
Before JavaScript code is executed, it undergoes a phase often referred to as