Maison >interface Web >js tutoriel >Partage de questions de connaissances de base d'entrevue JavaScript

Partage de questions de connaissances de base d'entrevue JavaScript

小云云
小云云original
2018-02-12 15:21:543326parcourir

Partage de questions de connaissances de base d'entrevue JavaScript

Selon l'enquête StackOverflow, JavaScript est le langage de programmation le plus populaire depuis 2014. Bien sûr, c'est raisonnable, après tout, 1/3 du travail de développement nécessite des connaissances en JavaScript. Par conséquent, si vous souhaitez devenir développeur, vous devez apprendre ce langage.

L'objectif principal de ce blog est de résumer les concepts communs à toutes les interviews afin que vous puissiez les comprendre rapidement. (Etant donné que cet article est trop long pour faciliter la lecture, il sera divisé en trois blogs pour traduction. Ceci est la troisième partie. Pour la première partie, veuillez cliquer sur Maîtriser rapidement les bases des entretiens JavaScript (1))

Articles connexes recommandés :La collection la plus complète de questions d'entretien js en 2020 (dernière)

nouveaux mots-clés

Si vous utilisez le mot-clé new pour appeler une fonction d'une manière très particulière. Nous appelons ces fonctions appelées avec new fonctions constructeur.

Que fait exactement la fonction utilisant new ?

  • Créer un nouvel objet

  • Définir le prototype de l'objet sur le prototype du constructeur

  • Exécuter le constructeur, thisexécute l'objet nouvellement construit

  • renvoie l'objet. Si le constructeur renvoie un objet, alors l'objet construit est renvoyé.

// 为了更好地理解底层,我们来定义new关键字
function myNew(constructor, ...arguments) {
  var obj = {}
  Object.setPrototypeOf(obj, constructor.prototype);
  return constructor.apply(obj, arguments) || obj
}

Quelle est la différence entre utiliser new et ne pas l'utiliser ?

function Bird() {
  this.wings = 2;
}
/* 普通的函数调用 */
let fakeBird = Bird();
console.log(fakeBird);    // undefined
/* 使用new调用 */
let realBird= new Bird();
console.log(realBird)     // { wings: 2 }

Afin de faciliter la comparaison et la compréhension, le traducteur a ajouté une situation de test supplémentaire :

function MBird(){
  this.wings =2; 
  return "hello";
}

let realMBrid = new MBird();
console.log(realMBird) // { wings: 2 }

Vous constaterez que cette phrase return "hello" ne prend pas effet !

Prototype et héritage

Le prototype est le concept le plus déroutant en JavaScript. L'une des raisons est que prototype peut être utilisé dans deux situations différentes.

  • Relation prototype
    Chaque objet a un prototype objet, qui contient toutes les propriétés de son prototype.
    .__proto__ est un mécanisme informel (fourni dans ES6) utilisé pour obtenir le prototype d'un objet. Vous pouvez le comprendre car il pointe vers le parent de l'objet.
    Tous les objets ordinaires héritent de l'attribut .constructor, qui pointe vers le constructeur de l'objet. Lorsqu'un objet est implémenté via un constructeur, l'attribut __proto__ pointe vers le .prototype du constructeur du constructeur. Object.getPrototypeOf() est une fonction standard d'ES5, utilisée pour obtenir le prototype d'un objet.

  • Propriétés du prototype
    Chaque fonction possède une propriété .prototype, qui contient toutes les propriétés pouvant être héritées. Par défaut, cet objet contient un attribut .constructor pointant vers le constructeur d'origine. Chaque objet créé à l'aide d'un constructeur possède une propriété constructeur.

Ce qui suit est un exemple pour aider à comprendre :

function Dog(breed, name){
  this.breed = breed,
  this.name = name
}
Dog.prototype.describe = function() {
  console.log(`${this.name} is a ${this.breed}`)
}
const rusty = new Dog('Beagle', 'Rusty');

/* .prototype 属性包含了构造函数以及构造函数中在prototype上定义的属性。*/
console.log(Dog.prototype)  // { describe: ƒ , constructor: ƒ }

/* 使用Dog构造函数构造的对象 */
console.log(rusty)   //  { breed: "Beagle", name: "Rusty" }
/* 从构造函数的原型中继承下来的属性或函数 */
console.log(rusty.describe())   // "Rusty is a Beagle"
/* .__proto__ 属性指向构造函数的.prototype属性 */
console.log(rusty.__proto__)    // { describe: ƒ , constructor: ƒ }
/* .constructor 属性指向构造函数 */
console.log(rusty.constructor)  // ƒ Dog(breed, name) { ... }

L'utilisation de JavaScript peut être considérée comme assez flexible afin d'éviter les bugs. , autant accepter Enter Fundebug pour une surveillance en ligne en temps réel.

Chaîne de prototypes

La chaîne de prototypes fait référence à des objets qui sont liés via des prototypes pour former une chaîne dirigée. Lors de l'accès à une propriété d'un objet, le moteur JavaScript vérifiera d'abord si l'objet contient la propriété. Sinon, vérifiez s'il est inclus dans le prototype de l'objet. Et ainsi de suite jusqu'à ce que la propriété soit trouvée ou que le dernier objet soit trouvé. Le prototype du dernier objet est par défaut nul.

Posséder ou hériter

Un objet a deux types de propriétés, qui sont ses propres propriétés définies et héritées.

function Car() { }
Car.prototype.wheels = 4;
Car.prototype.airbags = 1;

var myCar = new Car();
myCar.color = 'black';

/*  原型链中的属性也可以通过in来查看:  */
console.log('airbags' in myCar)  // true
console.log(myCar.wheels)        // 4
console.log(myCar.year)          // undefined

/*  通过hasOwnProperty来查看是否拥有该属性:  */
console.log(myCar.hasOwnProperty('airbags'))  // false — Inherited
console.log(myCar.hasOwnProperty('color'))    // true

Object.create(obj) crée un nouvel objet avec un prototype pointant vers obj.

var dog = { legs: 4 };
var myDog = Object.create(dog);

console.log(myDog.hasOwnProperty('legs'))  // false
console.log(myDog.legs)                    // 4
console.log(myDog.__proto__ === dog)       // true

L'héritage est passé par référence

Les propriétés héritées sont toutes transmises par référence. Comprenons-le clairement à travers des exemples :

var objProt = { text: 'original' };
var objAttachedToProt = Object.create(objProt);
console.log(objAttachedToProt.text)   // original

// 我们更改objProt的text属性,objAttachedToProt的text属性同样更改了
objProt.text = 'prototype property changed';
console.log(objAttachedToProt.text)   // prototype property changed

// 但是如果我们讲一个新的对象赋值给objProt,那么objAttachedToProt的text属性不受影响
objProt = { text: 'replacing property' };
console.log(objAttachedToProt.text)   // prototype property changed

Héritage classique vs héritage prototypique

L'article d'Eric Elliott a une introduction très détaillée : Maîtrisez l'interview JavaScript : quelle est la différence entre l'héritage de classe et l'héritage prototypique ?
L'auteur estime que l'héritage prototypique est supérieur à l'héritage classique et propose une introduction vidéo : https://www.youtube.com/watch...

JavaScript asynchrone

JavaScript est un langage de programmation monothread, ce qui signifie que le moteur JavaScript ne peut exécuter qu'un certain morceau de code à la fois. Le problème que cela provoque est le suivant : si un morceau de code prend beaucoup de temps à s’exécuter, les autres opérations seront bloquées. JavaScript utilise Call Stack pour enregistrer les appels de fonction. Une Call Stack peut être considérée comme une pile de livres. Le dernier livre est placé dessus et est retiré en premier. Les livres placés en premier se trouvent en bas et sont retirés en dernier.

Afin d'éviter que du code complexe n'occupe le CPU trop longtemps, une solution consiste à définir une fonction de rappel asynchrone. Définissons nous-mêmes une fonction asynchrone :

function greetingAsync(name, callback){
  let greeting = "hello, " + name ;
  setTimeout(_ => callback(greeting),0);
}

greetingAsync("fundebug", console.log);
console.log("start greeting");

我们在greetingAsync中构造了greeting语句,然后通过setTimeout定义了异步,callback函数,是为了让用户自己去定义greeting的具体方式。为方便起见,我们时候直接使用console.log
上面代码执行首先会打印start greeting,然后才是hello, fundebug。也就是说,greetingAsync的回调函数后执行。在网站开发中,和服务器交互的时候需要不断地发送各种请求,而一个页面可能有几十个请求。如果我们一个一个按照顺序来请求并等待结果,串行的执行会使得网页加载很慢。通过异步的方式,我们可以先发请求,然后在回调中处理请求结果,高效低并发处理。

下面通过一个例子来描述整个执行过程:

const first = function () {
  console.log('First message')
}
const second = function () {
  console.log('Second message')
}
const third = function() {
  console.log('Third message')
}

first();
setTimeout(second, 0);
third();

// 输出:
  // First message
  // Third message
  // Second message
  1. 初始状态下,浏览器控制台没有输出,并且事件管理器(Event Manager)是空的;

  2. first()被添加到调用栈

  3. console.log("First message")加到调用栈

  4. console.log("First message")执行并输出“First message”到控制台

  5. console.log("First message")从调用栈中移除

  6. first()从调用栈中移除

  7. setTimeout(second, 0)加到调用栈

  8. setTimeout(second, 0)执行,0ms之后,second()被加到回调队列

  9. setTimeout(second, 0)从调用栈中移除

  10. third()加到调用栈

  11. console.log("Third message")加到调用栈

  12. console.log("Third message")执行并输出“Third message”到控制台

  13. console.log("Third message")从调用栈中移除

  14. third()从调用栈中移除

  15. Event Loop 将second()从回调队列移到调用栈

  16. console.log("Second message")加到调用栈

  17. console.log("Second message")Second message”到控制台

  18. console.log("Second message")从调用栈中移除

  19. Second()从调用栈中移除

特别注意的是:second()函数在0ms之后并没有立即执行,你传入到setTimeout()函数的时间和second()延迟执行的时间并不一定直接相关。事件管理器等到setTimeout()设置的时间到期才会将其加入回调队列,而回调队列中它执行的时间和它在队列中的位置已经它前面的函数的执行时间有关。

相关学习推荐:javascript视频教程

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn