首页
归档
笔记
树洞
搜索
友言

文章详情

Interesting People Record Interesting.

/ JavaScript / 文章详情

前端常考面试题

Sonder
2023-06-08
4074字
10分钟
浏览 (1.2k)

原型和原型链

说一下什么是原型

每个函数都有一个特殊属性,那就是prototype。就像是打印了以下函数

复制代码
function person(){}
console.log(person.prototype)

显示出了函数所有的原型

image.png

那什么是原型链呢

所有对象都是由原型对象继承而来的,而原型对象本身也是一个对象,它也有自己的对象,这样层层上溯,就形成了原型链。原型链的最低端是null,因为null是没有对象的

复制代码
const person = { name: 'ExMaterial', age: 20 };

console.log(person);  // { name: 'ExMaterial', age: 20 }
console.log(person.toString());  // [object Object]

那原型和原型链存在的意义是什么?

实例对象可以共享构造函数的方法和属性,节省内存。构造函数原型上的方法和属性越多,节省内存就越大

复制代码
function person(name, age) {
   this.name = name;
   this.age = age;
}
person.prototype.eating = function() {
   return this.name + " is eating."
}
person.prototype.running = function() {
   return this.name + " is running."
}

const p1 = new person('ExMaterial', 20)
console.log(p1.eating());  // ExMaterial is eating.

如何理解作用域和作用域链?

什么是作用域?

作用域就是函数里面定义的变量,不能直接从外面访问变量值

复制代码
function scope() {
 var insideVariable = 'insideVariable';
}
scope();
console.log(inVariable); // Uncaught ReferenceError: inVariable is not defined

在ES6之后,作用域可分为以下三种:

全局作用域

复制代码
// 全局变量
var greeting = 'Hello World!';
function greet() {
 console.log(greeting);
}
// 打印 'Hello World!'
greet();

函数作用域

复制代码
function greet() {
 var greeting = 'Hello World!';
 console.log(greeting);
}
// 打印 'Hello World!'
greet();
// 报错: Uncaught ReferenceError: greeting is not defined
console.log(greeting);

块级作用域

复制代码
{
 // 块级作用域中的变量
 let greeting = 'Hello World!';
 var lang = 'English';
 console.log(greeting); // Prints 'Hello World!'
}
// 变量 'English'
console.log(lang);
// 报错:Uncaught ReferenceError: greeting is not defined
console.log(greeting);

什么是作用域链?

一层一层的作用域嵌套关系就是作用域链,直接说就是函数里面套函数

复制代码
var a = 100;
function globalFunc(){
 var b = 200;
 function currentFunc(){
   var c = 300;
   console.1og(a)://全局作用域的变量
 }
 currentFunc();
}
globalFunc();

你对闭包怎么理解?

什么是闭包

能够访问其他函数内部变量的函数,被称为闭包

复制代码
function closure() {
   var name = 'Mozilla';
   function displayName() {
       console.log(name);
   }
   return displayName;
}
var myFunc = closure();
myFunc();

闭包存在什么问题?

优点:

  1. 避免全局变量的污染
  2. 一个变量长期存储在内存中(缓存变量)
  3. 环境私有化,方法都是孤立的

缺点:

  1. 内存泄露(消耗)
  2. 常驻内存,增加内存使用量

来看下面一段代码:

复制代码
function foo() {
   var a = 3;
   function result() {
       console.log(a);
   }
   return result;
}
var test = foo();
test();

上述代码中,理论上来说,foo函数作用域隔绝了外部环境,所有变量引用都在函数内部完成,foo运行完成以后,内部的变量就应该被销毁,内存被回收。然而闭包导致了全局作用域始终存在一个test的变量在引用着foo内部的result函数,这就意味着foo内部定义的result函数引用数始终为3,垃圾运行机制就无法把它销毁这就是我们说的闭包本身会造成内部变量常驻内存。

谈谈对 this 对象的理解?

  1. this 总是指向函数的直接调用者(而非间接调用者)
  2. 如果有 new 关键字,this 指向 new 出来的那个对象
  3. 箭头函数的 this 是指向外部上下文的 this

如何来修改 this 指向

bind、apply 和 call 可以修改指向。使用某个上下文调用该函数,使用 .bind()。 如果要立即调用函数,使用.call().apply(),并修改上下文。

复制代码
const mbs = {
 name: '麻不烧',
 say(prefix, age) {
   console.log(`${prefix},my name is ${this.name},i am ${age} year old`)
 }
}

const A = {
 name:'小丁'
}

mbs.say.call(A,'hello',3) // 'hello,my name is 小丁,i am 3 year old'

浅拷贝和深拷贝

浅拷贝地址还是指向原来那个内存地址,深拷贝是重新开辟一个内存地址

深拷贝JSON.parse(JSON.stringify())有什么缺点,如何解决呢

js关键字有丢失,比如functionnull正则表达式

解决方法:循环对象,把对象的 KEY 和 VALUE 存放到一个新的变量里面

复制代码
   function deepClone(source) {
       const targetObj = source.constructor === Array ? [] : {};
       for (keys in source) {
           if(source.hasOwnProperty(keys)) {
               // 数组和对象
               if(source[keys] && typeof source[keys] === 'object') {
                   // targetObj[keys] = targetObj[keys] === Array ? [] : {}; // 只是为了可读性,可要可不要
                   targetObj[keys] = deepClone(source[keys]);
               } else {
                   // 基本类型
                   targetObj[keys] = source[keys];
               }
           }
       }
       return targetObj;
   }

js的基本类型和引用类型有哪些

基本数据类型指的是简单的数据段,有5种,包括null、undefined、string、boolean、number;

引用数据类型指的是有多个值构成的对象,包括object、array、date、regexp、function等。

vue3对比vue2的优势

  • 响应式系统,proxy 替代 Object.defineProperty 监听对象,监听对象不需要再深度遍历,proxy可劫持整个对象。Proxy 返回的是一个新对象,而 Object.defineProperty 只能遍历对象属性直接修改。
  • 体积包减少

说一下 vue2 的响应式原理

vue数据双向绑定是通过数据劫持结合发布者-订阅者模式的方式来实现的。利用了 Object.defineProperty() 这个方法重新定义了对象获取属性值(get)和设置属性值(set)。

下一篇 / 【源代码】分享一些好看的404页面

🎯 相关文章

💡 推荐文章

🕵️‍♂️ 评论 (0)