近日的一些前端笔试题【01】

181 阅读11分钟

最近笔试的时候,遇到一些常考的前端知识点,这里总结一下,方便回顾复习。

1. CSS中可以继承的属性?

不可继承属性子元素继承属性列表元素可以继承表格元素可以继承都可以继承属性
display、margin、padding、border、background、width、height、overflow、position系列、float、clear、table-layout、vertical-align、page-bread-before/after、unicode-bidiletter-spacing、word-spacing、white-space、line-height、color、font系列、text-decoration、text-transform、direction、text-indent、text-alignlist-style系列border-collapsevisibility、cursor

对于不可继承的属性,如果希望子元素可以保持和父元素一致,可以将该属性值设置为inherit

    border: inherit;

2. sessionStorage数据共享

    localStorage存储的数据能够在客户端本地永久保存。 同域的任何页面都可以访问到localStorage存储的数据。但sessionStorage与localStorage有着较大的不同,简述如下:

  • sessionStorage受到同源策略限制。
  • sessionStorage存储数据还受到浏览器选项卡的限制。
  • 手动新开一个选项卡,即便同域同URL,也不会共享sessionStorage数据。
  • 当前选项卡关闭,sessionStorage中存储的数据也随之被销毁。

数据共享方式:

首先要明确一个概念,在新选项卡或者窗口打开一个新的页面,会新创建一个sessionStorage会话。 手动新开一个选项卡,即便同域同URL,也不会共享Sessionstorage数据。但是并不是说就没有办法共享sessionStorage存储的数据,准确的说不是共享,而是拷贝一份。

  • 通过手动方式新开一个选项卡或者窗口不会共享数据。
  • 通过JavaScript或者链接标签打开同源页面会共享数据(准确说是拷贝一份),两者是独立的。

假设A页面通过sessionStorage存储一些数据,页面中有一个链接指向同源的B页面。 点击链接,在新的选项卡打开B页面,那么A页面的数据会被B页面共享(事实是拷贝了一份)。 两个页面的数据是相互独立的,在B页面删除一条记录,并不会影响A页面中的数据。

3. img标签中title属性和alt属性?

alt 属性(图片描述):

图片加载不出来的时候,就会在图片未显示的地方出现一段 alt 设置的属性内容。【这个属性的作用是为了给未加载的图片显示提示信息,即使在网络比较差的时候,用户也可以知道图片的内容,从而方便用于浏览网页,同时程序员对网站维护的时候也能更快地查找问题。】 浏览器的搜索引擎可以通过 alt 属性的文字描述来获取图片。

title 属性(图片解释说明):

title 属性可以用在任何元素上,当用户把鼠标移动到元素上时,就会显示预先设置的 title 的内容,起到对图片说明的作用,实际上就是对图片的解释和备注。

1. img 标签中引用的图片不论是否正常显示,图片只设置 title 属性之后,当鼠标经过或者悬停在图片区域时,就能看到图片的文字描述。

2. 当图片仅仅设置 alt 属性的时候。当鼠标悬停或者经过图片区域的时候,可以看到该图片设置的 alt 属性的文字内容。

3. 如果图片设置了 title 和 alt 两个属性,鼠标悬停或者经过图片区域的时候,只会显示 title 属性设置的内容。

4. CSS 盒子模型中()是透明的,这部分可以显示背景()

A、padding

B、margin

C、border

D、content

参考答案:A

答案解析:

Margin(外边距) 清除边框外的区域,外边距是透明的。

Border(边框) - 围绕在内边距和内容外的边框。

Padding(内边距) - 清除内容周围的区域,内边距是透明的。

Content(内容) - 盒子的内容,显示文本和图像。

margin 清除周围的元素(外边框)的区域。margin 没有背景颜色,是完全透明的。

Padding(填充), 当元素的Padding(填充)(内边距)被清除时,所"释放"的区域将会受到元素背景颜色的填充。

5. 进程与线程的关系?

  • 进程是资源分配的基本单位,线程是CPU调度和分派的基本单位

  • 线程是进程的一部分,一个线程只能属于一个进程,一个进程可以有多个线程,但至少有一个线程

  • 每个进程都有独立的代码和数据空间(程序上下文),程序间的切换开销大,

  • 线程可看做轻量级的进程,同一类线程共享代码和数据空间,每个线程都有自己独立的运行栈和程序计数器(PC),线程间切换开销小

  • 在操作系统中能同时运行多个进程(程序)在同一个进程(程序)中多个线程同时执行(通过CPU调度,在每个时间片中只有一个线程执行)

  • 系统在运行的时候会为每个进程分配不同的内存空间线程除了CPU外,系统不会为线程分配内存(线程所使用的资源来自其所属进程的资源),线程组之间只能共享资源

  • 两者都是多任务编程的方式,都能够使用计算机的多核

  • 进程的创建删除要比线程消耗更多的计算机资源

  • 线程使用全局变量通信,更加简单,但是需要同步互斥操作

  • 进程线程都独立执行,有自己的特有资源如属性,id, 命令集等

  • 线程可以创建线程

6. 跨域的方式?

  • 利用HTML5 postMessage
  • 利用document.domain + frame的设置
  • 通过服务器Nginx配置跨域
  • 利用iframe + location.hash
  • windows.name实现跨域数据传输

7. visiblity:hiddendisplay:none的区别?

作用不同:

  • visibility:hidden将元素隐藏,但是在网页中该占的位置还是占着。
  • display:none将元素的显示设为无,即在网页中不占任何的位置。

使用后HTML元素有所不同:

  • visibility:hidden,使用该属性后,HTML元素(对象)仅仅是在视觉上看不见(完全透明),而它所占据的空间位置仍然存在,也即是说它仍具有高度、宽度等属性值。
  • display:none,使用该属性后,HTML元素(对象)的宽度、高度等各种属性值都将“丢失”。

定义不同:

  • visibility属性指定一个元素是否是可见的。
  • display这个属性用于定义建立布局时元素生成的显示框类型。

8. Vue的事件修饰符?

  • prevent:阻止默认事件(常用)

      <!-- 阻止默认事件(常用) -->
      <a href="http://www.atguigu.com" @click.prevent="showInfo">点我提示信息</a>
    

    a标签的默认有跳转到href的行为,我们把默认行为禁用后,就不会跳转页面

  • stop:阻止事件冒泡(常用)

      <div class="demo1" @click="showInfo">
          <button @click.stop="showInfo">点我提示信息</button>
          <!-- 修饰符可以连续写 -->
           <a href="http://www.atguigu.com" @click.prevent.stop="showInfo">点我提示信息</a> 
      </div>
    
  • once:事件只触发一次(常用)

      <button @click.once="showInfo">点我提示信息</button>
    
  • capture:使用事件的捕获模式

      <div class="box1" @click.capture="showMsg(1)">
          div1
          <div class="box2" @click="showMsg(2)">
              div2
          </div>
      </div>
    
  • self:只有event.target是当前操作的元素时才触发事件

   <div class="demo1" @click.self="showInfo">
       <button @click="showInfo">点我提示信息</button>
   </div>

9. javaScript与客户端交互是基于事件驱动的

10. History 对象是 window 对象的一部分,可通过 window.history 属性对其进行访问

11. Vue中通过ref属性获取DOM

12. npm包管理器是基于Node.js平台使用的

13. 看题说输出

function A(cName) {
  if (cName) {
    this.name = cName;
  }
}
A.prototype.name = 'dingding';
let a = new A();
console.log('A', a.name); // 当你给A原型上加name属性,new出来的实例就可以访问得到。

function B(cName) {
  this.name = cName;
}
B.prototype.name = 'ylai';
let b = new B();
console.log('B', b.name); // B new出来的实例身上本书有name,所以不会再顺着原型链往上找了
// // A dingding B ylai

14 看题说输出2

function Foo() {
    //这里的getName没有var关键字,定义的是一个全局变量
    getName = function () {
      console.log(1);
    };
    // this的默认绑定,返回的是window
    return this;
}
// 给Foo定义一个getName静态属性存储了一个匿名函数
Foo.getName = function () {
    console.log(2);
};
// 给Foo的原型定义getName方法
Foo.prototype.getName = function () {
    console.log(3);
};
// 定义全局的getName方法,函数表达式
var getName = function () {
    console.log(4);
};
// 声明一个叫getName的函数
function getName() {
    console.log(5);
}
Foo.getName(); // 2
getName(); // 4
Foo().getName(); // 1
getName(); // 1
// 关于运算符优先级的问题
new Foo.getName(); // 2
new Foo().getName(); // 3
new new Foo().getName(); // 3

此题涉及的知识点众多,包括变量定义提升、this指针指向、运算符优先级、原型、继承、全局变量污染、对象属性及原型属性优先级等等。

第一问:

首先定义了一个Foo的函数,后为Foo创建了一个叫getName的静态属性存储了一个匿名函数,之后为Foo的原型对象新创建了一个叫getName的匿名函数。之后又通过函数变量表达式创建了一个getName的函数,最后再声明一个叫getName函数。

第一问的 Foo.getName() 自然是访问Foo函数上存储的静态属性,自然是2,没什么可说的。

第二问:

直接调用 getName 函数。既然是直接调用那么就是访问当前上文作用域内的叫getName的函数,所以跟1 2 3都没什么关系。此题有无数面试者回答为5。此处有两个坑,一是变量声明提升,二是函数表达式。

函数表达式 与 函数声明 重名 会覆盖函数声明

函数表达式最大的问题,在于js会将此代码拆分为两行代码分别执行。 例如下代码:

console.log(x);//输出:function x(){}
var x=1;
function x(){}

实际执行的代码为,先将 var x=1 拆分为 var x; 和 x = 1; 两行,再将 var x; 和 function x(){} 两行提升至最上方变成:

var x;
function x(){}
console.log(x);
x=1;

所以最终函数声明的x覆盖了变量声明的x,log输出为x函数。

同理,原题中代码最终执行时的是:

function Foo() {

    getName = function () { alert (1); };

    return this;

}

var getName;//只提升变量声明

function getName() { alert (5);}//提升函数声明,覆盖var的声明

Foo.getName = function () { alert (2);};

Foo.prototype.getName = function () { alert (3);};

getName = function () { alert (4);};//最终的赋值再次覆盖function getName声明

getName();//最终输出4

第三问:

第三问的 Foo().getName(); 先执行了Foo函数,然后调用Foo函数的返回值对象的getName属性函数。

Foo函数的第一句  getName = function () { alert (1); };  是一句函数赋值语句,注意它没有var声明,所以先向当前Foo函数作用域内寻找getName变量,没有。再向当前函数作用域上层,即外层作用域内寻找是否含有getName变量,找到了,也就是第二问中的alert(4)函数,将此变量的值赋值为 function(){alert(1)}。

此处实际上是将外层作用域内的getName函数修改了。

注意:此处若依然没有找到会一直向上查找到window对象,若window对象中也没有getName属性,就在window对象中创建一个getName变量。

之后Foo函数的返回值是this,this的指向是由所在函数的调用方式决定的。而此处的直接调用方式,this指向window对象。

遂Foo函数返回的是window对象,相当于执行 window.getName() ,而window中的getName已经被修改为alert(1),所以最终会输出1

此处考察了两个知识点,一个是变量作用域问题,一个是this指向问题

第四问:

直接调用getName函数,相当于 window.getName() ,因为这个变量已经被Foo函数执行时修改了,遂结果与第三问相同,为1

第五问:

第五问 new Foo.getName(); ,此处考察的是js的运算符优先级问题。 点(.)的优先级高于new操作,相当于是:

new (Foo.getName)();

所以实际上将getName函数作为了构造函数来执行,遂弹出2

第六问:

第六问 new Foo().getName() ,首先看运算符优先级括号高于new,实际执行为

(new Foo()).getName()

先执行Foo函数,而Foo此时作为构造函数却有返回值,所以这里需要说明下js中的构造函数返回值问题。

返回的是this,而this在构造函数中本来就代表当前实例化对象,遂最终Foo函数返回实例化对象。

之后调用实例化对象的getName函数,因为在Foo构造函数中没有为实例化对象添加任何属性,遂到当前对象的原型对象(prototype)中寻找getName,找到了。

遂最终输出3。

第七问:

new new Foo().getName(); 同样是运算符优先级问题

最终实际执行为:

new ((new Foo()).getName)();

先初始化Foo的实例化对象,然后将其原型上的getName函数作为构造函数再次new。

遂最终结果为3