自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

超好運(yùn)的大廠實(shí)習(xí)(帶轉(zhuǎn)正)面試,直接拿下!猛猛的!

開發(fā)
const 聲明的是一個(gè)不可重新賦值的變量,但它的值(如果是對(duì)象或數(shù)組)可以是可變的。

Hello,大家好,我是 Sunday。

運(yùn)氣也是實(shí)力的一部分,此話誠不欺我!

最近有位同學(xué),校招面試攜程,一面、二面,都是純八股文的面試。這可是 帶轉(zhuǎn)正的 HC 呀! 直接輕松拿下。

實(shí)習(xí)一天 220,額外加 1000/月 的房補(bǔ)。在大廠中算是中等水平。

那么下面咱們就來看看這次面試,都聊了什么問題吧!

一、improt和require的區(qū)別

import 和 require 是 JavaScript 中用來導(dǎo)入模塊的兩種不同的語法,主要用于 ES6 和 CommonJS 模塊系統(tǒng)。以下是它們的主要區(qū)別:

1. 模塊系統(tǒng)

  • require: 屬于 CommonJS 模塊系統(tǒng),主要用于 Node.js 中。它是同步加載模塊的,適合在服務(wù)器端使用。
  • import: 屬于 ES6 模塊系統(tǒng)(也稱為 ECMAScript 模塊)。它支持異步加載,適合在瀏覽器端和現(xiàn)代 JavaScript 環(huán)境中使用。

2. 語法

  • require:
const module = require('module-name');
  • import:
import module from 'module-name'; // 導(dǎo)入默認(rèn)導(dǎo)出
import { namedExport } from 'module-name'; // 導(dǎo)入命名導(dǎo)出
import * as allExports from 'module-name'; // 導(dǎo)入所有導(dǎo)出

3. 加載時(shí)機(jī)

  • require: 在代碼運(yùn)行時(shí)被調(diào)用,模塊在被調(diào)用時(shí)才會(huì)被加載,因此是同步的。
  • import: 在編譯階段被處理,模塊會(huì)在模塊代碼執(zhí)行前被加載,因此是異步的。

4. Hoisting(提升)

  • require: 不會(huì)提升,必須在代碼中顯式調(diào)用。
  • import: 會(huì)提升,可以在文件的任何位置使用,但在模塊的頂部進(jìn)行導(dǎo)入是最佳實(shí)踐。

5. 導(dǎo)出方式

CommonJS 導(dǎo)出:

// 導(dǎo)出模塊
module.exports = {
    functionA: function() {},
    functionB: function() {},
};

ES6 導(dǎo)出:

// 導(dǎo)出默認(rèn)
export default functionA;

// 導(dǎo)出命名
export function functionB() {}

6. 循環(huán)依賴處理

  • require: 處理循環(huán)依賴時(shí),返回的是已經(jīng)加載的模塊部分。
  • import: 在循環(huán)依賴的情況下,會(huì)引發(fā)錯(cuò)誤,因?yàn)樗谀K解析階段就會(huì)出錯(cuò)。

7. 總結(jié)

  • require: 適合 Node.js 和后端開發(fā),采用同步加載的方式。
  • import: 更加現(xiàn)代,適合前端開發(fā),支持異步加載和靜態(tài)分析。

在現(xiàn)代前端開發(fā)中,建議使用 ES6 的 import 語法,因?yàn)樗峁┝烁玫哪K化和可維護(hù)性。

二、require 有辦法實(shí)現(xiàn)異步嗎?

在 Node.js 中,require 本身是同步的,但可以通過一些其他方式實(shí)現(xiàn)異步模塊加載。以下是幾種方法:

1. 使用 import()

從 ES6 開始,可以使用動(dòng)態(tài) import() 函數(shù)來實(shí)現(xiàn)異步加載模塊。雖然它與 require 不同,但在現(xiàn)代 JavaScript 環(huán)境中是推薦的方式。

async function loadModule() {
    const module = await import('./module.js');
    module.someFunction();
}

2. 使用 require 結(jié)合回調(diào)

可以在回調(diào)中使用 require,盡管這并不是真正的異步加載,但可以通過事件循環(huán)達(dá)到異步效果。

function loadModule(callback) {
    setTimeout(() => {
        const module = require('./module.js');
        callback(module);
    }, 0);
}

loadModule((module) => {
    module.someFunction();
});

3. 使用 require 結(jié)合 Promise

通過 Promise 的方式包裹 require,達(dá)到異步的效果:

function loadModule() {
    return new Promise((resolve) => {
        setTimeout(() => {
            const module = require('./module.js');
            resolve(module);
        }, 0);
    });
}

loadModule().then((module) => {
    module.someFunction();
});

4. 使用 async_hooks

在更復(fù)雜的場(chǎng)景中,可以使用 Node.js 的 async_hooks 模塊來處理異步上下文,但這通常不適用于簡(jiǎn)單的模塊加載需求。

5. 總結(jié)

雖然 require 本身是同步的,不能直接實(shí)現(xiàn)異步模塊加載,但可以使用動(dòng)態(tài) import() 或通過回調(diào)和 Promise 來模擬異步行為。在現(xiàn)代開發(fā)中,推薦使用 ES6 的動(dòng)態(tài) import(),因?yàn)樗呖勺x性和一致性。

三、export 和 export default的區(qū)別

export 和 export default 是 ES6 中用于導(dǎo)出模塊的兩種方式,它們的主要區(qū)別如下:

1. 導(dǎo)出方式

(1) export

// module.js
export const a = 1;
export const b = 2;
export function add(x, y) {
    return x + y;
}
// main.js
import { a, add } from './module.js';
console.log(a); // 1
console.log(add(1, 2)); // 3

允許在一個(gè)模塊中導(dǎo)出多個(gè)變量、函數(shù)或類。

導(dǎo)出時(shí)不需要指定名稱,可以在導(dǎo)入時(shí)使用 {} 指定要導(dǎo)入的變量名稱。

(2) export default

// module.js
const multiply = (x, y) => x * y;
export default multiply;
// main.js
import multiply from './module.js';
console.log(multiply(2, 3)); // 6

每個(gè)模塊只能有一個(gè)默認(rèn)導(dǎo)出。

在導(dǎo)入時(shí)可以使用任何名稱,不需要使用 {}。

2. 導(dǎo)入方式

使用export的導(dǎo)入:

import { a, b } from './module.js';

導(dǎo)入時(shí)需要使用相同的名稱,且需要使用 {} 包裹。

使用export default的導(dǎo)入:

import myFunction from './module.js';

導(dǎo)入時(shí)可以自定義名稱,且不需要 {}。

3. 使用場(chǎng)景

  • export: 當(dāng)你需要導(dǎo)出多個(gè)功能或變量時(shí),適合使用 export。
  • export default: 當(dāng)一個(gè)模塊有一個(gè)主要功能或?qū)ο髸r(shí),適合使用 export default。

4. 組合使用

可以同時(shí)使用兩者:

// module.js
export const a = 1;
export const b = 2;
const multiply = (x, y) => x * y;
export default multiply;
// main.js
import multiply, { a } from './module.js';
console.log(a); // 1
console.log(multiply(2, 3)); // 6

5. 總結(jié)

export 允許多個(gè)命名導(dǎo)出,而 export default 只允許一個(gè)默認(rèn)導(dǎo)出。

導(dǎo)入時(shí),命名導(dǎo)出需要使用 {},而默認(rèn)導(dǎo)入可以使用任意名稱。

四、閉包

能夠調(diào)用其他函數(shù)中變量的函數(shù),就是 閉包函數(shù)。

function outerFunction() {
    let outerVariable = 'I am outside!';
    // innerFunction 函數(shù)使用了 outerFunction 里面的變量,所以它就是【閉包函數(shù)】
    function innerFunction() {
        console.log(outerVariable);
    }

    return innerFunction;
}

const closureFunction = outerFunction(); // outerFunction 被執(zhí)行
closureFunction(); // 輸出: I am outside!

五、在什么情況下閉包會(huì)出現(xiàn)內(nèi)存泄漏的問題

閉包在某些情況下會(huì)導(dǎo)致內(nèi)存泄漏,主要是由于閉包持有外部變量的引用,進(jìn)而阻止了這些變量的垃圾回收。以下是幾種可能導(dǎo)致內(nèi)存泄漏的情況:

1. 循環(huán)引用

當(dāng)閉包持有外部對(duì)象的引用,而該對(duì)象又持有對(duì)閉包的引用時(shí),就會(huì)產(chǎn)生循環(huán)引用。這種情況會(huì)導(dǎo)致垃圾回收器無法正確回收內(nèi)存。

function createClosure() {
    let obj = {};
    obj.closure = function() {
        console.log(obj);
    };
    return obj.closure;
}

const closure = createClosure(); // obj 和 closure 形成循環(huán)引用

在上面的例子中,obj 對(duì)象持有對(duì)閉包的引用,而閉包又引用了 obj,這導(dǎo)致內(nèi)存無法被回收。

2. 不當(dāng)使用事件監(jiān)聽器

如果使用閉包作為事件監(jiān)聽器并沒有在適當(dāng)?shù)臅r(shí)候移除它們,可能會(huì)導(dǎo)致內(nèi)存泄漏。特別是在動(dòng)態(tài)創(chuàng)建和銷毀 DOM 元素時(shí)。

function createElement() {
    const button = document.createElement('button');
    button.innerText = 'Click me';
    
    button.addEventListener('click', function() {
        // 使用了外部變量
        console.log('Button clicked');
    });
    
    document.body.appendChild(button);
}

// 每次調(diào)用 createElement 都會(huì)添加一個(gè)新的按鈕,但事件監(jiān)聽器不會(huì)被移除
createElement();

在這個(gè)例子中,每次調(diào)用 createElement 函數(shù)都會(huì)創(chuàng)建一個(gè)新的按鈕并添加事件監(jiān)聽器,但如果不手動(dòng)移除這些監(jiān)聽器,它們將一直保留在內(nèi)存中。

3. 大型數(shù)據(jù)結(jié)構(gòu)

當(dāng)閉包持有大型數(shù)據(jù)結(jié)構(gòu)(如大數(shù)組或?qū)ο螅┑囊脮r(shí),如果這些數(shù)據(jù)結(jié)構(gòu)沒有在不需要時(shí)被清理,也可能導(dǎo)致內(nèi)存泄漏。

let largeArray = new Array(1000000).fill('data');

function createLargeDataClosure() {
    return function() {
        console.log(largeArray.length); // 持有對(duì) largeArray 的引用
    };
}

const closure = createLargeDataClosure();

在這個(gè)例子中,closure 持有對(duì) largeArray 的引用,如果沒有在適當(dāng)?shù)臅r(shí)候釋放這個(gè)引用,將會(huì)導(dǎo)致內(nèi)存占用持續(xù)增加。

4. 使用全局作用域

如果閉包中的變量是全局變量,那么閉包會(huì)一直持有對(duì)這些全局變量的引用,直到整個(gè)程序結(jié)束。這在長時(shí)間運(yùn)行的應(yīng)用中,可能導(dǎo)致內(nèi)存的不斷增長。

let globalVar = 'Hello';

function createClosure() {
    return function() {
        console.log(globalVar);
    };
}

const closure = createClosure();

在這個(gè)例子中,閉包始終引用了 globalVar,從而保持了對(duì)它的引用。

5. 預(yù)防內(nèi)存泄漏的措施

  • 合理使用閉包:盡量避免不必要的閉包,尤其是在循環(huán)和事件處理器中。
  • 及時(shí)清理引用:在不再需要的時(shí)候,主動(dòng)清理閉包中的引用,例如通過將事件監(jiān)聽器設(shè)置為 null。
  • 使用 WeakMap 和 WeakSet:對(duì)于需要被垃圾回收的對(duì)象引用,可以使用 WeakMap 和 WeakSet,它們不會(huì)阻止垃圾回收。
  • 手動(dòng)移除事件監(jiān)聽器:在元素被移除時(shí),記得手動(dòng)移除事件監(jiān)聽器。

通過以上方式,可以有效減少使用閉包時(shí)可能出現(xiàn)的內(nèi)存泄漏問題。

六、說一下 JS 中原型鏈的概念

原型鏈?zhǔn)?JavaScript 中實(shí)現(xiàn)繼承的一種機(jī)制,每個(gè)對(duì)象都有一個(gè)內(nèi)部屬性指向其原型對(duì)象。原型鏈?zhǔn)峭ㄟ^對(duì)象的 __proto__ 屬性或 Object.getPrototypeOf() 方法連接起來的。下面是原型鏈的基本概念以及圖示說明。

1. 原型鏈的概念

  • 原型:每個(gè) JavaScript 對(duì)象都有一個(gè)原型,原型也是一個(gè)對(duì)象,可以有自己的原型,這樣就形成了一個(gè)鏈?zhǔn)浇Y(jié)構(gòu),稱為原型鏈。
  • 構(gòu)造函數(shù):通過構(gòu)造函數(shù)創(chuàng)建的對(duì)象會(huì)有一個(gè) prototype 屬性,指向構(gòu)造函數(shù)的原型對(duì)象。

查找順序:

  • 當(dāng)訪問一個(gè)對(duì)象的屬性時(shí),JavaScript 引擎首先在該對(duì)象自身查找。如果找不到,它會(huì)查找該對(duì)象的原型(即 __proto__ 屬性指向的對(duì)象)。
  • 如果在原型中也沒有找到,它會(huì)繼續(xù)向上查找,直到找到屬性或到達(dá)原型鏈的末端(通常是 Object.prototype),如果仍未找到,則返回 undefined。

2. 示例代碼

function Animal(name) {
  this.name = name;
}

Animal.prototype.speak = function() {
  console.log(this.name + ' makes a noise.');
};

function Dog(name) {
  Animal.call(this, name); // Call the parent constructor
}

// 設(shè)置 Dog.prototype 為 Animal 的實(shí)例
Dog.prototype = Object.create(Animal.prototype);
Dog.prototype.constructor = Dog; // 糾正 constructor

Dog.prototype.speak = function() {
  console.log(this.name + ' barks.');
};

const dog = new Dog('Rex');
dog.speak(); // 輸出: Rex barks.

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

3. 解析示例

Animal 是一個(gè)構(gòu)造函數(shù),創(chuàng)建的實(shí)例具有 name 屬性和 speak 方法。

Dog 是另一個(gè)構(gòu)造函數(shù),它通過 Object.create(Animal.prototype) 使得 Dog.prototype 成為 Animal.prototype 的實(shí)例,從而繼承了 Animal 的方法。

dog 是 Dog 的一個(gè)實(shí)例,它可以訪問 speak 方法,雖然該方法在 Dog 的原型上被覆蓋,但它也可以訪問 Animal 的 speak 方法(如果需要的話)。

4. 小結(jié)

原型鏈?zhǔn)?JavaScript 繼承的基礎(chǔ),允許對(duì)象共享屬性和方法。

理解原型鏈對(duì)于掌握 JavaScript 的面向?qū)ο缶幊?、?gòu)造函數(shù)、以及如何實(shí)現(xiàn)繼承非常重要。

七、null有原型鏈嗎?

null 在 JavaScript 中被認(rèn)為是一個(gè)特殊的原始值。它表示“無”或“空值”。在原型鏈的上下文中,null 是原型鏈的終點(diǎn)。

八、Array的原型是什么

在 JavaScript 中,Array 是一種內(nèi)置的對(duì)象,用于處理數(shù)組。Array 的原型是 Array.prototype。這使得所有數(shù)組實(shí)例都能夠訪問 Array.prototype 上定義的方法和屬性。

1. 原型鏈結(jié)構(gòu)

(1) Array.prototype:

  • Array.prototype 是所有數(shù)組對(duì)象的原型,定義了數(shù)組的方法和屬性,如 push(), pop(), map(), filter() 等。
  • 你可以在 Array.prototype 上添加自定義的方法,這樣所有數(shù)組實(shí)例都可以使用。

(2) Object.prototype:

  • 所有對(duì)象(包括數(shù)組)的原型最終都會(huì)鏈接到 Object.prototype。這意味著數(shù)組實(shí)例也繼承了 Object 的方法和屬性,如 toString(), hasOwnProperty() 等。

(3) null:

  • Object.prototype 的原型是 null,這是原型鏈的終點(diǎn)。

2. 示例

下面是一個(gè)示例,展示了如何通過 Array.prototype 訪問數(shù)組方法:

// 定義一個(gè)數(shù)組
const arr = [1, 2, 3];

// 訪問 Array.prototype 上的方法
console.log(arr.map(x => x * 2)); // 輸出: [2, 4, 6]

// 檢查原型
console.log(Object.getPrototypeOf(arr) === Array.prototype); // 輸出: true
console.log(Object.getPrototypeOf(Array.prototype) === Object.prototype); // 輸出: true

3. 總結(jié)

Array 的原型是 Array.prototype。

所有數(shù)組實(shí)例都可以訪問 Array.prototype 上定義的方法和屬性。

Array.prototype 又可以通過其原型鏈訪問到 Object.prototype,最終終止于 null。

九、Object的原型是什么

在 JavaScript 中,Object 是所有對(duì)象的基類。Object 的原型是 Object.prototype。這是一個(gè)包含許多通用方法和屬性的對(duì)象,所有普通對(duì)象都可以繼承這些方法和屬性。

1. 原型鏈結(jié)構(gòu)

(1) Object.prototype:

  • Object.prototype 是所有對(duì)象的原型,它定義了一些通用的方法和屬性,例如 toString(), hasOwnProperty(), isPrototypeOf(), 和 valueOf() 等。
  • 所有普通對(duì)象(即通過對(duì)象字面量、構(gòu)造函數(shù)或 Object.create() 創(chuàng)建的對(duì)象)都能夠訪問 Object.prototype 上的方法和屬性。

(2) null:

Object.prototype 的原型是 null,這是原型鏈的終點(diǎn)。

2. 示例

下面是一個(gè)示例,展示了如何通過 Object.prototype 訪問對(duì)象方法:

// 創(chuàng)建一個(gè)普通對(duì)象
const obj = {
  name: 'Alice',
  age: 30
};

// 訪問 Object.prototype 上的方法
console.log(obj.toString()); // 輸出: [object Object]
console.log(obj.hasOwnProperty('name')); // 輸出: true

// 檢查原型
console.log(Object.getPrototypeOf(obj) === Object.prototype); // 輸出: true
console.log(Object.getPrototypeOf(Object.prototype)); // 輸出: null

3. 總結(jié)

Object 的原型是 Object.prototype。

所有普通對(duì)象都可以訪問 Object.prototype 上定義的方法和屬性。

Object.prototype 的原型是 null,這是原型鏈的終點(diǎn)。

十、let const var的區(qū)別

let、const 和 var 是 JavaScript 中用于聲明變量的關(guān)鍵字。它們之間有一些重要的區(qū)別:

1. 聲明的作用域

(1) var:

聲明的變量具有 函數(shù)作用域。如果在函數(shù)內(nèi)部使用 var 聲明變量,該變量只在該函數(shù)內(nèi)可用。如果在函數(shù)外部使用 var 聲明,變量會(huì)變成全局變量。

例子:

function example() {
  var a = 10;
}
console.log(a); // ReferenceError: a is not defined

(2) let和const:

聲明的變量具有 塊級(jí)作用域。也就是說,它們只在其聲明的代碼塊內(nèi)有效(例如,if 語句、for 循環(huán)等)。

例子:

{
  let b = 20;
  const c = 30;
}
console.log(b); // ReferenceError: b is not defined
console.log(c); // ReferenceError: c is not defined

2. 變量提升

(1) var:

變量會(huì)被提升到函數(shù)的頂部,初始化為 undefined。在變量聲明之前使用該變量不會(huì)報(bào)錯(cuò),但值為 undefined。

例子:

console.log(d); // undefined
var d = 5;
console.log(d); // 5

(2) let和const:

變量也會(huì)被提升,但在聲明之前是 “暫時(shí)性死區(qū)”(Temporal Dead Zone, TDZ),使用它們會(huì)導(dǎo)致 ReferenceError。

例子:

console.log(e); // ReferenceError: Cannot access 'e' before initialization
let e = 15;

3. 重新賦值

(1) var和let:

這兩個(gè)關(guān)鍵字聲明的變量都可以被重新賦值。

例子:

var f = 1;
f = 2; // 可以重新賦值
console.log(f); // 2

let g = 3;
g = 4; // 可以重新賦值
console.log(g); // 4

(2) const:

聲明的變量不能被重新賦值,必須在聲明時(shí)初始化。

例子:

const h = 5;
h = 6; // TypeError: Assignment to constant variable.

4. 常量和可變性

const:

用于聲明常量,但這只意味著變量的引用不可以被改變。如果 const 聲明的是一個(gè)對(duì)象或數(shù)組,可以修改其屬性或元素。

例子:

const obj = { name: 'Alice' };
obj.name = 'Bob'; // 允許,修改對(duì)象的屬性
console.log(obj.name); // Bob

5. 總結(jié)

  • var: 函數(shù)作用域、提升、可以重復(fù)聲明和賦值。
  • let: 塊級(jí)作用域、提升、可以賦值,但不能重復(fù)聲明。
  • const: 塊級(jí)作用域、提升、不能重新賦值,聲明時(shí)必須初始化。

十一、const的原理是什么?為什么不能改變

const 是 JavaScript 中用于聲明常量的關(guān)鍵字,其原理和行為主要與塊級(jí)作用域和引用類型有關(guān)。以下是對(duì) const 的詳細(xì)解釋:

1. 塊級(jí)作用域

const 聲明的變量具有塊級(jí)作用域。這意味著它們只在定義它們的代碼塊內(nèi)有效。例如,在一個(gè) if 語句或循環(huán)內(nèi)聲明的 const 變量不能在其外部訪問。

{
  const x = 10;
}
console.log(x); // ReferenceError: x is not defined

2. 不可重新賦值

const 聲明的變量不能被重新賦值。這并不是說變量本身是不可變的,而是說變量的引用(地址)是不可變的。也就是說,您不能將一個(gè) const 變量重新指向一個(gè)新的值。

const y = 20;
y = 30; // TypeError: Assignment to constant variable.

3. 引用類型的可變性

如果 const 聲明的是一個(gè)對(duì)象或數(shù)組,您可以修改其屬性或元素,但不能改變其引用。這意味著您可以對(duì)對(duì)象的內(nèi)容進(jìn)行修改,但不能將該對(duì)象指向另一個(gè)對(duì)象。

const obj = { name: 'Alice' };
obj.name = 'Bob'; // 允許,修改對(duì)象的屬性
console.log(obj.name); // Bob

obj = { name: 'Charlie' }; // TypeError: Assignment to constant variable.

4. 原理解析

const 的原理在于 ECMAScript 的變量綁定機(jī)制。聲明一個(gè) const 變量時(shí),它會(huì)創(chuàng)建一個(gè)綁定到該值的不可更改的引用。以下是這一機(jī)制的詳細(xì)解讀:

  • 綁定:當(dāng)您使用 const 聲明一個(gè)變量時(shí),實(shí)際上是將該變量與一個(gè)值綁定在一起。這個(gè)綁定是固定的,您不能改變它。
  • 作用域:const 聲明的變量?jī)H在聲明時(shí)的塊內(nèi)有效,并在退出該塊后被銷毀。
  • 不可重新賦值:一旦綁定建立,就不能再將該變量指向另一個(gè)值(即不可重新賦值)。

5. 總結(jié)

const 聲明的是一個(gè)不可重新賦值的變量,但它的值(如果是對(duì)象或數(shù)組)可以是可變的。

這種設(shè)計(jì)使得 const 適用于需要保護(hù)不被重新分配的變量,同時(shí)仍允許對(duì)其內(nèi)部狀態(tài)進(jìn)行修改的場(chǎng)景。

責(zé)任編輯:趙寧寧 來源: 程序員Sunday
相關(guān)推薦

2013-04-16 10:36:41

Gartner云安全

2013-09-02 14:56:02

開發(fā)者工具前段工具后端工具

2022-06-14 10:41:23

CSS前端

2015-07-03 15:09:15

2024-09-20 09:30:44

2015-05-08 08:22:27

2011-11-17 14:27:51

并購2011

2020-03-04 14:10:14

戴爾

2015-04-07 15:58:51

2012-07-02 10:09:09

imo即時(shí)通訊

2019-11-29 08:00:00

技術(shù)研發(fā)技能

2013-05-02 09:15:15

2012-08-06 12:56:51

imo即時(shí)通訊

2013-09-02 10:22:28

開發(fā)者工具

2020-09-08 07:01:01

調(diào)度算法

2010-02-25 15:39:23

2011-09-22 13:34:03

3G

2013-02-26 08:57:17

AWS亞馬遜Rackspace
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)