js面试题(上)

https://segmentfault.com/a/11...javascript

原型 / 构造函数 / 实例

  • 对原型的理解
咱们知道在es6以前,js没有类和继承的概念,js是经过原型来实现继承的。在js中一个构造函数默认自带有一个prototype属性, 这个的属性值是一个对象,同时这个prototype对象自带有一个constructor属性,这个属性指向这个构造函数,同时每个实例 都有一个__proto__属性指向这个prototype对象,咱们能够将这个叫作隐式原型,咱们在使用一个实例的方法的时候,会先检查 这个实例中是否有这个方法,没有则会继续向上查找这个prototype对象是否有这个方法,刚刚咱们说到prototype是一个对象, 那么也便是说这个是一个对象的实例,那么这个对象一样也会有一个__proto__属性指向对象的prototype对象。

原型链

JS 原型与原型链前端

执行上下文(EC)

变量对象

  • javascript有哪些方法定义对象

对象字面量: var obj = {};
构造函数: var obj = new Object();
Object.create(): var obj = Object.create(Object.prototype);java

做用域

做用域链

做用域链的原理和原型链很相似,若是这个变量在本身的做用域中没有,那么它会寻找父级的,直到最顶层。
注意:JS没有块级做用域,若要造成块级做用域,可经过(function(){})();当即执行的形式实现。git

闭包

闭包指的是一个函数能够访问另外一个函数做用域中变量。常见的构造方法,是在一个函数内部定义另一个函数。内部函数能够引用外层的变量;外层变量不会被垃圾回收机制回收。
注意,闭包的原理是做用域链,因此闭包访问的上级做用域中的变量是个对象,其值为其运算结束后的最后一个值。
优势:避免全局变量污染。缺点:容易形成内存泄漏。
例子:程序员

function makeFunc() {
    var name = "Mozilla";
    function displayName() {
        console.log(name); 
    }
    return displayName;
}
var myFunc = makeFunc();
myFunc();   //输出Mozilla

myFunc 变成一个 闭包。闭包是一种特殊的对象。它由两部分构成:函数,以及建立该函数的环境。环境由闭包建立时在做用域中的任何局部变量组成。在咱们的例子中,myFunc 是一个闭包,由 displayName 函数和闭包建立时存在的 "Mozilla" 字符串造成。es6

script引入方式

对象的拷贝

这道题考察了如下知识点:
使用 typeof 判断值得类型;
使用 toString 区分数组和对象;
递归函数的使用;
  • 实现一个函数 clone(),能够对 JavaScript 中的5种主要的数据类型(包括 Number、String、Object、Array、Boolean)进行值复制。
function clone(obj) {
    //判断是对象,就进行循环复制
    if (typeof obj === 'object' && typeof obj !== 'null') {
        // 区分是数组仍是对象,建立空的数组或对象
        var o = Object.prototype.toString.call(obj).slice(8, -1) === "Array" ? [] : {};
        for (var k in obj) {
            // 若是属性对应的值为对象,则递归复制
            if(typeof obj[k] === 'object' && typeof obj[k] !== 'null'){
                o[k] = clone(obj[k])
            }else{
                o[k] = obj[k];
            }
        }
    }else{ //不为对象,直接把值返回
        return obj;
    }
    return o;
}

new运算符的执行过程

1) 建立一个空对象,而且 this 变量引用该对象,同时还继承了该函数的原型。
2) 属性和方法被加入到 this 引用的对象中。
3) 新建立的对象由 this 所引用,而且最后隐式的返回 this 。github

使用new操做符实例化一个对象的具体步骤
1.构造一个新的对象
2.将构造函数的做用域赋给新对象(也就是说this指向了新的对象)
3.执行构造函数中的代码
4.返回新对象面试

instanceof原理

代码的复用

继承

其余问题

js数据类型

其余问题
  • typeof 返回哪些数据类型
typeof 返回七种值:
“number”、“string”、“boolean”、“object”、"symbol"、“function”和“undefined”。
typeof undefined、null、NaN分别返回undefined,object,number
  • JavaScript有几种类型的值?你能画一下他们的内存图吗?
基本数据类型存储在栈中,引用数据类型(对象)存储在堆中,指针放在栈中。
两种类型的区别是:存储位置不一样;原始数据类型直接存储在栈中的简单数据段,占据空间小、大小固定,属于被频繁使用数据,因此放入栈中存储;引用数据类型存储在堆中的对象,占据空间大、大小不固定,若是存储在栈中,将会影响程序运行的性能
引用数据类型在栈中存储了指针,该指针指向堆中该实体的起始地址。当解释器寻找引用值时,会首先检索其在栈中的地址,取得地址后从堆中得到实体。
  • 栈和堆的区别
栈(stack):由编译器自动分配释放,存放函数的参数值,局部变量等;
堆(heap):通常由程序员分配释放,若程序员不释放,程序结束时可能由操做系统释放。

类型转换

  • 对象到数字的转换步骤
  1. 若是对象有valueOf()方法而且返回元素值,javascript将返回值转换为数字做为结果
  2. 不然,若是对象有toString()而且返回原始值,javascript将返回结果转换为数字做为结果
  3. 不然,throws a TypeError
  • 对象到字符串的转换步骤

1.若是对象有toString()方法,javascript调用它。若是返回一个原始值(primitive value如:string number boolean),将这个值转换为字符串做为结果
2.若是对象没有toString()方法或者返回值不是原始值,javascript寻找对象的valueOf()方法,若是存在就调用它,返回结果是原始值则转为字符串做为结果
3.不然,javascript不能从toString()或者valueOf()得到一个原始值,此时throws a TypeError编程

类型判断

  • javascript作类型判断的方法有哪些?

typeof、instanceof 、 Object.prototype.toString()(待续)json

  • 实现一个类型判断函数,须要鉴别出基本类型、function、null、NaN、数组、对象?

只须要鉴别这些类型那么使用typeof便可,要鉴别null先判断双等判断是否为null,以后使用typeof判断,若是是obejct的话,再用Array.isArray判断 是否为数组,若是是数字再使用isNaN判断是否为NaN,(须要注意的是NaN并非JavaScript数据类型,而是一种特殊值)以下:

function type(ele) {
  if(ele===null) {
    return null;
  } else if(typeof ele === 'object') {
    if(Array.isArray(ele)) {
      return 'array';
    } else {
      return typeof ele;
    }
  } else if(typeof ele === 'number') {
    if(isNaN(ele)) {
      return NaN;
    } else {
      return typeof ele;
    }
  } else{
    return typeof ele;
  }
}

模块化

  • 对js模块化的理解

在ES6出现以前,js没有标准的模块化概念,这也就形成了js多人写做开发容易形成全局污染的状况,之前咱们可能会采用当即执行 函数、对象等方式来尽可能减小变量这种状况,后面社区为了解决这个问题陆续提出了AMD规范和CMD规范,这里不一样于Node.js的 CommonJS的缘由在于服务端全部的模块都是存在于硬盘中的,加载和读取几乎是不须要时间的,而浏览器端由于加载速度取决于网速, 所以须要采用异步加载,AMD规范中使用define来定义一个模块,使用require方法来加载一个模块,如今ES6也推出了标准的模块 加载方案,经过export和import来导出和导入模块。

  • 模块化开发怎么作

模块化开发指的是在解决某一个复杂问题或者一系列问题时,依照一种分类的思惟把问题进行系统性的分解。模块化是一种将复杂系统分解为代码结构更合理,可维护性更高的可管理的模块方式。对于软件行业:系统被分解为一组高内聚,低耦合的模块。
(1)定义封装的模块
(2)定义新模块对其余模块的依赖
(3)可对其余模块的引入支持。在JavaScript中出现了一些非传统模块开发方式的规范。 CommonJS的模块规范,AMD(Asynchronous Module Definition),CMD(Common Module Definition)等。AMD是异步模块定义,全部的模块将被异步加载,模块加载不影响后边语句运行。

  • 如何实现一个JS的AMD模块加载器

AMD是解决JS模块化的规范,实现这样的一个模块加载器的关键在于解决每一个模块依赖的解析。首先咱们须要有一个模块的入口,也就是主模块,好比咱们使用 一个use方法做为入口,以后以数组的形式列出了主模块的依赖,这时候咱们要想到的是如何解析这一个一个的依赖,也就是如何解析出一个个js文件的绝对地址, 咱们能够制定一个规则,如默认为主模块的路径为基准,也能够像requirejs同样使用一个config方法来指定一个baseurl和为每个模块指定一个path,最后就是 模块的问题,咱们须要暴露一个define方法来定义模块,也就是模块名,依赖以及每一个模块的各自代码。其中每一个模块的代码都应该在依赖加载完以后执行,这就是一个 回调函数,模块的依赖、回调函数、状态、名字、模块导出等能够看作是一个模块的属性,所以咱们可使用一个对象来保存全部的模块,而后每一个模块的各个属性存放在一个对象中。 最后咱们来考虑一下模块加载的问题,上面咱们说到use方法,use方法的逻辑就是遍历依赖,而后对每一个模块进行加载,也就是解析地址而后使用插入script,咱们假设 使用loadModule方法来加载依赖,那么这个函数的逻辑就应该是检查咱们的模块是否已经加载过来判断是否须要加载,若是这个模块还有依赖则调用use方法继续解析,模块依赖中咱们 尚未提到的问题就是每一个模块的依赖是须要被传进模块里来使用的,解决方法就是每一个模块的callback方法执行后的返回的export记录下来而后使用apply之类的方法将这些参数传递进去。 大体就是这样子的。

参考:
动手实现一个AMD模块加载器(一)
动手实现一个AMD模块加载器(二)
动手实现一个AMD模块加载器(三)

防抖和节流

函数节流就是让一个函数没法在很短的时间间隔内连续调用,而是间隔一段时间执行,这在咱们为元素绑定一些事件的时候常常会用到,好比咱们 为window绑定了一个resize事件,若是用户一直改变窗口大小,就会一直触发这个事件处理函数,这对性能有很大影响。
什么是函数节流?
前端面试查漏补缺--(一) 防抖和节流

函数执行改变this

  • 谈谈对this对象的理解

1) this老是指向函数的直接调用者(而非间接调用者)
2) 若是有new关键字,this指向new出来的那个对象
3) 在事件中,this指向目标元素,特殊的是IE的attachEvent中的this老是指向全局对象window。

ES6/ES7

  • 简要介绍ES6

ES6在变量的声明和定义方面增长了let、const声明变量,有局部变量的概念,赋值中有比较吸引人的结构赋值,同时ES6对字符串、 数组、正则、对象、函数等拓展了一些方法,如字符串方面的模板字符串、函数方面的默认参数、对象方面属性的简洁表达方式,ES6也 引入了新的数据类型symbol,新的数据结构set和map,symbol能够经过typeof检测出来,为解决异步回调问题,引入了promise和 generator,还有最为吸引人了实现Class和模块,经过Class能够更好的面向对象编程,使用模块加载方便模块化编程,固然考虑到 浏览器兼容性,咱们在实际开发中须要使用babel进行编译。

  • let、const、var的使用区别

let: 至关于var,用于声明一个变量,在块级做用域有效(可解决for循环问题);不能重复声明;不会变量提高;不会预处理
const: 用于定义一个常量,不能修改,其余特色等同于let,用于保存不用改变的数据

  • Map与普通对象的区别

JavaScript 的对象(Object),本质上是键值对的集合(Hash 结构),可是传统上只能用字符串看成键。这给它的使用带来了很大的限制。为了解决这个问题,ES6 提供了 Map 数据结构。它相似于对象,也是键值对的集合,可是“键”的范围不限于字符串,各类类型的值(包括对象)均可以看成键。也就是说,Object 结构提供了“字符串—值”的对应,Map 结构提供了“值—值”的对应,是一种更完善的 Hash 结构实现。若是你须要“键值对”的数据结构,Map 比 Object 更合适。

AST

babel编译原理

函数柯里化

数组

  • 判断数组
Array.isArray([]);  // true
Array.isArray(undefined); // false;

或者
array instanceof Array; // true 检测对象的原型链是否指向构造函数的prototype对象
或者
array.constructor === Array; // true

终极大招:
if (!Array.isArray) {
  Array.isArray = function(arg) {
    return Object.prototype.toString.call(arg) === '[object Array]';
  };
}

注意:typeof []; // "object" 不能够用此方法检查!!!

null,undefined的区别

null表示一个对象被定义了,但存放了空指针,转换为数值时为0。
undefined表示声明的变量未初始化,转换为数值时为NAN。
typeof(null) -- object;
typeof(undefined) -- undefined

["1", "2", "3"].map(parseInt) 答案是多少

[1,NaN,NaN]

解析:
Array.prototype.map()
array.map(callback[, thisArg])
callback函数的执行规则
参数:自动传入三个参数
currentValue(当前被传递的元素);
index(当前被传递的元素的索引);
array(调用map方法的数组)

parseInt方法接收两个参数
第三个参数["1", "2", "3"]将被忽略。parseInt方法将会经过如下方式被调用
parseInt("1", 0)
parseInt("2", 1)
parseInt("3", 2)

parseInt的第二个参数radix为0时,ECMAScript5将string做为十进制数字的字符串解析;
parseInt的第二个参数radix为1时,解析结果为NaN;
parseInt的第二个参数radix在2—36之间时,若是string参数的第一个字符(除空白之外),不属于radix指定进制下的字符,解析结果为NaN。
parseInt("3", 2)执行时,因为"3"不属于二进制字符,解析结果为NaN。

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

IE为事件冒泡,Firefox同时支持事件捕获和事件冒泡。但并不是全部浏览器都支持事件捕获。jQuery中使用event.stopPropagation()方法可阻止冒泡;(旧IE的方法 ev.cancelBubble = true;)

如何阻止事件冒泡和默认事件?
标准的DOM对象中可使用事件对象的stopPropagation()方法来阻止事件冒泡,但在IE8如下中IE的事件对象经过设置事件对象的cancelBubble属性为true来阻止冒泡; 默认事件的话经过事件对象的preventDefault()方法来阻止,而IE经过设置事件对象的returnValue属性为false来阻止默认事件。

javascript 代码中的"use strict";是什么意思 ? 使用它区别是什么?

除了正常模式运行外,ECMAscript添加了第二种运行模式:“严格模式”。
做用:
1) 消除js不合理,不严谨地方,减小怪异行为
2) 消除代码运行的不安全之处,
3) 提升编译器的效率,增长运行速度
4) 为将来的js新版本作铺垫。

对JSON的了解

全称:JavaScript Object NotationJSON中对象经过“{}”来标识,一个“{}”表明一个对象,如{“AreaId”:”123”},对象的值是键值对的形式(key:value)。JSON是JS的一个严格的子集,一种轻量级的数据交换格式,相似于xml。数据格式简单,易于读写,占用带宽小。两个函数:JSON.parse(str)解析JSON字符串 把JSON字符串变成JavaScript值或对象JSON.stringify(obj) 将一个JavaScript值(对象或者数组)转换为一个 JSON字符串eval('('+json+')') 用eval方法注意加括号 并且这种方式更容易被攻击

相关文章
相关标签/搜索