No78.精选前端面试题,享受每天的挑战和学习

简介: No78.精选前端面试题,享受每天的挑战和学习

1px边框问题怎么解决的

在实际开发中,1px边框问题指的是在高分辨率屏幕上显示为模糊或厚度不一致的边框。这是由于高分辨率屏幕的设备像素比(device pixel ratio)较大,导致以传统1个物理像素宽度定义的边框在显示中被缩放并且不再保持细腻的外观。

有几种常见的解决方案可以解决1px边框问题:

  1. 使用CSS的 border-widthborder-image 属性:可以使用 border-width: 1px; 并结合 border-image 属性来创建细腻且一致的边框效果。
.element {
  border-width: 1px;
  border-style: solid;
  border-image: linear-gradient(to right, transparent, rgba(0, 0, 0, 0.5), transparent);
}
  1. 使用像素单位加倍:可以将边框宽度设置为2px,并结合 transform: scale(0.5); 缩小元素的一半大小来模拟1px边框效果。
.element {
  border-width: 2px;
  transform: scale(0.5);
  transform-origin: top left;
}
  1. 使用伪元素并进行缩放:可以使用伪元素来创建额外的边框,并将其缩小一半大小来模拟1px边框。
.element {
  position: relative;
}
.element::after {
  content: "";
  position: absolute;
  left: 0;
  top: 0;
  right: 0;
  bottom: 0;
  border: 1px solid;
  transform: scale(0.5);
  transform-origin: top left;
}

这些解决方案都可以在高分辨率屏幕上创建更细腻和一致的1px边框效果。具体选用哪种方法取决于具体需求和实现环境。

手写一个new

当你使用 new 关键字创建一个对象时,实际上发生了以下几个步骤:

  1. 创建一个空对象。
  2. 将新创建的对象的原型链指向构造函数的原型对象。
  3. 将构造函数的执行上下文指向新创建的对象。
  4. 使用新创建的对象作为构造函数的执行上下文来执行构造函数,并获取返回值。
  5. 如果构造函数的返回值是一个对象,则返回该对象;否则,返回新创建的对象。

下面是一个简单的手写实现 new 的示例:

function myNew(constructor, ...args) {
  // 创建一个空对象,指定原型链为构造函数的原型对象
  const obj = Object.create(constructor.prototype);
  // 使用新对象作为构造函数的执行上下文来执行构造函数
  const result = constructor.apply(obj, args);
  // 如果构造函数返回的是一个对象,则返回该对象
  if (typeof result === 'object' && result !== null) {
    return result;
  }
  // 否则返回新对象
  return obj;
}

使用示例:

function Person(name) {
  this.name = name;
}
Person.prototype.sayHello = function() {
  console.log('Hello, ' + this.name);
};
const john = myNew(Person, 'John');
john.sayHello(); // 输出: Hello, John

在上述示例中,我们定义了一个 Person 构造函数,然后使用 myNew 实现了一个简单的 new 方法。通过调用 myNew(Person, 'John'),我们创建了一个 Person 的实例对象 john,并成功调用了 sayHello 方法。

组合寄生解决了组合继承的什么问题

组合寄生式继承是一种继承模式,它可以解决组合继承中的一个问题,即避免了在调用父类构造函数时多次执行父类的构造逻辑。

组合继承是指将原型链继承和借用构造函数继承结合起来的一种继承方式。

它通过使用 Object.create 方法继承父类的原型,并在子类构造函数内部通过调用父类构造函数来继承父类的实例属性。

这样做的结果是,每当创建子类的实例时,都会调用两次构造函数:

  • 一次是在继承父类原型时调用
  • 一次是在子类构造函数内部调用。

而组合寄生式继承则通过创建一个中间对象来解决这个问题。

它使用 Object.create 方法继承父类的原型,并将该中间对象作为子类原型的原型。

然后,通过调用父类构造函数来继承父类的实例属性。

这样一来,在创建子类的实例时,只需要调用一次构造函数,即在子类构造函数内部调用父类构造函数。

这样就避免了多次执行父类的构造逻辑,提高了性能效率。

下面是一个利用组合寄生式继承的示例:

function Parent(name) {
  this.name = name;
}
Parent.prototype.sayHello = function() {
  console.log('Hello, ' + this.name);
};
function Child(name, age) {
  Parent.call(this, name); // 继承父类的实例属性
  this.age = age;
}
// 继承父类的原型
Child.prototype = Object.create(Parent.prototype);
Child.prototype.constructor = Child; // 指定子类的构造函数
Child.prototype.sayAge = function() {
  console.log('I am ' + this.age + ' years old');
};
const child = new Child('John', 21);
child.sayHello(); // 输出: Hello, John
child.sayAge(); // 输出: I am 21 years old

在上述示例中,Child 构造函数使用 Parent.call(this, name) 继承了父类 Parent 的实例属性,而 Child.prototype 使用 Object.create(Parent.prototype) 继承了父类的原型。通过这样的继承方式,子类的实例既拥有了父类的实例属性,也能够使用父类的原型方法,同时避免了调用父类构造函数的重复执行。

原型链讲一下,__proto__是标准吗

原型链是 JavaScript 中实现对象继承的一种机制。每个对象都有一个内部属性 [[Prototype]](也称为 __proto__)。通过原型链,对象可以从其原型对象(也可以是其他对象的原型对象)继承属性和方法。

当访问对象的属性或方法时,如果对象本身没有该属性或方法,JavaScript 引擎会沿着对象的原型链依次查找,直到找到该属性或方法或者到达原型链的末端(即 null)为止。这个查找过程可以形成一个链状结构,即原型链。

可以使用 Object.setPrototypeOf(obj, prototype) 方法来动态修改一个对象的原型,或者使用字面量方式创建对象时使用 Object.create(proto) 来指定对象的原型。此外,ES6 引入了 classextends 关键字,也提供了更简便的方式来实现对象之间的继承。

关于 __proto__,在 ES6 标准中,它被标识为非标准的原型访问方式。尽管大多数现代浏览器对于 __proto__ 提供了支持,但它并不被推荐使用,因为它不是标准规范的一部分。为了更加规范和可靠地访问对象的原型,可以使用 Object.getPrototypeOf(obj) 方法来获取对象的原型,使用 Object.setPrototypeOf(obj, prototype) 方法来设置对象的原型。

以下是一个使用原型链的简单示例:

// 创建一个原型对象
const animal = {
  type: 'unknown',
  sound: function() {
    console.log('The ' + this.type + ' makes a sound.');
  }
};
// 创建一个继承自原型对象的子对象
const dog = Object.create(animal);
dog.type = 'dog';
dog.bark = function() {
  console.log('The dog barks.');
};
// 调用继承自原型的方法
dog.sound(); // 输出: The dog makes a sound.
dog.bark(); // 输出: The dog barks.

在上述示例中,dog 对象继承自 animal 对象,并且它们之间形成了原型链关系。dog 对象可以访问原型对象 animal 的属性和方法,比如调用了 sound 方法。

相关文章
|
26天前
|
存储 XML 移动开发
前端大厂面试真题
前端大厂面试真题
|
9天前
|
网络协议 算法 数据库
|
27天前
|
前端开发 Java 编译器
【前端学java】如何从前端视角快速学习Maven
【8月更文挑战第12天】如何从前端视角快速学习Maven
39 2
【前端学java】如何从前端视角快速学习Maven
|
28天前
|
前端开发 JavaScript API
前端框架Vue------>第二天学习(1)插槽
这篇文章介绍了Vue框架中插槽(slot)的概念和用法,以及如何在组件中使用自定义事件进行父子组件间的通信。
前端框架Vue------>第二天学习(1)插槽
|
14天前
|
前端开发 算法 网络协议
如何学习计算机基础知识,打好前端和网络安全的基础
如何学习计算机基础知识,打好前端和网络安全的基础
28 4
|
22天前
|
存储 前端开发 JavaScript
44 个 React 前端面试问题
【8月更文挑战第18天】
23 2
|
22天前
|
存储 JavaScript 前端开发
2022年前端js面试题
2022年前端js面试题
19 0
|
24天前
|
存储 前端开发 JavaScript
44 个 React 前端面试问题
44 个 React 前端面试问题
|
27天前
|
前端开发 JavaScript
前端网站学习大全
这篇文章提供了前端网站开发学习的资源大全,涵盖了HTML常用标签和CSS常用样式,以及如何使用`<meta>`标签提供页面元信息和`lang`属性定义内容语言等基础知识。
前端网站学习大全
|
28天前
|
前端开发 JavaScript
前端框架Vue------>第三天学习(1)
这篇文章介绍了Vue框架的组件基础和计算属性的概念,通过示例代码展示了如何定义可复用的Vue组件和使用计算属性来声明性地描述依赖其他值的数据。