AI智能
改变未来

JavaScript面试题三千问—上篇


1.JavaScript的组成

  • ECMAScript(核心):JavaScript语言基础
  • DOM(文档对象模型):规定了访问 HTML 和 XML 的接口
  • BOM(浏览器对象模型):提供了浏览器窗口之间进行交互的对象和方法

2.JS 的基本数据类型和引用数据类型

  • 基本数据类型:undefined、null、bollean、number、string、symbol
  • 引用数据类型:object、array、function

3.检测浏览器版本有哪些方式?

  • 根据 navigator.userAgent // UA.toLowerCase().indexOf(‘chrome’)
  • 根据 window 对象的成员 // ‘ActiveXObject’ in window

4.介绍 JS 有哪些内置对象

  • 数据封装类对象:Object、Array、Boolean、Number、String
  • 其他对象:Function、Arhuments、Math、Date、RegExp、Error
  • ES6 新增对象:Symbol、Map、Set、Promises、Proxy、Reflect

5.JavaScript 的基本规范

  • 代码缩进,建议使用\”四个空格\”缩进
  • 代码段使用花括号 {} 包裹
  • 语句结束使用分号 ;
  • 变量和函数在使用前进行声明
  • 以大写字母开头命名构造函数,全大写命名常量
  • 规范定义 JSON 对象,补全双引号
  • 用 {} 和 [] 声明对象和数组

6.如何编写高性能的 JavaScript?

  • 遵循严格模式:“use strict”;
  • 将 js 脚本放在页面底部,加快渲染页面
  • 将 js 脚本成组打包,减少请求
  • 使用非阻塞方式下载 js 脚本
  • 尽量使用局部变量来保存全局变量
  • 尽量减少使用闭包
  • 使用 window 对象属性方法时,省略 window
  • 尽量减少对象成员嵌套
  • 缓存 DOM 节点的访问
  • 避免使用 eval() 和 Function() 构造器
  • 给 setTimeout() 和serInterval() 传递函数而不是字符串作为参数
  • 尽量使用直接量创建对象和数组
  • 最小化重绘(repaint)和回流(reflow)

7.DOM 元素的 e 和 e.getAttribute(propName) 和 e.propName 有什么区别和联系

  • e.getAttribute(),是标准 DOM 操作文档元素属性的方法,具有通用性可在任意文档上使用,返回元素在源文件中设置的属性
  • e.propName 通常是在 HTML 文档中访问特定元素的特性,浏览器解析元素后生成对应对象(如 a 标签生成HTMLAnchorElement),这些对象的特性会根据特定规则结合属性设置得到,对于没有对应特性的属性,只能使用 getAttribute 进行访问
  • e.getAttribute()返回值是源文件中设置的值,类型是字符串或者 null(有的实现返回\”\”)
  • e.propName 返回值可能是字符串、布尔值、对象、undefined 等
  • 大部分 attribute 与 property 是一一对应关系,修改其中一个会影响另一个,如 id,title 等属性
  • 一些布尔属性
    <input hidden/>

    的检测设置需要 hasAttribute 和 removeAttribute 来完成,或者设置对应 property

  • <a href=\"../index.html\">link</a>

    中 href 属性,转换成 property 的时候需要通过转换得到完整 URL

  • 一些 attribute 和 property 不是一一对应如:form 控件中
    <input value=\"hello\"/>

    对应的是 defaultValue,修改或设置 value property 修改的是控件当前值,setAttribute 修改 value 属性不会改变 value property

8.offsetWidth/offsetHeight,clientWidth/clientHeight 与 scrollWidth/scrollHeight 的区别

  • offsetWidth/offsetHeight 返回值包含 content + padding + border,效果与 e.getBoundingClientRect()相同
  • clientWidth/clientHeight 返回值只包含 content + padding,如果有滚动条,也不包含滚动条
  • scrollWidth/scrollHeight 返回值包含 content + padding + 溢出内容的尺寸

9.描述浏览器的渲染过程,DOM 树和渲染树的区别

浏览器的渲染过程:

  • 解析 HTML 构建 DOM(DOM 树),并行请求 css/image/js
  • CSS 文件下载完成后,开始构建 CSSOM(CSS 树)
  • CSSOM 构建结束后,和 DOM 一起生成 Render Tree(渲染树)
  • 布局(Layout):计算出每个节点在屏幕中的位置
  • 显示(Painting):通过显卡把页面渲染到屏幕上
    DOM 树和渲染树的区别:
  • DOM 树与 HTML 标签一一对应,包括 head 和隐藏元素
  • 渲染树不包括 head 和隐藏元素,大段文本的每一行都是独立节点,每一个节点都有对应的 css 属性

10.重绘(repaint)和回流(重排)(reflow)的区别和关系

  • 重绘:当渲染树中的元素外观(如:颜色)发生改变,不影响布局时,产生重绘
  • 回流:当渲染树中的元素的布局(如:尺寸、位置、隐藏/显示状态)发生改变时,产生重绘回流
  • 注意:JS 获取 Layout 属性值(如:offsetLeft、scrollTop、getComputedStyle 等)也会引起回流。因为浏览器需要回流计算最新值
  • 回流必将引起重绘,而重绘不一定会引起回流

11.如何最小化重绘(repaint)和回流(reflow)

  • 需要对元素集进行复杂的操作时,可以先隐藏(display:“none”),操作完成后在显示
  • 需要创建多个 DOM 节点时,使用 DocumentFragment 创建完成后一次性加入 document
  • 缓存 Layout 属性值,如:var left = elem.offsetLeft; 这样,多次使用 left 只产生一次回流
  • 尽量避免使用 css 表达式(expression),因为每次调用都会重新计算值(包括加载页面)
  • 尽量使用 css 属性简写,如:用 border 代替 border-width,border-style,border-color 批量修改元素样式

12.script 的位置是否会影响首屏显示时间

  • 在解析 HTML 生成 DOM 过程中,js 文件的下载是并行的,不需要 DOM 处理到 script 节点。因此,script 的位置不会影响首屏显示的开始时间
  • 浏览器解析 HTML 是自上而下的线性过程,script 作为 HTML 的一部分同样遵循这个原则
  • 因此,script 会延迟 DomContentLoad,只显示其上部分首屏内容,从而影响首屏显示的完成时间

13.解释 JavaScript 中的作用域与变量声明提升

JavaScript 作用域:

  • 在 Java、C 等语言中,作用域为 for 语句、if 语句或 {} 内的一块区域,称为作用域
  • 而在 JavaScript 中,作用域为 function(){} 内的区域,称为函数作用域
    JavaScript 变量声明提升:
  • 在 JavaScript 中,函数声明与变量声明经常被 JavaScript 引擎隐式的提升到当前作用域的顶部
  • 声明语句中的赋值部分并不会被提升,只要名称被提升
  • 函数声明的优先级高于变量,如果变量名跟函数名相同且未赋值,则函数声明会覆盖变量声明
  • 如果函数有多个同名参数,那么最后一个参数(即使没有定义)会覆盖前面的同名参数

14.介绍 JavaScript 的原型,原型链有什么特点

原型:

  • JavaScript 的所有对象中都包含了一个 [proto] 内部属性,这个属性所对应的就是该对象的原型
  • JavaScript 的函数对象,除了原型 [proto] 外,还预置了 prototype 属性
  • 当函数对象作为构造函数创建实例时,该 prototype 属性值将被作为实例对象的原型 [proto]

原型链:

  • 当一个对象调用的属性/方法自身不存在时,就会去自己的 [proto] 关联的前辈 prototype 对象上去找
  • 如果没找到,就回去该 prototype 原型 [proto] 关联的前辈 prototype 去找。以此类推,直到找到属性/方法或 undefined 为止。从而形成了所谓的\”原型链\”

原型特点:

  • JavaScript 对象是通过引用来传递的,当修改原型时,与之相关的对象也会继承这一改变

15.JavaScript 有几种类型的值?

  • 原始数据类型(Undefined,Null,Boolean,String) – 栈
  • 引用数据类型(对象、数组和函数) – 堆
  • 两种类型的区别是:存储位置不同
  • 原始数据类型是直接存储在栈(stack)中的简单数据段,占据空间小、大小固定,属于被频繁使用数据
  • 引用数据类型存储在堆(heap)中,占据空间大、大小不固定,如果存储在栈中,将会影响程序运行的性能
  • 引用数据类型在栈中存储了指针,该指针指向堆中该实体的起始地址
  • 当解释器寻找引用值时,会首先检索其在栈中的地址,取得地址后从堆中获得实体

16.JavaScript 如何实现一个类,怎么实例化这个类?

1.构造函数法(this + prototype) – 用 new 关键字生成实例对象
缺点:用到了 this 和 prototype,编写复杂,可读性差

function Mobile(name, price){this.name = name;this.price = price;}Mobile.prototype.sell = function(){alert(this.name + \",售价 $\" + this.price);}var iPhone7 = new Mobile(\"iPhone7\", 1000);iPhone7.sell();

2.Object.create 法 – 用 Object.create() 生成实例对象
缺点:不能实现私有属性和私有方法,实例对象之间也不能共享数据

var Person = {firstname: \"Mark\",lastname: \"Yun\",age: 25,introduce: function(){alert(\'I am \' + Person.firstname + \' \' + Person.lastname);}};var person = Object.create(Person);person.introduce();// Object.create 要求 IE9+,低版本浏览器可以自行部署:if (!Object.create) {    Object.create = function (o) {    function F() {}    F.prototype = o;    return new F();  }; }

3.极简主义法(消除 this 和 prototype) – 调用 createNew() 得到实例对象
优点:容易理解,结构清晰优雅,符合传统的\”面向对象编程\”的构造

var Cat = {age: 3, // 共享数据 -- 定义在类对象内,createNew() 外createNew: function () {var cat = {};// var cat = Animal.createNew(); // 继承 Animal 类cat.name = \"小咪\";var sound = \"喵喵喵\"; // 私有属性--定义在 createNew() 内,输出对象外cat.makeSound = function () {alert(sound);  // 暴露私有属性};cat.changeAge = function(num){Cat.age = num; // 修改共享数据};return cat; // 输出对象}};var cat = Cat.createNew();cat.makeSound();

4.ES6 语法糖 class – 用 new 关键字生成实例对象

class Point {constructor(x, y) {this.x = x;this.y = y;}toString() {return \'(\' + this.x + \', \' + this.y + \')\';}}var point = new Point(2, 3);

17.JavaScript 如何实现继承?

1.构造函数绑定:使用 call 或 apply 方法,将父对象的构造函数绑定在子对象上

function Cat(name,color){ Animal.apply(this, arguments); this.name = name; this.color = color;}

2.实例继承:将子对象的 prototype 指向父对象的一个实例

Cat.prototype = new Animal();Cat.prototype.constructor = Cat;

3.拷贝继承:把父对象的所有属性和方法,拷贝进子对象

function extend(Child, Parent) {   var p = Parent.prototype;   var c = Child.prototype;   for (var i in p) {      c[i] = p[i];   }   c.uber = p;}

4.原型继承:将子对象的 prototype 指向父对象的 prototype

function extend(Child, Parent) {var F = function(){}; F.prototype = Parent.prototype; Child.prototype = new F(); Child.prototype.constructor = Child; Child.uber = Parent.prototype;}

5.ES6 语法糖 extends:class ColorPoint extends Point {}

class ColorPoint extends Point {constructor(x, y, color) {super(x, y); // 调用父类的constructor(x, y)this.color = color;}toString() {return this.color + \' \' + super.toString(); // 调用父类的toString()}}

18.js 继承方式及其优缺点

原型链继承的缺点:

  • 字面量重写原型会中断关系,使用引用类型的原型,并且子类型还无法给超类型传递参数

借用构造函数(类式继承)

  • 借用构造函数虽然解决了刚才两种问题,但没有原型,则复用无法谈起。所有我们需要原型链 + 借用构造函数的模式,这种模式成为组合继承

组合式继承

  • 组合式继承是比较常用的一种继承方法,其背后的思路是使用原型链实现对原型属性和方法的继承,而通过构造函数来实现对实例属性的继承。这样,即通过在原型上定义方法实现了函数复用,又保证每个实例都会有他自己的属性

19.JavaScript 创建对象的几种方式

JavaScript 创建对象简单的说,就是使用内置对象或各种自定义对象,当然还可以用 JSON;但写法有很多种,也能混合使用
1.对象字面量的方式

person={firstname:\"Mark\",lastname:\"Yun\",age:25,eyecolor:\"black\"};

2.用 function 来模拟无参的构造函数

function Person(){}var person=new Person();//定义一个function,如果使用new\"实例化\",该function可以看作是一个Classperson.name=\"Mark\";person.age=\"25\";person.work=function(){alert(person.name+\" hello...\");}person.work();

3.用 function 来模拟参构造函数来实现(用 this 关键字定义构造的上下文属性)

function Pet(name,age,hobby){this.name=name;//this作用域:当前对象this.age=age;this.hobby=hobby;this.eat=function(){alert(\"我叫\"+this.name+\",我喜欢\"+this.hobby+\",是个程序员\");}}var maidou =new Pet(\"麦兜\",25,\"coding\");//实例化、创建对象maidou.eat();//调用eat方法

4.用工厂方式来创建(内置对象)

var wcDog =new Object();wcDog.name=\"旺财\";wcDog.age=3;wcDog.work=function(){alert(\"我是\"+wcDog.name+\",汪汪汪......\");}wcDog.work();

5.用原型方式来创建

function Dog(){}Dog.prototype.name=\"旺财\";Dog.prototype.eat=function(){alert(this.name+\"是个吃货\");}var wangcai =new Dog();wangcai.eat();

6.用混合方式来创建

function Car(name,price){this.name=name;this.price=price;}Car.prototype.sell=function(){alert(\"我是\"+this.name+\",我现在卖\"+this.price+\"万元\");}var camry =new Car(\"凯美瑞\",27);camry.sell();

20.JavaScript 作用域链

  • 全局函数无法查看局部函数的内部细节,但局部函数可以查看其上层的函数细节,直至全局细节
  • 如果当前作用域没有找到属性或方法,会向上层作用域查找,直至全局函数,这种形式就是作用域链

21.谈谈 this 对象的理解

  • this 总是指向函数的直接调用者
  • 如果有 new 关键字,this 指向 new 出来的实例对象
  • 在事件中,this 指向触发这个事件的对象
  • IE 下 attachEvent 中的 this 总是指向全局对象 Window

22.eval 是做什么的?

eval 的功能是把对应的字符串解析成 JS 代码并运行

  • 应该避免使用 eval,不安全,非常耗性能(先解析成 js 语句,在执行)
  • 由 JSON 字符串转换为 JSON 对象的时候可以用 eval(’(’ + str + ‘)’)

23.什么是 Window 对象?什么是 Document 对象?

  • Window 对象表示当前浏览器窗口,是 JavaScript 的顶级对象
  • 我们创建的所有对象、函数、变量都是 Window 对象的成员
  • Window 对象的方法和属性是在全局范围有效的
  • Document 对象是 HTML 文档的根节点与所有其他节点(元素节点、文本节点、属性节点、注释节点)
  • Document 对象使我们可以通过脚本对 HTML 页面中的所有元素进行访问
  • Document 对象是 Window 对象的一部分,可通过 window.document 属性对其进行访问

24.介绍 DOM 的发展

  • DOM:文档对象模型(Document Object Model),定义了访问 HTML 和 XML 文档的标准,与编程语言及平台无关
  • DOM0:提供了查询和操作 Web 文档的内容 API。未形成标准,实现混乱。如:document.forms[‘login’]
  • DOM1:W3C 提出标准化的 DOM,简化了对文档中任意部分的访问和操作。如:JavaScript 中的 Document 对像
  • DOM2:原来 DOM 基础上扩充了鼠标事件等细分模块,增加了对 CSS 的支持。如:getComputedStyle(elem,pseudo)
  • DOM3:增加了 XPath 模块和加载与保存(Load and Save)模块。如:XPathEvaluator

25.介绍 DOM0,DOM2,DOM3 事件处理方式区别

DOM0 级事件处理方式:

  • btn.onclick = fn;
  • btn.onclick = null;

DOM2 级事件处理方式:

  • btn.addEventListener(‘click’,fn,false);
  • btn.removeEventListener(‘click’,fn,false);
  • btn.attachEvent(‘onclick’,fn);
  • btn.detachEvent(‘onclick’,fn);

DOM3 级事件处理方式:

  • eventUtil.addListener(input,“textInput”,fn);
  • eventUtil 是自定义对象,textInput 是 DOM3 级事件

26.事件的三个阶段

捕获、目标、冒泡

27.介绍事件\”捕获\”和\”冒泡\”执行顺序和事件的执行次数

按照 W3C 标准的事件:首先进入捕获阶段,直到到达目标元素,在进入冒泡阶段
事件执行次数:元素上绑定事件的个数

  • 前提是事件被确实触发
  • 事件绑定几次就算几个事件,即使类型和功能完全一样也不会覆盖

事件执行顺序:判断的关键是否目标元素

  • 并非目标元素:根据 W3C 的标准执行:捕获->目标元素->冒泡
  • 目标元素:依据事件绑定顺序:先绑定的事件先执行
  • 最终顺序:父元素捕获->目标元素事件1->目标元素事件2->子元素捕获->子元素冒泡->父元素冒泡
  • 注意:子元素事件执行前提 事件确实\”落\”到子元素布局区域上,而不是简单的具有嵌套关系

28.在一个 DOM 上同时绑定两个点击事件:一个用捕获,一个用冒泡。事件会执行几次?先捕获还是先冒泡?

  • 该 DOM 上的事件如果被触发,会执行两次
  • 如果该 DOM 是目标元素,则按事件绑定顺序执行,不区分冒泡/捕获
  • 如果该 DOM 是处于事件流中的非目标元素,则先执行捕获,后执行冒泡

29.事件的代理/委托

事件委托是指将目标元素的事件绑定到父元素上,利用冒泡机制触发该事件
优点:

  • 可以减少事件注册,节省大量内存占用
  • 可以将事件应用于动态添加的子元素上

缺点:

  • 使用不当会造成事件在不该触发时触发

30.IE 与火狐的事件机制有什么区别?如何阻止冒泡?

IE 只事件冒泡,不支持事件捕获;火狐同时支持事件冒泡和捕获
阻止冒泡:

  • 取消默认操作:W3C 的方法是 e.preventDefault(),IE 则是使用 e.returnValue = false;
  • return false javascript 的 return false 只会阻止默认行为,而用 jQuery 的话则既阻止默认行为又防止对象冒泡
  • 阻止冒泡 W3C 的方法是 e.stopPropagation(), IE 则是使用e.cancelBubble = true;
[js] view plaincopyfunction stopHandler(event)window.event?window.event.cancelBubble=true:event.stopPropagation();}
赞(0) 打赏
未经允许不得转载:爱站程序员基地 » JavaScript面试题三千问—上篇