我经历的前端面试题(二)

  • 这是来自某出行类大司的一面,凉。
  • 偏Javascript基础。

js基础

1.基本类型有哪些

Number String Boolean Null Undefined Symbol (落下没说)

2.Null 和 Undefined什么区别?

参考文章:undefined与null的区别

null表示"没有对象",即该处不应该有值。典型用法是:

(1) 作为函数的参数,表示该函数的参数不是对象。

(2) 作为对象原型链的终点。

undefined表示"缺少值",就是此处应该有一个值,但是还没有定义。典型用法是:

(1)变量被声明了,但没有赋值时,就等于undefined。

(2)  调用函数时,应该提供的参数没有提供,该参数等于undefined。

(3)对象没有赋值的属性,该属性的值为undefined。

(4)函数没有返回值时,默认返回undefined。

区别:

(1)定义:undefined表示一个变量没有被声明,或者被声明了但没有被赋值。(比如,一个没有传入实参的形参变量的值为undefined。再比如,如果一个函数什么都不返回,则该函数默认返回undefined;)

                     null是一个表示“没有值”的值,是空对象引用,引用指向为空 。

(2)类型:undefined的类型(typeof)是undefined;null的类型(typeof)是object。

(3)用Number()转化成数值:undefined为NaN ,null为0。

3.如何判断数组类型,几种方法?

参考文章:Js中如何判断一个对象为数组类型

var testArr = [1, 2]

console.log (testArr instanceof Array )
console.log( testArr.constructor == Array ) // 不一定准确,因为数组是引用类型
console.log( Object.prototype.toString.call(testArr) === '[object Array]' )
console.log( Array.isArray( testArr) ) //ES5提供

4.循环有哪些写法?for括号中有什么,能不写吗?while的条件可以是什么?结束循环有哪些方式?

结束循环的方法:

  • return ==》结束循环并中断函数执行;
  • break ==》结束循环函数继续执行;
  • continue ==》跳过本次循环;
  • for 循环中的变量 i,由于 ES5并没有块级作用域的存在,它在循环结束以后仍然存在于内存中,所以建议使用函数自执行的方式来避免;

10.遍历一个数组的方法?

(1)常用的方法性能对比(由强到弱):for(length缓存,每次计算length、不为null)、forEach、map、for of 、for in 。参考文章:JS几种数组遍历方式以及性能分析对比(已经不知道谁是原作者了,2006年的应该是吧)

(2)我不常用的方法还有:filter、some、every、reduce、reduceRight、find、findIndex

(3)ES6提供的:entries()、keys()、values()

参考文章:js数组遍历方法总结(页面好看点就完美了)

它们都返回一个遍历器对象,可以用for...of循环进行遍历,唯一的区别是keys()是对键名的遍历、values()是对键值的遍历,entries()是对键值对的遍历。

5.ES6:let 和 var 有哪些区别?

(1)块作用域:let声明的变量仅在块级作用域内有效,var声明的变量在全局范围内都有效。

(2)变量提升:let声明的变量一定要在声明后使用,否则报错ReferenceError。var声明的变量可以在声明之前使用,值为undefined,即“变量提升”。

(3)let的“暂时性死区”(TDZ):如果区块中存在letconst命令,这个区块对这些命令声明的变量,从一开始就形成了封闭作用域。凡是在声明之前就使用这些变量,就会报错。使用let命令声明变量之前,该变量都是不可用的。这在语法上,称为“暂时性死区”(temporal dead zone,简称 TDZ)。

if (true) {
  // TDZ开始
  tmp = 'abc'; // ReferenceError
  console.log(tmp); // ReferenceError

  let tmp; // TDZ结束
  console.log(tmp); // undefined

  tmp = 123;
  console.log(tmp); // 123
}

6.ES6:箭头函数与普通函数写法有什么区别?

参考文章:箭头函数和普通函数的区别

(1)构造函数:箭头函数没有构造函数,不能通过new获得对象。

(2)参数:箭头函数不绑定arguments,取而代之用rest参数...解决

let C = (...c) => {
  console.log(arguments) // Uncaught ReferenceError: arguments is not defined
  console.log(c);
}
C(3,82,32,11323);  // [3, 82, 32, 11323]

(3)this指向:箭头函数不绑定this,会捕获其所在的上下文的this值,作为自己的this值。

(先自己分析,再看链接里的具体分析)

示例一:

var obj = {
  a: 10,
  b: function(){
    console.log(this.a); //10
  },
  c: function() {
     return ()=>{
           console.log(this.a); //10
     }
  }
}
obj.b(); 
obj.c()();

示例二: 

var obj = {
  a: 10,
  b: () => {
    console.log(this.a); //undefined
    console.log(this); //window
  },
  c: function() {
    console.log(this.a); //10
    console.log(this); //obj{...}
  }
}
obj.b(); 
obj.c();

(4)使用call()和apply()调用:直传入参数,不改变this指向。

(5)原型属性:箭头函数没有原型属性。

(6)箭头函数不能当做Generator函数,不能使用yield关键字。

(7)箭头函数不能换行。

7.一个页面引入了1.js和2.js,1.js中有个变量a,2.js能访问到a变量吗?怎么访问?

我想到的最直接的:html中引用1.js、2.js,2.js中可以访问1.js中的方法从而访问到变量。具体怎么写?两种。

方法一:构造函数。

从闭包角度,对于getName,它的作用域链中包括包含函数的作用域,所以能访问到name变量



 
// coding.js中
function Person(name){
  var name = name || "noName"
  // 从闭包角度,对于getName,它的作用域链中包括包含函数的作用域,所以能访问到name变量
  this.getName=function(){
      return name; 
  };
  // setName同理
  this.setName=function(value){
    name=value;
  };
}
// test.js
var person = new Person()
console.log(person.name) // undefined
console.log(person.getName()) // noName
var person=new Person('哈哈');
console.log(person.getName());//'哈哈'
person.setName('呀呀');
console.log(person.getName());//'呀呀'

方法二:利用闭包的私有作用域。
构造函数使用函数表达式 并且不用var声明;公共方法写在原型链上;私有变量是实例共享的;

// coding.js
(function(){
  var name='noName';
  // 构造函数使用函数表达式,然而不用var声明,所以是全局的
  Person=function(value){
      name = value;
  };
  // 公共方法写在原型链上,都访问同样的内部变量,所以私有变量是实例共享的
  Person.prototype.getName=function(){
      return name;
  };
  Person.prototype.setName=function(value){
      name=value;
  }
})();
// test.js
var person = new Person()
console.log('直接访问:' + person.name)
console.log('无参数访问:' + person.getName())
var person1=new Person('旧实例');
var person2=new Person('新实例');
console.log(person1.getName());
console.log(person2.getName());

 

方法三:使用本地存储策略。cookie或者localStorage。(回忆一下做过的微信小程序项目)

方法四:使用参数传递。

这两种方法感觉不是本题的意思,应该属于跨页面的数据传递。

参考文章:JS实现把一个页面层数据传递到另一个页面的两种方式

8.形参和实参分别是什么。

形参是函数定义的时候的参数。实参是调用该函数实际传入的参数。

function add(a,b) { // a b 是形参
    return a + b
};
add(1,2); // 1 2 是实参

需要注意的是: 

  • 调用函数传递的实参与定义函数规定的形参是依次对应的
  • 超出形参数目的实参不传递其值。
  • 如果没有对应的实参(实参数目少于形参数目)传入,其值为undefined。
  • 而函数使用了形参未定义的‘字面量’,出错:xx is not defined 。
// 关于实参、形参
function add(a, b, c){
  // console.log(arguments)
  console.log(a,b,c)
  console.log(a + b + c)
  // console.log(x) //报错:x is not defined 
}
add(1,2,3,4)
add(1,2)
add(1,'2',3)

我经历的前端面试题(二)_第1张图片

9.说一下作用域链。

看前面的总结即可。闭包为什么会造成内存泄漏?


数据结构

1.什么是平衡二叉树?满二叉树?完全二叉树?

下一篇:


设计模式

整理单独一篇吧

用vue实现数据双向绑定举例子说的观察者模式。

 

你可能感兴趣的:(前端学习小积累,面试,前端面试)