前端面试题整理—JavaScript篇(一)

一、JS的基本数据类型和引用数据类型有哪些,二者区别javascript

  基本数据类型->string、number、Boolean、null、undefined、symbolcss

  引用数据类型->array、object、functionhtml

  基本数据类型是保存在栈内存中,操做的是值,改变源数据不会影响新的变量java

  引用数据类型保存在堆内存中,操做的是地址,改变其中一个会影响另外一个node

 

二、数据类型中为假的有哪些?jquery

  false (布尔型)es6

  0(数值型)ajax

  null(定义空的或者不存在,如今没有,未来可能有)正则表达式

  undefined(未定义,一直不存在)express

  NaN(不是一个有效数字)

  空字符串(空字符串,字符类型)

 

三、举例JavaScript的基本规范,以及如何编写高性能代码

  基本规范

  1)代码缩进,建议使用“四个空格”缩进

  2)语句结束使用分号

  3)变量和函数在使用前进行声明

  4)以大写字母开头命名构造函数,全大写命名常量

  5)使用ID最好先获取一下

  6)规范定义JSON对象,补全双引号

  

  1)遵循严格模式:"use strict";

  2)将js脚本放在页面底部,加快渲染页面

  3)尽可能减小使用闭包

  4)尽可能使用直接量建立对象和数组

  5)尽可能减小对象成员嵌套

  6)最小化重绘(repaint)和回流(reflow)

 

四、JS有哪些内置对象

  Object、Array、Boolean、Number、String、Function、Arguments、Math、Date、RegExp

  ES6新增对象:Symbol、Map、Set、Promises、Proxy

 

五、怎么实现string和number的相互转换

  String 转换成 Number:Number()、parseInt()、parseFloat()

  Number 转换成 String:String()、toString() 

 

六、怎么建立、添加、替换、克隆、删除元素

  建立-> document.createElement('标签名')
  添加-> parent.appendChild()   
      parent.insertBefore(新插入的元素,老元素)  
  替换-> replaceChild(new,old)
  克隆-> cloneChild()
  删除->removeChild()

 

七、什么状况下会转为字符串

  1)基于alert、confirm、document.write等输出内容时,会先把值转为字符串后在输出

  2)基于'+'进行字符串拼接时

  3)把复合类型值转换数字时候。首先会转换字符串而后再转为数字

  4)给对象设置属性名时候,若是不是字符串 先转为字符串,而后在做为属性存储到对象中(对象属性只能是字符串和数字)

  5)手动调用toString、toFixed(将 Number 四舍五入为指定小数位数的数字)、join、String方法时候,也是为了转换字符串

 

八、获取对象属性[]和.的区别

  .后面的是这个对象的属性,凡是用.的地方均可以用[]

  []中括号的内容能够是字符串也能够是变量,基本上[]放的是变量

 

九、null和undefined的区别

  Null:表明空对象指针。如今没有,未来可能会有

  undefined:空,未定义。如今没有,未来也不会有(Js中独有的数据类型)

 

十、检测数据类型的几种方式,以及他们的对比

  typeof、instanceof、constructor、Object.prototype.toString.call()

  typeof只针对基本数据类型,遇到引用数据类型是不起做用的(没法细分对象)

  instanceof用来判断对象和函数,不适合判断字符串和数字

  constructor是Object其中的一个属性。默认指向实例的构造函数

  经过Object.prototype.toString方法,判断某个对象值属于哪一种内置类型

 

十一、in 与 hasOwnProperty

  二者都表明查看某个属性是否是本身的

  in判断的是对象的全部属性,包括对象实例及其原型的属性

  hasOwnProperty则是判断对象实例的是否具备某个属性

 

十二、innerHTML和innerText区别

  innerHTML能够获取结构和文本

  innerText只获取文本内容

 

1三、如何清除一个定时器?

  clearTimeout(timer)

 

1四、说一下倒计时原理及公式

  将来时间-如今时间= 剩余时间

        let d = Math.floor(t/86400);
        t % =86400;
        let h = Math.floor(t/3600);
        t % = 3600;
        let m = Math.floor(t/60);
        t % = 60;

 

1五、什么时候使用 === 什么时候使用 ==

  判断对象的属性是否存在可使用双等,其他都用全等

  ===更严谨,不只值相等类型也要相等,不用进行类型转换,而且比==速度快

 

1六、eval 是作什么的?

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

  由JSON字符串转换为JSON对象的时候能够用 eval('('+ str +')');

  应避免使用eval,由于不安全,耗性能

 

1七、数组经常使用的一些方法有哪些 

  push()向数组末尾添加数据
  pop()删除数组最后一项
  unshift()向数组首位添加新内容
  shift()删除数组的第一项
  slice()按照条件查找出其中的部份内容
  splice()对数组进行增删改
  join()用指定的分隔符对数组拼接
  concat()用于链接两个或多个数组
  indexOf()/lastIndexOf()当前值在数组中第一次/最后一次出现的位置索引
  includes()判断一个数组是否包含指定的值
  sort()对数组进行排序
  reverse()把数组倒过来排列
  forEach()循环遍历数组每一项

 

1八、说一下什么是DOM映射机制

  经过DOM中方法获取到的元素,与页面一一对应的这种关系称之为DOM映射

  querySelectorAll获取到的元素集合没有DOM映射,必须是元素的内置属性发生变化,浏览器才能监听获得

 

1九、一行代码实现数组去重

[...new Set([1,2,3,4])]

 

20、节点类型都有哪些,如何判断当前节点类型

  1元素节点,2属性节点,3文本节点,8注释节点、9文档节点

  经过nodeObject.nodeType判断节点类型,其中,nodeObject为节点对象

  该属性返回以数字表示的节点类型,例如,元素节点返回1,属性节点返回2

 

2一、重绘和回流(重排)区别,什么状况会触发重排和重绘

  当页面元素(宽高,位置)发生改变,回致使页面重排,浏览器会根据新位置进行从新渲染

  回流必将引发重绘,而重绘不必定会引发回流。重绘相对于回流性能消耗较低

  

  任何改变用来构建渲染树的信息都会致使一次重排或重绘

  好比添加、删除、更新DOM节点,经过display: none隐藏,调整样式属性,调整窗口大小,滚动等等

 

2二、如何最小化重绘(repaint)和回流(reflow)

  1)须要对元素进行复杂的操做时,能够先display:none隐藏,操做完再显示

  2)须要建立多个DOM节点时,使用DocumentFragment建立完后一次性的加入document

  3)尽可能避免用table布局

  4)避免使用css表达式(expression),每次调用都会从新计算值(包括加载页面)

  5)尽可能使用css简写,如:用border代替border-width,border-style, border-color

 

2三、什么是自执行函数,用于什么场景

   自执行函数,即定义和调用合为一体,好比匿名函数自执行

  他能够建立一个独立做用域,防止做用域污染,防止变量影响到全局,以避免产生冲突

  多用于框架和插件

 

2四、改变this指向的方法

  call、apply、bind

  call和apply能够自动执行,bind须要手动调用,返回值为函数

  call和bind都有无数个参数,apply只有两个参数,而且第二个为数组

 

2五、iframe的优缺点

  优势:

  1)iframe可以原封不动的把嵌入的网页展示出来

  2)头部和底部同样时能够写成一个页面,用iframe来嵌套,能够增长代码的可重用

  3)引用多个页面,只须要修改iframe的内容,就能够实现页面内容的更改

  缺点:

  不容易管理、用户体验度差、不利于搜索引擎优化、兼容性差、增长服务器的http请求,通常用Ajax来代替iframe

 

2六、类数组转数组的方法

  Array.from

  Array.prototype.slice.call

   [].slice.call

 

2七、请解释什么是暂时性死区

  let 和 const 声明的变量不存在变量提高,其做用域都是块级做用域,凡是在声明变量以前使用变量就会报错,

  因此,在代码块内,使用let命令声明变量以前,该变量都是不可用的。这在语法上,称为“暂时性死区”

 

2八、严格模式与非严格模式的区别

  非严格模式又被被称为懒散模式

  严格模式 use strict是一种ECMAscript 5添加的运行模式,这种模式使得 Js在更严格的条件下运行,使JS编码更加规范化

  消除Javascript语法的一些不合理、不严谨之处,减小一些怪异行为。

  严格模式中变量必须显示声明

  在严格模式下,arguments和eval是关键字,不能被修改

  在严格模式下,函数的形参也不能够同名

 

2九、验证手机号码和邮箱的正则表达式

  手机号码验证

/^(13[0-9]|14[5-9]|15[012356789]|166|17[0-8]|18[0-9]|19[8-9])[0-9]{8}$/

  邮箱验证

^[A-Za-z]\w{3,17}@[1-9A-Za-z]{2,8}\.(com|cn|net)$

 

30、window 和document常见的方法和属性

  Window对象常见的属性:  

  top 表明当前全部窗口的最顶层窗口
  parent 指当前窗口的父窗口
  self 指当前窗口
  status 指定当前窗口状态栏中的信息

  Window对象常见的方法:

  alert 显示带有一个“肯定”按钮的对话框
  confirm 显示带有“肯定”和“取消”两个按钮的对话框
  open 打开一个新的窗口
  close 关闭用户打开的窗口

  Document常见属性: 

  title 设置文档标题,也就是html的标签
  bgColor 设置页面的背景色
  URL 设置url属性
  fileSize 文件大小

  Document常见的方法:  

  write() 动态向页面写入内容
  createElement(Tag) 建立一个HTML标签
  getElementById(ID) 得到指定id的对象
  getElementsByName(Name) 得到以前Name的对象

 

3一、如何添加HTML元素的事件,有几种方法

  标签之中直接添加 onclick="fn()"

  JS添加 btn.onclick = method

  绑定事件 obj.addEventListener('click', method, false)

 

3二、使用js去除字符串空格

  str.trim()

  使用replace正则匹配str.replace(/\s*/g,"")

 

3三、什么是闭包,有什么优缺点

  在Js中当函数套函数,子函数使用了父函数的参数或者变量,而且子函数被外界所使用(没有释放),

  此时父函数的参数和变量,是不会被浏览器垃圾回收机制立马收回,这个时候父级造成了闭包环境。

function fn(){
     let a = 10;
     return function(){
        console.log(a);
      }
 }
 let f = fn();
console.dir(f);// 控制台中的closure就表明闭包

  优势:

  保护—闭包会造成私有做用域,保护里面的私有变量不受外界干扰

  存储—闭包能够把父函数的参数或变量存储起来

  缺点:

  相对于普通函数要消耗内存,闭包使用不当将会在IE(IE9以前)中形成内存泄漏

  

3四、理解的JavaScript垃圾回收机制

  Js具备自动垃圾回收机制。垃圾收集器会按照固定的时间间隔周期性的执行

  垃圾回收机制主要有两种方法:

  一、标记清除法 

  打开页面时,先把全部的变量打上标记,而后把被使用的变量清除标记。若是下次查询以前标记的没有被引用,此时就回收

  二、引用计数法

  变量每用一次就记录一次,一开始为0,下次引用+1,每少用一次就-1。当变为0时候 就清空回收

 

  直接给变量赋值一个null的地址能够解决闭包消耗的内存

  

3五、什么状况会引发内存泄漏,产生缘由及解决方案?

  1)意外的全局变量引发的内存泄漏

  缘由:全局变量,不会被回收

  解决:可使用严格模式避免

  2)闭包引发的内存泄漏

  缘由:闭包能够维持函数内局部变量,使其得不到释放

  解决:将事件处理函数定义在外部,解除闭包,或者在定义事件处理函数的外部函数中,删除对dom的引用

   3)没有清理的DOM元素引用

  缘由:虽然别的地方删除了,可是对象中还存在对dom的引用

  解决:手动删除便可

  4) 忘记的定时器或者回调

  缘由:定时器中有dom的引用,即便dom删除了,可是定时器还在

  解决:手动清除定时器和dom

 

3六、什么是原型,什么是原型链,二者关系

  原型(prototype):函数自带的属性,函数的实例化对象找不到某个属性或者方法,必定会去构造函数的原型下去找

  原型链(__proto__):实例化对象身上自带一个属性

  原型关系链:函数的实例化对象找不到某个属性或方法,必定会去构造函数的原型下去找,若是尚未会去原型下的原型链查找,直到找到Object.prototype为止

  二者关系:实例化对象的原型链 === 构造函数的原型

 

3七、如何合并两个数组

//第一种 
var arr1=[1,2,3];
var arr2=[4,5,6];
arr1 = arr1.concat(arr2);
console.log(arr1); 

//第二种
var arr1=[1,2,3];
ar arr2=[4,5,6];
Array.prototype.push.apply(arr1,arr2);
console.log(arr1);

 

3八、简述this出现的状况

  1)全局下的this是window
  2)单纯的函数名+括号执行,this是window
  3)匿名函数自执行,this是window
  4)定时器中的this是window
  5)事件触发,触发谁this就是谁
  6)对象方法中,.前面是谁 this就指向谁
  7)构造函数中this是实例化对象
  8)严格模式下this是undefined
  9)箭头函数中this指向上一级
  10)箭头函数中this暴露在外面就指向window

 

3九、函数声明和函数表达式的区别

fn()      //不会报错
function fn(){
     //声明
}

fn1()      //会报错:fn1 is not a function 
     var a = function(){
      //表达式
}

 

40、说一下对变量提高的理解

  在某一做用域中,声明变量的语句会默认解析,在该做用域的最开始就已经声明了

 

4一、Js有哪些解决异步的方案

  1)callback 回调函数
  2)promise
  3)事件监听
  4)async await

 

4二、new以后发生了什么

  使用new以后不用加括号同样会执行函数
  new以后this变为实例化对象
  默认返回值就不是undefined而是实例化对象
  写了return,若是return后面是简单类型,返回结果依然是实例化对象,若是是复合类型,返回结果则是这个复合类型

4三、写一个原生的xhr请求过程,readystate的几种状态 分别什么含义?

    let xhr = new XMLHttpRequest();
    xhr.open('get','./package.json');
    xhr.onreadystatechange = function () {
       if(xhr.readyState == 4 && xhr.status == 200) {
           let result = JSON.parse(xhr.responseText);
           console.log(result.name)
       }
    };
    xhr.send()

  readyState的几种状态

  0:请求未初始化(此时尚未调用open)
  1:服务器链接已创建,已经发送请求开始监听
  2:请求已接收,已经收到服务器返回的内容
  3:请求处理中,解析服务器响应内容
  4:请求已完成,且响应就绪

 

4四、什么是做用域、做用域链

  做用域分为全局做用域、局部做用域(包括es6新增块级做用域)

  简单理解做用域就是一个独立的空间,让变量不会暴露。不一样做用域下同名变量不会冲突

  当前做用域未定义的变量(自由变量)会向父级做用域查找,若是父级没有再一层层往上找,直到全局做用域,这种一层层的关系称为做用域链

 

4五、浅拷贝和深拷贝,实现的几种方式

  浅拷贝只复制某个对象的指针,而不复制对象自己,新旧对象仍是共享同一块内存

  深拷贝会开辟一个新的栈,新对象跟原对象不共享内存,修改新对象不影响原对象

  简单来讲假如B复制了A,当修改A时候B若是跟着改变就是浅拷贝,B没有改变则为深拷贝

  浅拷贝实现方式:

  Object.assign()、Array.prototype.concat()、Array.prototype.slice()

  深拷贝实现方式:

  JSON.parse(JSON.stringify())、手写递归、jquery的$.extend

 

4六、声明变量和声明函数的提高有什么区别

  变量声明提高:变量申明在进入执行上下文就完成了

  只要变量进行声明,不管在哪一个位置,js引擎都会将它的声明放在做用域的顶部

  函数声明提高:执行代码以前会先读取函数声明,能够把函数申明放在调用它的语句后面

  函数声明会覆盖变量声明,但不会覆盖变量赋值

 

4七、说一下变量提高机制  

  关于变量提高:
  不管条件成不成立都会先进行预解析
  匿名函数不会预解析
  es6不存在变量提高
  预解析的函数只解析一次(再遇到就会跳过)

  变量提高机制:
  1、变量提高
  1)先找var进行提高,赋值undefined,变量名同样,后者覆盖前者
  2)碰见函数,把函数名提高,赋值整个代码块
  函数名同名,后者覆盖前面,只看最后一个函数便可
  3)变量名与函数名同名状况下,最终留下代码块
  若是是函数声明,就只解读一次,遇到别的直接跳过
  函数表达式是带等号的因此会解读
  2、逐行解读代码
  只看带有等号的,若是有赋值,这个变量就是被赋值的值
  就算下面有函数声明也不会继续看了

 

4八、平时怎么样进行数据交互?若是后台没有提供数据怎么进行开发?mock数据与后台返回的格式不统一怎么办?

  由后台编写接口文档、提供数据接口实、前台经过ajax访问实现数据交互;

  在没有数据的状况下寻找后台提供静态数据或者本身定义mock数据

  返回数据不统一时编写映射文件 对数据进行映射

 

4九、什么是回调函数

  回调函数callback,就是一个函数执行完后马上执行另外一个

  它与箭头函数不同的是,它会拿返回的值做为参数

 

50、什么是构造函数?与普通函数有什么区别

  构造函数:是一种特殊的方法、主要用来建立对象时初始化对象,总与new运算符一块儿使用。建立对象的语句中构造函数的函数名必须与类名彻底相同

  与普通函数相比只能由new关键字调用,构造函数是类的标示

 

5一、ajax 和 jsonp区别

  相同点:都是请求一个url

  不一样点:ajax的核心是经过xmlHttpRequest获取内容

  jsonp的核心则是动态添加<script>标签来调用服务器 提供的js脚本

 

5二、JavaScript 有哪几种建立对象的方式?

  1)对象字面量的方式

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

  3)用工厂方式来建立(内置对象)

  4)用原型方式来建立

 

5三、举例ES5数组新增的哪些方法  

  1)forEach() 专门用来遍历数组
  2)map() 将调用的数组中每一个元素传递给指定的函数,并返回一个新数组
  3)filter() 过滤,返回知足条件的元素组成的新数组
  4)every()全部元素知足条件就返回true,有一个不知足条件就返回false
  5)some()全部元素只要有一个知足条件就返回true,都不知足条件就返回false
  6)reduce()累加器,数组中的每一个值(从左到右)开始缩减,最终计算为一个值

 

5四、获取随机数,要求是长度一致的字符串格式

var random = Math.random() + '0000000000';
var random = random.slice(0,10);

 

5五、移动端点击事件300ms延迟如何去掉,产生缘由 

  产生缘由:
  移动端会有双击缩放的这个操做,所以浏览器在click以后要等待300ms,看用户有没有下一次点击(也就是此次操做是否是双击)

  解决方法:

  1)禁用缩放

<meta name="viewport" content="user-scalable=no">
<meta name="viewport" content="initial-scale=1,maximum-scale=1">

  2)更改默认的视口宽度

<meta name="viewport" content="width=device-width"/>

  3)使用fastClick插件

window.addEventListener( "load", function() {
    FastClick.attach( document.body );
}, false );

 

5六、let有什么用,有了var为何还要用let ?

  ES6以前,声明变量只能用var,他有一些不合理的地方。

  let声明的变量拥有本身的块级做用域,且修复了var声明变量带来的变量提高问题

 

5七、请描述一下对事件冒泡、事件捕获、事件流的理解,怎么阻止冒泡

  事件冒泡:就是从目标元素自下而上一直到window(结束)这样一个过程

  事件捕获:就是从window自上而下一直到目标元素的这样一个过程

  通常是先执行捕获,后执行冒泡

  事件流:当一个事件触发时候,通常会经历3个过程,第一个为捕获阶段,第二个为目标阶段,第三个为冒泡阶段这么一个过程

  使用stopPropagation() 和 cancelBubble阻止冒泡

 

5八、什么是事件委托,有什么好处

  事件委托又叫事件代理。利用冒泡的原理,把事件加到父级上,触发执行效果

  好处:新添加的元素还会有以前的事件;提升性能

 

5九、拖拽会用到哪些事件?

  使用onmousedown、onmousemove、onmouseup来实现

 

60、什么是移动端点透事件,如何解决

  一个元素下有焦点(好比a 、input)在300毫秒以内让上层元素消失,这时手机会记录按下的位置并进行监听(是否触发两次)
  由于要监听是否双击,在第一次按下时捕捉到了坐标,正好坐标下有焦点元素,此时就会触发焦点元素
  

  解决方案:
  一、在上层元素消失时候延迟执行
  二、不使用焦点元素。好比以div代替a
  三、在touch事件里面调用e.preventDefault() 进行阻止

 

6一、简述一下你理解的面向对象

  把相同的代码抽象出来归为一类,把描述特征的功能挂在这个类的原型上的一种设计编程思想

  面向对象具备封装性,继承性,多态性。提升了大型程序的重用性和可维护性

 

6二、如何获取hash,并设置一个hash

  window.location.hash
  window.location.hash = 'p=0';

 

6三、js延迟加载的方式有哪些

   defer和async、动态建立DOM方式、按需异步载入js

 

6四、什么是事件默认行为,如何阻止

  当用户触发某个事件的时候,某种行为不是咱们主动写的而是浏览器默认就有的事件

  阻止:

  DOME0:return false
  DOME1:ev.preventDefault

 

6五、列举js经常使用的事件

  onmouseover鼠标移入、onmouseout鼠标移出

  onmouseenter鼠标穿过、onmouseleave鼠标离开

  onmousemove鼠标移动、onmousewheel 鼠标滚轮

  onclick点击、oncontextmenu右击菜单

  onchange改变内容、onfocus获取焦点、onblur失去焦点

  onresize改变窗口、onload加载完成

  onkeyup键盘抬起、onkeydown键盘按下

 

6六、构造函数、原型对象、实例对象三者的关系

  三者的关系是,每一个构造函数都有一个原型对象,原型对象上包含着一个指向构造函数的指针,而实例都包含着一个指向原型对象的内部指针。

  通俗的说,实例能够经过内部指针访问到原型对象,原型对象能够经过constructor找到构造函数

 

6七、Js中,有一个函数,执行对象查找时,永远不会去查找原型,这个函数是哪一个

  hasOwnProperty

  该函数方法返回一个布尔值,指出一个对象是否具备指定名称的属性。此方法没法检查该对象的原型链中是否具备该属性;该属性必须是对象自己的一个成员

 

6八、Canvas和SVG的比较

  canvas是一个标签(canvas)+一个对象(getcontext),全部图形图像都靠ctx绘制

  SVG几十个标签-每一个图形对应一个标签

  canvas位图技术,能够保存为.png,SVG矢量图技术,不能保存为位图

  canvas不能被搜索引擎爬虫所访问,SVG能够

  只能为整个Canvas绑定监听函数,SVG每一个图形(标签)均可以绑定事件监听函数

 

6九、如何规避javascript多人开发函数重名问题

  (1) 能够开发前规定命名规范,根据不一样开发人员开发的功能在函数前加前缀

  (2) 将每一个开发人员的函数封装到类中,调用的时候就调用类的函数,即便函数重名只要类名不重复便可

 

70、Cookie、Session、WebStorage的区别

  cookie:用来保存客户浏览器请求服务器页面的请求信息,大小4KB
  session:是一种服务器端的机制,服务器使用一种相似于散列表的结构来保存信息
  WebStorage提供了localStorage、sessionStorage两种API,大小都在5M
  cookie数据存放在客户的浏览器上,session数据放在服务器上
  cookie不是很安全,别人能够分析存放在本地的cookie
  session会在必定时间内保存在服务器上。当访问增多,会占用服务器的性能
  cookie:能够经过expires设置失效时间,不设置默认关闭浏览器即失效
  localStorage:除非手动清除,不然永久保存
  sessionStorage:仅在当前会话时候生效,关闭页面即失效

 

7一、什么是柯里化函数

  柯里化(Currying)就是把接收多个参数的函数转换成一个单个参数的函数

  而且返回接收余下的参数。返回结果是一个新函数

  函数柯里化的主要做用和特色是参数复用、提早返回和延迟执行

 

7二、如何理解防抖和节流

  防抖:短期内连续触发的事件,在某个时间期限内事件函数只执行一次

  节流:若是短期内大量触发同一事件,在函数执行一次以后,在指定的时间期限内再也不工做,直至过了这段时间才从新生效

 

7三、什么是单例模式,什么是工厂模式

  单例模式:把描述同一个事物的属性和方法放在一个内存空间下,起到分组的做用

  这样不一样事物之间的属性即便同名也不会冲突。单例模式实例化出来的对象是惟一的

  工厂模式:把相同代码封装起来,实现批量生产目的的一种模式。减小冗余代码

 

7四、举例几种经常使用的Object方法

  Object.assign()、Object.create()

  Object.defineProperty、Object.prototype.hasOwnProperty

 

7五、js实现继承的几种方式

  1)类式(call)继承

  2)拷贝继承

  3)原型继承

  4)寄生组合式继承

  5)es6中class继承

相关文章
相关标签/搜索