JavaScript面试题目

1.for…in和object.keys的区别
1.for..in是JavaScript中最常见的迭代语句,常常用来枚举对象的属性。某些情况下,可能按照随机顺序遍历数组元素;
2.Object构造器有一个实例属性keys,则可以返回以对象的属性为元素的数组。数组中属性名的顺序跟使用for..in遍历返回的顺序是一致的。
3.for...in循环会枚举对象原型链上的可枚举属性,而object.key不会。
2.ES6代码转化成ES5代码的实现思路是什么?大致说一下babel的原理?
一.ES6转化为ES5大致分为三个步骤:
    1.将代码字符串解析成抽象语法树,即所谓的AST;
    2.对AST进行处理,在这个阶段可以对ES6代码进行相应的转化,即生成ES5代码;
    3.根据处理后的AST在生成代码字符串。
   
二.Bable原理
    bable的转义过程分为三个阶段,这三部分具体是:
    1.解析parse:将代码解析生成抽象语法树(AST),其实就是计算机理解我们代码的方式(扩展:一般来说每个js引擎都有自己的AST, 比如V8,chorme浏览器会把js源码转换为抽象语法树,再进一步转换为字节码或机器代码),而babel则是通过babylon来实现的。简单来说就是一个对于js代码的一个编译过程,进行词法分析和语法分析的过程。
    2.转换Transform: 对于AST进行变换的一系列操作,babel接受得到AST并通过babel-traverse对其进行遍历,在此过程中进行添加,更新及移除等操作。
    3.生成Generate: 将变换后的AST再转换为JS代码,使用到的模块是babel-generator。
3.词法作用域和this的区别?
1.词法作用域包含了上下文中的变量声明;代码书写时就决定了代码的作用域结构。
2.this: 是执行上下文的一个可能为空值的属性,是对对象的引用。它是js代码执行时绑定的当前执行函数的调用者,最上层是windows对象,this的绑定和函数声明的位置没有任何关系,只取决于函数的调用方式。类似一种动态作用域的方式提供调用者的信息。
4.箭头函数和普通函数的区别?
1.箭头函数没有自己的this,只能通过作用域链来向上查找离自己最近的那个函数的this。
2.箭头函数不能作为constructor,因此不能通过new来调用,所以它并没有new.target这个属性。
3.箭头函数没有argument属性,可以通过rest获取。
4.箭头函数不能直接使用call和apply,bind来改变this。
5.箭头函数不能使用yield,不能作为generator函数。
6.箭头函数语法比普通函数更加简洁。
注:ES6为new命令引入了一个new.target属性,该属性一般用在构造函数之中,返回new命令作用于的那个构造函数或构造方法。如果构造函数不是通过new命令或Reflect.construct()调用的,new.target会返回undefined,因此这个属性可以用来确定构造函数是怎样调用的。包括super也不存在以及原型prototype---因为在执行new的时候需要将函数的原型赋值给实力对象的原型属性。
5.如何判断一个对象是否属于某个类?
1.使用instanceof运算符来判断构造函数得prototype属性是否出现在对象原型链中得任何位置。
2.可以通过对象的constructor属性来判断,对象的constructor属性指向该对象的构造函数,但是这种方式不是很安全,因为constructor属性可以被改写。
3.若需要判断的是某个内置的引用类型的话,可以使用Obect.prototype.toString.call()方法来打印对于的
[[class]]属性来进行判断。
6.请介绍下装饰者模式,并实现。
  • 简介
装饰者模式:动态地给类或对象增加职责的设计模式。它能够在不改变类或对象自身的基础上,在程序运行期间动态
的添加职责。在不改变元对象基础上,对这个对象进行包装和拓展(包括添加属性和方法),从而使这个对象可以有
更复杂的功能。
  • 实现方式简介
  • 1 传统的面向对象语言的实现方式。
var Car = function(){};
Car.prototype.drive = function(){
     console.log('最原始的一版')
}
var AutopilotDecorator = function(val){
  this.val = val;
}
AutopilotDecorator.prototype.drive = function(){
  this.val.drive();
  console.log('启动驾驶');
}
var car = new Car();
car = new AutopilotDecorator(car);
car.drive(); 
 
/** 该实现方式的要点是装饰器类要维护目标对象的一个引用的同时,还要实现目标类的所有接口(这个例子中的
drive方法,如果还有其他方法,也同样要实现的)。调用方法时,先执行目标对象原有的方法,再执行自行添加
的特性。当接口比较多,装饰器也比较多时,可以独立抽取一个装饰器父类,实现目标父类的所有接口,再创建真
正的装饰器来继承这个父类。**/
// 实现例子2 多接口的实现
var Car = function(){};
Car.prototype.drive = function(){
     console.log('最原始的一版')
}
Car.prototype.brake = function(){
  console.log('多了一个刹车功能');
}
var CarDecorator = function(val){
  this.val = val;
}
CarDecorator.prototype = {
 drive:function(){
   this.val.drive()
 },
 brake:function(){
   this.val.brake();
 }
}
// 真正的装饰器
var AutopilotDecorator = function(car){
  CarDecorator.call(this.car);
}
AutopilotDecorator.prototype = new CarDecorator();
AutopilotDecorator.prototype.drive = function(){
  this.car.drive();
  console.log('启动')
}
// 真正的装饰器2
var HybridDecorator = function(car){
  CarDecorator.call(this.car);
};
HybridDecorator.prototype = new CarDecorator();
HybridDecorator.prototype.brake = function(){
  this.car.brake();
  console.log('启动2')
}
var car = new Car();
car = new AutopilotDecorator(car);
car = new HybridDecorator(car);
car.drive()
car.brake(); 
  • 基于对象的实现方式
var car = {
  drive:function(){
    console.log('drive')
  }
};
var driveBasic = car.drive;
var autopilotDecorator = function(){
  console.log('启动')
}
var carToDecorate = object.create(car);
carToDecorate.drive = function(){
  driveBasic();
  autopilotDecorator();
};
carToDecorator.drive();
/**该方式基于js自身语言特点。定义类的目的是实现代码的封装和复用。它只有两种数据类型:基本类型
和对象类型。实现逻辑的封装和代码的重用只需要通过对象来组织代码,然后利用原生提供的克隆机制来达到目的。
 从代码角度看,想扩展drive方法,只需要一个变量保存原函数的引用,然后再重写drive方法就可以了。在重写
的方法里面,只需要记得调用方法原有的行为就可以了。**/
  • 通过工具函数来实现
Function.prototype.after = function(afterFn){
  var _self = this;
  return function(){
    var ret = _self.apply(this,arguments);
    afterFn.apply(this,arguments);
    return ret;
  }
};
var car = {
  drive: function(){
    console.log('启动')
  },
};
var autopilotDecorator = function(){
  console.log('启动驾驶')
};
var carToDecorator = Object.create(car);
carToDecorator.drive = car.drive.after(autopilotDecorator);
carToDecorator.drive();
/**通过Function的原型链上定义after函数,给所有函数都赋予了被扩展的功能,当然也可以根据需要定义一个
before函数,在函数执行前去做一些操作。这种实现方式借鉴了AOP(Aspect Oriented Programming,面向切
面编程)的思想。**/
  • ES7的实现方式
function autopilotDecorator(target,key,desciptor){
  const method = desciptor.value;
  desciptor.value = () => {
    method.apply(target);
    console.log('启动')
  };
  return desciptor;
};
class Car {
  @autopilotDecorator
  drive(){
    console.log('启动ll');
  }
};
let car = new Car();
car.drive();
  • Object.defineProperty实现
var o = {};
Object.defineProperty(o,'name',{
  value: 'sunny',
  writable: true,
  enumerable: true,
  configurable: true
});
// 在对象中添加一个新方法
Object.defineProperty(o,'sayHello',{
  value: function(){
    console.log(this.name)
  },
  writable: true,
  enumerable: true,
  configurable: true
})
o.sayHello();
/**decorator的实现依赖于ES5的Object.defineProperty方法。defineProperty所作事情是为一个对象增加
新的属性或者更改为某个已存在的属性。调用方式是Object.defineProperty(obj,prop,descriptor)**/
/**decorator的参数跟defineProperty是完全一样的,含义也类似,通过修改desriper,能达到扩展功能的目
的。**/
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值