ES6面试题

1.箭头函数中的this指向定义时当前周围的作用域;

2.如果使用标记模板字面量,第一个参数的值总是字符串的数组。其余的参数获取的是传递的表达式的值;

3. es6中和原型一样用来继承的class和继承是怎么实现的?

贴上

class Point {
  // ...
}
typeof Point // "function",类的数据类型就是函数
Point === Point.prototype.constructor // true,类本身就指向构造函数

使用的时候,也是直接对类使用new命令,跟构造函数的用法完全一致,不使用new会报错。

类的所有方法都定义在类的prototype属性上面。

class Point {
  constructor() {    // ...  }
  toString() {    // ...  }
  toValue() {    // ...  }
}
// 等同于
Point.prototype = {
  constructor() {},
  toString() {},
  toValue() {},
};

//Object.assign方法可以很方便地一次向类添加多个方法
Object.assign(Point.prototype, {
  toString(){},
  toValue(){}
});

类不存在变量提升(hoist),这一点与 ES5 完全不同。

Class 可以通过extends关键字实现继承。

class ColorPoint extends Point {}//ColorPoint继承了Point类所有的属性和方法

super关键字,表示父类的构造函数,用来新建父类的this对象。

子类必须在constructor方法中调用super方法,否则新建实例时会报错,只有调用super之后,才可以使用this关键字。

区别:

ES5 的继承,实质是先创造子类的实例对象this,然后再将父类的方法添加到this上面Parent.apply(this))。

ES6 的继承机制完全不同,实质是先将父类实例对象的属性和方法,加到this上面(所以必须先调用super方法),然后再用子类的构造函数修改this

Class 作为构造函数的语法糖,同时有prototype属性和__proto__属性,因此同时存在两条继承链。

(1)子类的_proto_属性,表示构造函数的继承,总是指向父类。

(2)子类prototype属性的_proto_属性,表示方法的继承,总是指向父类的prototype属性。

子类实例的__proto__属性的__proto__属性,指向父类实例的__proto__属性。也就是说,子类的原型的原型,是父类的原型。

Object.getPrototypeOf方法判断,一个类是否继承了另一个类。

4. es6中const、let、var之间的区别?

  1. var定义的变量,作用域是整个封闭函数,是全域的;

    let定义的变量,作用域是在块级或者字块中;

  2. 变量提升:不论通过var声明的变量处于当前作用于的第几行,都会提升到作用域的最顶部

    而let声明的变量不会在顶部初始化,凡是在let声明之前使用该变量都会报错(引用错误ReferenceError);

  3. 只要块级作用域内存在let,它所声明的变量就会绑定在这个区域

  4. let不允许在相同作用域内重复声明(报错同时使用var和let,两个let)

const用来专门声明一个常量,它跟let一样作用于块级作用域没有变量提升重复声明会报错,不同的是const声明的常量不可改变,声明时必须初始化(赋值),const定义的对象可变。

const使用场景很广,包括常量、配置项以及引用的组件、定义的 “大部分” 中间变量等,都应该以cosnt做定义。反之就 let 而言,他的使用场景应该是相对较少的,我们只会在 loop(for,while 循环)及少量必须重定义的变量上用到他。

5. 大致讲一下ES6新特性;

箭头函数

② 增加了对类的支持class关键字;继承:class Programmer extends Animal

③ 增强了对象字面量:可以在对象字面量里面定义原型

__proto__: human, //设置此对象的原型为human,相当于继承human

定义方法可以不用function关键字

work() {console.log('working...'); }

字符串模板:反引号 ` 来创建字符串;

解构:[name,age]=[Alice,’male’,’secrect’];//数组解构;

⑥ 参数默认值,不定参数,拓展参数:

参数默认值:在定义函数的时候指定参数的默认值

function sayHello2(name='dude'){
    console.log(`Hello ${name}`);
}

不定参数:在函数中使用命名参数同时接收不定数量的未命名参数,三个句点后跟代表所有不定参数的变量名

function add(...x){
    return x.reduce((m,n)=>m+n);
}

拓展参数:允许传递数组或者类数组直接做为函数的参数而不用通过apply。

var people=['Wayou','John','Sherlock'];
sayHello(...people);//输出:Hello Wayou,John,Sherlock

letconst关键字

for of值遍历:for in 循环用于遍历数组,类数组或对象,for of循环功能相似,不同的是每次循环它提供的不是序号而是值

for…of 循环的i代表的是value(多用于数组),for…in 循环的是key(多用于对象

⑨ iterator, generator:iterator拥有一个next方法;generator是一种特殊的iterator,通过function来声明的,yield 关键字*可以暂停函数的执行,随后可以再进进入函数继续执行。

模块module

// point.js
module "point" {
    export class Point {
        constructor (x, y) {
            public x = x;
            public y = y;
        } 
    }
}

// myapp.js
module point from "/point.js";  //声明引用的模块
import Point from "point";      //可以看出,尽管声明了引用的模块,还是可以通过指定需要的部分进行导入
var origin = new Point(0, 0);
console.log(origin);

Map,Set 和 WeakMap,WeakSet:提供了更加方便的获取属性值的方法,不用像以前一样用hasOwnProperty来检查某个属性是属于原型链上还是当前对象的。同时,在进行属性值添加与获取时有专门的get,set 方法。WeakMap,WeakSet更加安全,作为属性键的对象如果没有别的变量在引用它们,则会被回收释放掉。

② Proxies:监听对象身上发生了什么事情,并在这些事情发生后执行一些相应的操作。

③ Symbols:是一种基本类型,不是一个对象。可以用symbol这种值来做为对象的键。

④ Math,Number,String,Object 的新API;

⑤ Promises:处理异步操作的一种模式,then()

6.Object.assign浅拷贝

Object.assign方法用来将源对象(source)的所有可枚举属性,复制到目标对象(target)。

Object.assign方法实行的是浅拷贝,而不是深拷贝。

参数

​ 它至少需要两个对象作为参数,第一个参数是目标对象,后面的参数都是源对象。

​ 如果只有一个参数,Object.assign会直接返回该参数。

​ 如果该参数不是对象,则会先转成对象,然后返回

​ 由于undefined和null无法转成对象,所以如果它们作为参数,就会报错

注:如果目标对象与源对象有同名属性,或多个源对象有同名属性,则后面的属性会覆盖前面的属性

注意:如果非对象参数出现在源对象的位置(即非首参数),那么处理规则有所不同。首先,这些参数都会转成对象,如果无法转成对象,就会跳过。这意味着, 如果undefined和null不在首参数,就不会报错。其他类型的值(即数值、字符串和布尔值)不在首参数,也不会报错。但是,除了字符串会以数组形式,拷贝入目标对象,其他值都不会产生效果。

对于嵌套的对象,Object.assign的处理方法是替换,而不是添加。

var target = { a: { b: 'c', d: 'e' } }
var source = { a: { b: 'hello' } } 
Object.assign(target, source); /*{ a: { b: 'hello' } } */

注意,Object.assign可以用来处理数组,但是会把数组视为对象

console.log(Object.assign([1, 2, 3], [4, 5]));
/*[4,5,3] 4覆盖1,5覆盖2,因为它们在数组的同一位置,所以就对应位置覆盖了*/

如果源对象某个属性的值是对象,那么目标对象拷贝得到的是这个对象的引用。

var object1 = { a: { b: 1 } };
var object2 = Object.assign({}, object1); 
object1.a.b = 2; 
console.log(object2.a.b);

用途

为对象添加属性;为对象添加方法;克隆对象;合并多个对象;为属性指定默认值

//克隆对象:将原始对象拷贝到一个空对象,就得到了原始对象的克隆
function copyFnc(origin) {
    return Object.assign({}, origin)
} 
var sur = { a: 1, b: 2 };
console.log(copyFnc(sur));

采用这种方法克隆,只能克隆原始对象自身的值,不能克隆它继承的值。如果想要保持继承链,可以采用下面的代码。

/*克隆对象:在JS里子类利用Object.getPrototypeOf去调用父类方法,用来获取对象的原型*/
function clone(origin) {
    let originProto = Object.getPrototypeOf(origin);
    return Object.assign(Object.create(originProto), origin);
}

//多个对象合并到某个对象
const merge = (target, ...sources) => Object.assign(target, ...sources);
//多个对象合并到新对象
const merge = (...sources) => Object.assign({}, ...sources);

const o1 = { a: 1 };
const o2 = { b: 2 };
const o3 = { c: 3 };
const obj = Object.assign(o1, o2, o3);// { a: 1, b: 2, c: 3 }

7.箭头函数和一般函数有什么区别?

定义箭头函在数语法上要比普通函数简洁得多。箭头函数省去了function关键字,采用箭头=>来定义函数。

基本语法:关于箭头函数的参数:

① 如果箭头函数没有参数,直接写一个空括号即可。

② 如果箭头函数的参数只有一个,也可以省去包裹参数的括号

③ 如果箭头函数有多个参数,将参数依次用逗号(,)分隔,包裹在括号中即可。

基本语法:关于箭头函数的函数体:

① 如果箭头函数的函数体只有一句代码,就是简单返回某个变量或者返回一个简单的JS表达式,可以省去函数体的大括号{ }。

② 如果箭头函数的函数体只有一句代码,就是返回一个对象,用小括号包裹要返回的对象,不报错

let getTempItem = id => ({ id: id, name: "Temp" });

③ 如果箭头函数的函数体只有一条语句并且不需要返回值(最常见是调用一个函数),可以给这条语句前面加一个void关键字

let fn = () => void doesNotReturn();
//用来简化回调函数:
[1,2,3].map(function (x) {return x * x;});// 正常函数写法
[1,2,3].map(x => x * x);// 箭头函数写法
var result = [2, 5, 1, 4, 3].sort(function (a, b) {  return a - b;});// 正常函数写法
var result = [2, 5, 1, 4, 3].sort((a, b) => a - b);// 箭头函数写法

区别

1、语法更加简洁、清晰

2、箭头函数不会创建自己的this,它会捕获自己在定义时(注意,是定义时,不是调用时)所处的外层执行环境的this,并继承这个this值。所以,箭头函数中this的指向在它被定义的时候就已经确定了,之后永远不会改变。

3、箭头函数继承而来的this指向永远不变

4、.call()/.apply()/.bind()无法改变箭头函数中this的指向(但是也不会报错)

5、箭头函数不能作为构造函数使用:因为箭头函数没有自己的this,它的this其实是继承了外层执行环境中的this,且this指向永远不会随在哪里调用、被谁调用而改变,所以箭头函数不能作为构造函数使用,或者说构造函数不能定义成箭头函数,否则用new调用时会报错!

6、箭头函数没有自己的arguments:在箭头函数中访问arguments实际上获得的是外层局部(函数)执行环境中的值。可以在箭头函数中使用rest参数代替arguments对象,来访问箭头函数的参数列表

7、箭头函数没有原型prototype

let sayHi = () => {    console.log('Hello World !')};
console.log(sayHi.prototype); // undefined

8.Promise、async await 的使用?

promise和async/await都是异步方案,promise是es6的新特性,而async/await是es7新出的特性。

Promise是一个对象,可以实现链式的写法来实现同步异步操作,

then()…catch()…,then表示上一个promise执行完后执行,如果出现错误就会传入catch里面,通常这么写:

var pro = new promise (function(resolve,reject){
    resolve("success");
    console.log("afterresolve");
    reject("error");
});
pro.then(result=>{
    console.log(result);
});
pro.catch(result=>{
    console.log(result);
})
//afterresolve success

resolve下面的语句其实是可以执行的,那么为什么reject的状态信息在下面没有接受到呢?

这就是因为Promise对象的特点:状态的凝固。new出一个Promise对象时,这个对象的起始状态就是Pending状态,在根据resolve或reject返回Fulfilled状态/Rejected状态。

new Promise((resolve, reject) => {
    var param = 'Promise 执行完后返回的数据';
    var error = 'Promise 异步执行异常';
    if( error ) {
        reject(new Error('Promise 异步执行异常'));
    } else {
        resolve(param);
    }
}).then((res) => {
//  这里res就是Promise中的param参数
    console.log(res);  //  Promise 执行完后返回的数据
    var param = '第一个then 执行完后返回的数据';
    return param;
}).then((res) => {
//  这里的res就不是Promise中resolve的param参数了,而是上一个then中的返回值
    console.log(res);  //  第一个then 执行完后返回的数据
}).catch((error) => {
//  这里是Promise执行reject方法中的参数
    console.log(error); //  Promise 异步执行异常
});

第一个then()触发条件:是 Promise() 实例化时resolve()触发,resolve(param);

第二个及以后的then() 触发条件是第一个then()执行完成,并且将return值作为下一个then的参数;

catch()触发条件是执行了reject(),用于指定发生错误的时候的回调函数。

需要注意的是resolve与reject只能执行一个。也就是说如果不加入判断的话,某一个先执行了,后面的就自动忽略了。

对于async/await来说是基于promise的,他可以让我们更加优雅的写出代码,而替代then()的写法;

需要注意的就是await是强制把异步变成了同步,这一句代码执行完,才会执行下一句

await必须用在async方法中;处理错误的方法:

1572012187509
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 196,099评论 5 462
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 82,473评论 2 373
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 143,229评论 0 325
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,570评论 1 267
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,427评论 5 358
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,335评论 1 273
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,737评论 3 386
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,392评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,693评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,730评论 2 312
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,512评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,349评论 3 314
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,750评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,017评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,290评论 1 251
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,706评论 2 342
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,904评论 2 335

推荐阅读更多精彩内容