JavaScript面试题(一)

简介: JavaScript面试题(一)

1.★★ 介绍一下JS的内置类型有哪些?

空类型:null

未定义:undefined

布尔:boolean

数字:number

字符串:string

符号:symbol(ES6新增)

对象:object

除了对象之外,其他为基本类型.


2.★★★★ 介绍一下 typeof 区分类型的原理

typeof原理: 不同的对象在底层都表示为二进制,

在Javascript中二进制前(低)三位存储其类型信息


000: 对象

010: 浮点数

100:字符串

110: 布尔

1: 整数


typeof null 为"object",

原因是因为 不同的对象在底层都表示为二进制,

在Javascript中二进制前(低)三位都为0的话会被判断为Object类型,null的二进制表示全为0,

自然前三位也是0,所以执行typeof时会返回"object"


3.★★★ 介绍一下类型转换

/*-------------------显式转换---------------------*/
1. toString()      // 转化为字符串,不可以转null和underfined
2. Number()     // 转换为数字,字符串中有一个不是数值的字符,返回NaN
3. parseInt()    // 转换为数字,第一个字符不是数字或者符号就返回NaN
4. String()     // 转换为字符串, 
5. Boolean()     // 转换为布尔值
/*-------------------隐式转换(+-)---------------------*/
当 JavaScript 尝试操作一个 "错误" 的数据类型时,会自动转换为 "正确" 的数据类型
1. num  +  ""  -> String
2. num + bool -> num
// 当加号运算符时,String和其他类型时,其他类型都会转为 String;其他情况,都转化为Number类型
3. string - num -> num
// 其他运算符时, 基本类型都转换为 Number,String类型的带有字符的比如: 
4. 'a1' - num -> NaN
// 与undefined 一样。
/*-------------------隐式转换(逻辑表达式)---------------------*/
1. 对象和布尔值比较
对象和布尔值进行比较时,对象先转换为字符串,然后再转换为数字,布尔值直接转换为数字
[] == true;  //false  []转换为字符串'',然后转换为数字0,true转换为数字1,所以为false
2. 对象和字符串比较
对象和字符串进行比较时,对象转换为字符串,然后两者进行比较。
[1,2,3] == '1,2,3' // true  [1,2,3]转化为'1,2,3',然后和'1,2,3', so结果为true;
3. 对象和数字比较
对象和数字进行比较时,对象先转换为字符串,然后转换为数字,再和数字进行比较。
[1] == 1;  // true  `对象先转换为字符串再转换为数字,二者再比较 [1] => '1' => 1 所以结果为true
4. 字符串和数字比较
字符串和数字进行比较时,字符串转换成数字,二者再比较。
'1' == 1 // true
5. 字符串和布尔值比较
字符串和布尔值进行比较时,二者全部转换成数值再比较。
'1' == true; // true 
6. 布尔值和数字比较
布尔值和数字进行比较时,布尔转换为数字,二者比较。
true == 1 // true

4.★★★★ 说说你对 JavaScript 的作用域的理解。什么是作用域链?


在 JavaScript 中有两种作用域类型:

1. 局部作用域:只能在函数内部访问它们

2. 全局作用域:网页的所有脚本和函数都能够访问它


JavaScript 拥有函数作用域:每个函数创建一个新的作用域。

作用域决定了这些变量的可访问性(可见性)。

函数内部定义的变量从函数外部是不可访问的(不可见的)。


作用域链:

当查找变量的时候,会先从当前上下文的变量对象中查找,

如果没有找到,就会从父级(词法层面上的父级)执行上下文的变量对象中查找,

一直找到全局上下文的变量对象,也就是全局对象。

这样由多个执行上下文的变量对象构成的链表就叫做作用域链**


5.★★ 解释下 let 和 const 的块级作用域

/*------------let-----------*/
1. let声明的仅在块级作用域内有效,
2. let不会发生变量提升的现象,所以一定要在定义后使用,否则报错。
3. 暂时性死区:只要块级作用域内存在let命令,它所声明的变量就绑定这个区域,不再受外部影响。
4. 不允许重复声明,let不允许在相同作用域内,重复声明同一个变量:
/*-----------const----------*/
1. 声明一个只读的常量。一旦声明,常量的值就不能改变。
2. 一旦声明,就要立即初始化,否则也报错。
3. const命令声明的常量也不提升,同样存在暂时性死区,只能在声明的位置后使用。
4. 也不可以重复声明。


6.★★★★ 说说你对执行上下文的理解

执行上下文有且只有三类,全局执行上下文,函数上下文,与eval上下文(eval一般不会使用)


1. 全局执行上下文:

全局执行上下文只有一个,也就是我们熟知的window对象,我们能在全局作用域中通过this直接访问到它


2. 函数执行上下文

函数执行上下文可存在无数个,每当一个函数被调用时都会创建一个函数上下文;

需要注意的是,同一个函数被多次调用,都会创建一个新的上下文。


3. 执行上下文栈(下文简称执行栈)也叫调用栈,

执行栈用于存储代码执行期间创建的所有上下文,具有LIFO(Last In First Out后进先出,也就是先进后出)的特性。


JS代码首次运行,都会先创建一个全局执行上下文并压入到执行栈中,之后每当有函数被调用,

都会创建一个新的函数执行上下文并压入栈内;由于执行栈LIFO的特性,

所以可以理解为,JS代码执行完毕前在执行栈底部永远有个全局执行上下文。


7.★★★ 对闭包的看法,为什么要用闭包?说一下闭包的原理以及应用场景?闭包的 this 指向问题?

闭包的作用:
1. 在外部访问函数内部的变量
2. 让函数内的局部变量可以一直保存下去
3. 模块化私有属性和公共属性
闭包的原理:
全局变量生存周期是永久,局部变量生存周期随着函数的调用介绍而销毁。
闭包就是 在函数中定义且成为该函数内部返回的函数的自由变量 的变量,该变量不会随着外部函数调用结束而销毁。 
(注:不光是变量,函数内声明的函数也可以形成闭包)
当函数可以记住并访问所在的词法作用域,即使函数是在当前词法作用域之外执行,这时就产生了闭包。
闭包的应用场景:
// 1. 返回值 最常见的一种形式
    var fun_1 = function () {
      var name = "limo";
      return function () {      
        return name;
      }
    }
    var fun_1 = function () {
      var name = "limo";
      return name;
    }
    var fu_1 = fun_1();
    console.log("fu_1():" + fu_1());
// 2. 函数赋值 一种变形的形式是将内部函数赋值给一个外部变量
    var f2;
    var fun_2 = function () {
      var name = "limop"
      var a = function () {
        return name;
      }
      f2 = a;
    }
    f2();
    console.log(f2);
// 3. 函数参数 通过函数参数引用内部函数产生闭包
    var fn_3 = function (f3) {
      console.log(f3);
    }
    function fun_3() {
      var name = "limo";
      var a = function () {
        return name;
      }
      fn_3(a)
    }
    fun_3();
// 4. IIFE(自执行函数)
    var fn_4 = function (f4) {
      console.log(f4);
    };
    (function fun_4() {
      var name = "limo";
      var a = function () {
        return name;
      }
      fn_3(a)
    })();
// 5. 循环赋值
    function foo(){
      var arr = [];
      for(var i = 0; i < 10; i++){
        arr[i] = (function(n){
          return function(){
            return n;
          }
        })(i)
      }
      return arr;
    }
    var bar = foo();
    console.log(bar[3]());
// 6. getter和setter
    // getter和setter函数来将要操作的变量保存在函数内部,防止暴露在外部
    var getValue, setValue;
    (function () {
      var num = 0
      getValue = function () {
        return num
      }
      setValue = function (v) {
        if (typeof v === 'number') {
          num = v
        }
      }
    })();
    console.log(getValue());    //0
    setValue(10);
    console.log(getValue())     //10
// 7.迭代器(计数器)
    var add = function(){
      var num = 0;
      return function(){
        return ++num;
      }
    }();
    console.log(add());
    console.log(add());
    function setUp(arr){
      var i = 0;
      return function(){
        return arr[i++];
      }
    }
    var next = setUp(['Steve','Alex','LingYi']);
    console.log(next());
    console.log(next());
    console.log(next());
// 8.触发事件
    window.onload = function (){
      var btn = document.querySelector('.btn')
      btn.onclick = function (){//事件相当于在全局触发
        btn.style.color = 'red'//保持对上层作用域的引用 btn
        console.log('abc')
        // this
      }
    }
闭包的this指向问题:
var myNumber = {
  value: 1,
  add: function(i){
    var helper = function(i){
        console.log(this);
          this.value += i;
    }
    helper(i);
  }
}
myNumber.add(1);
1.this指向window对象(因为匿名函数的执行具有全局性,所以其this对象指向window);
2.不能实现value加1(每个函数在被调用时都会自动取得两个特殊变量,this和arguments,内部函数在搜索这两个对象时,只会搜索到其活动对象为止,所以不能实现访问外部函数的this对象);
3.修改代码实现正确功能
第一种解决方法:
var myNumber={
    value:1,
    add:function(i){
        var that=this;//定义变量that用于保存上层函数的this对象
        var helper=function(i){
             console.log(that);
        that.value+=i;
    }
    helper(i);
    }
}
myNumber.add(1);
第二种解决方法:
var myNumber={
    value:1,
    add:function(i){
        var helper=function(i){
            this.value+=i;
        }
        helper.apply(this,[i]);//使用apply改变helper的this对象指向,使其指向myNumber对象
    }
}
myNumber.add(1);
第三种解决方法
var myNumber={
    value:1,
    add:function(i){
        var helper=function(i){
            this.value+=i;
        }.bind(this,i);//使用bind绑定,和apply相似,只是它返回的是对函数的引用,不会立即执行
        helper(i);
    }
}
myNumber.add(1);

8.★★★ 简述闭包的问题以及优化

闭包的缺点:占用内层空间 大量使用闭包会造成栈溢出

由于闭包会一直占用内存空间,直到页面销毁,我们可以主动将已使用的闭包销毁:

将闭包函数赋值为null 可以销毁闭包


9.★★★ 如何确定 this 指向?改变 this 指向的方式有哪些?

 this 指向:
1. 全局上下文(函数外)
无论是否为严格模式,均指向全局对象。注意:严格模式下全局对象为undifined
2. 函数上下文(函数内)
默认的,指向函数的调用对象,且是最直接的调用对象:
简单调用,指向全局对象注意:严格模式下全局对象为undifined,某些浏览器未实现此标准也可能会是window
改变this指向的方式:
1. 第一种: new关键字改变this指向
//构造函数版this
function Fn(){
    this.user = "李某";
}
var a = new Fn();
console.log(a.user); //李某
/*----------------------------------------*/
2. 第二种: call()
// 把b添加到第一个参数的环境中,简单来说,this就会指向那个对象
var a = {
    user:"李某",
    fn:function(){
        console.log(this.user); //李某
    }
}
var b = a.fn;
b.call(a);  //若不用call,则b()执行后this指的是Window对象
/*----------------------------------------*/
3. 第三种:apply()
// apply方法和call方法有些相似,它也可以改变this的指向,也可以有多个参数,但是不同的是,第二个参数必须是一个数组
var a = {
    user:"李某",
    fn:function(){
        console.log(this.user); //李某
    }
}
var b = a.fn;
b.apply(a);
/*----------------------------------------*/
4. 第四种:bind()
// bind方法返回的是一个修改过后的函数,
// bind也可以有多个参数,并且参数可以执行的时候再次添加,但是要注意的是,参数是按照形参的顺序进行的。
var a = {
    user:"李某",
    fn:function(){
        console.log(this.user); //李某
    }
}
var b = a.fn;
var c = b.bind(a);
c();

10.★★★ 介绍箭头函数的 this

由于箭头函数不绑定this, 它会捕获其所在(即定义的位置)上下文的this值, 作为自己的this值

1. 所以 call() / apply() / bind() 方法对于箭头函数来说只是传入参数,对它的 this 毫无影响。

2. 考虑到 this 是词法层面上的,严格模式中与 this 相关的规则都将被忽略

作为方法的箭头函数this指向全局window对象,而普通函数则指向调用它的对象


11.★★★ 谈一下你对原型链的理解,画一个经典的原型链图示

原型链:

因为每个对象和原型都有原型,对象的原型指向原型对象,

而父的原型又指向父的父,这种原型层层连接起来的就构成了原型链。


12.★★★ ES5/ES6 的继承除写法以外还有什么区别?

  • ES5 的继承实质上是先创建子类的实例对象,然后再将父类的方法添加 到 this 上(Parent.apply(this))
  • ES6 的继承机制完全不同,实质上是先创建父类的实例对象 this(所以必 须先调用父类的super()方法),然后再用子类的构造函数修改 this。
  • ES5 的继承时通过原型或构造函数机制来实现。
  • ES6 通过 class 关键字定义类,里面有构造方法,类之间通过 extends 关 键字实现继承。
  • 子类必须在 constructor 方法中调用 super 方法,否则新建实例报错。因 为子类没有自己的 this对象,而是继承了父类的 this 对象,然后对其进行加工。 如果不调用 super 方法,子类得不到 this 对象。
  • 注意 super 关键字指代父类的实例,即父类的 this 对象。 注意:在子类构造函数中,调用 super 后,才可使用 this关键字,否则报错

13.★★★★ 你对事件循环有了解吗?说说看!

Event Loop(事件循环)中,每一次循环称为 tick, 每一次tick的任务如下:


  • 执行栈选择最先进入队列的宏任务(通常是script整体代码),如果有则执行
  • 检查是否存在 Microtask,如果存在则不停的执行,直至清空 microtask 队列
  • 更新render(每一次事件循环,浏览器都可能会去更新渲染)
  • 重复以上步骤


宏任务 > 所有微任务 > 宏任务,如下图所示:

从上图我们可以看出:


1、将所有任务看成两个队列:执行队列与事件队列。

2、执行队列是同步的,事件队列是异步的,宏任务放入事件列表,微任务放入执行队列之后,事件队列之前。

3、当执行完同步代码之后,就会执行位于执行列表之后的微任务,然后再执行事件列表中的宏任务


14.★★★★ 微任务和宏任务有什么区别?

46f533decb36abca1bed81d62bb7279.png


15.★★★★★ 浏览器和 Node 事件循环的区别?

浏览器中的事件循环:



Node中的事件循环:


Node 中的 Event Loop 和浏览器中的是完全不相同的东西。Node.js 采用 V8 作为 js 的解析引擎,而 I/O 处理方面使用了自己设计的 libuv,libuv 是一个基于事件驱动的跨平台抽象层,封装了不同操作系统一些底层特性,对外提供统一的 API,事件循环机制也是它里面的实现


Node.js 的运行机制如下:


  • V8 引擎解析 JavaScript 脚本。
  • 解析后的代码,调用 Node API。
  • libuv 库负责 Node API 的执行。它将不同的任务分配给不同的线程,形成一个 Event Loop(事件循环),以异步的方式将任务的执行结果返回给 V8 引擎。
  • V8 引擎再将结果返回给用户。


16.★★★ 异步解决方案有哪些?

解决方案:
/*---------1.回调函数callback:----------*/
被作为实参传入另一函数,并在该外部函数内被调用,用以来完成某些任务的函数。如setTimeOut,ajax请求,readFile等。
例:
function greeting(name) {
  alert('Hello ' + name);
}
function processUserInput(callback) {
  var name = prompt('请输入你的名字。');
  callback(name);
}
processUserInput(greeting);
优点:
解决了异步的问题。
缺点:
回调地狱:多个回调函数嵌套的情况,使代码看起来很混乱,不易于维护。
/*---------2.事件发布订阅:---------*/
当一个任务执行完成后,会发布一个事件,当这个事件有一个或多个‘订阅者’的时候,会接收到这个事件的发布,执行相应的任务,这种模式叫发布订阅模式。如node的events,dom的事件绑定
例:
document.body.addEventListener('click',function(){
  alert('订阅了');
},false);
document.body.click(); 
优点:
时间对象上的解耦。
缺点:
消耗内存,过度使用会使代码难以维护和理解
/*---------3.Promise:---------*/
Promise是es6提出的异步编程的一种解决方案。
Promise 对象有三种状态:
pending: 初始状态,既不是成功,也不是失败状态。
fulfilled: 意味着操作成功完成。
rejected: 意味着操作失败。
promise的状态只能从pending变成fulfilled,和pending变成rejected,状态一旦改变,就不会再改变,且只有异步操作的结果才能改变promise的状态。
例:
let promise = new Promise(function (resolve, reject) {
    fs.readFile('./1.txt', 'utf8', function (err, data) {
        resolve(data)
    })
})
promise
    .then(function (data) {
        console.log(data)
    })
优点:
解决了回调地狱的问题,将异步操作以同步操作的流程表达出来。
缺点:
无法取消promise。如果不设置回调函数,Promise内部抛出的错误,不会反应到外部。当处于Pending状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)。当执行多个Promise时,一堆then看起来也很不友好。
/*---------4.Generator:---------*/
Generator是es6提出的另一种异步编程解决方案,需要在函数名之前加一个*号,函数内部使用yield语句。Generaotr函数会返回一个遍历器,可以进行遍历操作执行每个中断点yield。
例:
function * count() {
  yield 1
  yield 2
  return 3
}
var c = count()
console.log(c.next()) // { value: 1, done: false }
console.log(c.next()) // { value: 2, done: false }
console.log(c.next()) // { value: 3, done: true }
console.log(c.next()) // { value: undefined, done: true }
优点:
没有了Promise的一堆then(),异步操作更像同步操作,代码更加清晰。
缺点:
不能自动执行异步操作,需要写多个next()方法,需要配合使用Thunk函数和Co模块才能做到自动执行。
/*---------5.async/await:---------*/
async是es2017引入的异步操作解决方案,可以理解为Generator的语法糖,async等同于Generator和co模块的封装,async 函数返回一个 Promise。
例:
async function read() {
 let readA = await readFile('data/a.txt')
 let readB = await readFile('data/b.txt')
 let readC = await readFile('data/c.txt')
 console.log(readA)
 console.log(readB)
 console.log(readC)
}
read()
优点:
内置执行器,比Generator操作更简单。async/await比*yield语义更清晰。返回值是Promise对象,可以用then指定下一步操作。代码更整洁。可以捕获同步和异步的错误。


17.★★★ async 和 await 、promise的区别 和 这两个的本质


/---------Promise概念:---------/

Promise 是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理和更强大,简单地说,Promise好比容器,里面存放着一些未来才会执行完毕(异步)的事件的结果,而这些结果一旦生成是无法改变的


/---------async await概念:---------/

async await也是异步编程的一种解决方案,他遵循的是Generator 函数的语法糖,他拥有内置执行器,不需要额外的调用直接会自动执行并输出结果,它返回的是一个Promise对象。


两者的区别:

Promise的出现解决了传统callback函数导致的“地域回调”问题,但它的语法导致了它向纵向发展行成了一个回调链,遇到复杂的业务场景,这样的语法显然也是不美观的。


async await代码看起来会简洁些,使得异步代码看起来像同步代码,await的本质是可以提供等同于”同步效果“的等待异步返回能力的语法糖,只有这一句代码执行完,才会执行下一句。


async await与Promise一样,是非阻塞的。

async await是基于Promise实现的,可以说是改良版的Promise,它不能用于普通的回调函数。


18.★★★ 简述 aync await 的好处

1. async/await最重要的好处是同步编程风格

2. async/await有本地浏览器支持。截至今天,所有主流浏览器 查看都完全支持异步功能。

3. async关键字。它声明 getBooksByAuthorWithAwait()函数返回值确保是一个 promise,以便调用者可以安全调用 getBooksByAuthorWithAwait().then(…)或 await getBooksByAuthorWithAwait()


19.★★★ 移动端点击事件 300ms 延迟如何去掉?原因是什么?

300毫秒原因:

当用户第一次点击屏幕后,需要判断用户是否要进行双击操作,于是手机会等待300毫秒,

解决方法:FastClick.js

FastClick 是 FT Labs 专门为解决移动端浏览器 300 毫秒点击延迟问题所开发的一个轻量级的库。FastClick的实现原理是在检测到touchend事件的时候,

会通过DOM自定义事件立即出发模拟一个click事件,并把浏览器在300ms之后的click事件阻止掉。


20.★★★ Cookie 有哪些属性?其中HttpOnly,Secure,Expire分别有什么作用?

Cookie属性:
name  字段为一个cookie的名称。
value  字段为一个cookie的值。
domain  字段为可以访问此cookie的域名。
path  字段为可以访问此cookie的页面路径。 比如domain是abc.com,path是/test,那么只有/test路径下的页面可以读取此cookie。
expires/Max-Age   字段为此cookie超时时间。若设置其值为一个时间,那么当到达此时间后,此cookie失效。不设置的话默认值是Session,意思是cookie会和session一起失效。当浏览器关闭(不是浏览器标签页,而是整个浏览器) 后,此cookie失效。
Size  字段 此cookie大小。
http  字段  cookie的httponly属性。若此属性为true,则只有在http请求头中会带有此cookie的信息,而不能通过document.cookie来访问此cookie。
secure   字段 设置是否只能通过https来传递此条cookie
1 secure属性
当设置为true时,表示创建的 Cookie 会被以安全的形式向服务器传输,也就是只能在 HTTPS 连接中被浏览器传递到服务器端进行会话验证,如果是 HTTP 连接则不会传递该信息,所以不会被窃取到Cookie 的具体内容。
2 HttpOnly属性
如果在Cookie中设置了"HttpOnly"属性,那么通过程序(JS脚本、Applet等)将无法读取到Cookie信息,这样能有效的防止XSS攻击。
3 Expire属性
设置Cookie的失效时间:

21.★★★★ 如何实现函数的柯里化?比如 add(1)(2)(3)

/*-----解决方法1:-----*/
function add () {
  var args = Array.prototype.slice.call(arguments);
  var fn = function () {
    var sub_arg = Array.prototype.slice.call(arguments);
   // 把全部的参数聚集到参数的入口为一个参数: args.concat(sub_arg)
    return add.apply(null, args.concat(sub_arg));
  }
  fn.valueOf = function () {
  return args.reduce(function(a, b) {
      return a + b;
    })
  }
  return fn;
}
console.log(add(1,2)) // 3
console.log(add(1)(2)) // 3
console.log(add(1)(2)(3)) // 6
console.log(add(1,2,3)(4)) // 10
/*-----解决方法2:-----*/
function add () {
    var args = Array.prototype.slice.call(arguments);
    var fn = function () {
        // 把参数都放在一个相当于全局变量的 args 里面 
        args.push(...arguments)
        return fn;
    }
    fn.valueOf = function () {
        return args.reduce(function(a, b) {
            return a + b;
        })
    }
    return fn;
}
console.log(add(1,2)) // 3
console.log(add(1)(2)) // 3
console.log(add(1)(2)(3)) // 6
console.log(add(1,2,3)(4)) // 10


22.★★★★ 什么是反柯里化

在JavaScript中,当我们调用对象的某个方法时,

其实不用去关心该对象原本是否被设计为拥有这个方法,这是动态类型语言的特点。

可以通过反柯里化(uncurrying)函数实现,让一个对象去借用一个原本不属于他的方法。


23.★★ 将 [1,2] 与 [3,[4]] 合并为 [1,2,3,[4]]

JS数组合并方法:
let arr3 = [1,2].concat([3,[4]]);    //[1,2,3,[4]]


24.★★ Array.forEach() 与 Array.map() 的区别,Array.slice() 与 Array.splice() 的区别?

/*-----forEach-----*/
forEach不支持return,对原来的数组也没有影响。但是我们可以自己通过数组的索引来修改原来的数组
var ary = [12,23,24,42,1];
var res = ary.forEach(function (item,index,input) {
     input[index] = item*10;
})
console.log(res);//-->undefined;
console.log(ary);//-->会对原来的数组产生改变;
/*-----map-----*/
map支持return返回值,也不影响原数组,但是会返回一个新的数组
var ary = [12,23,24,42,1];
var res = ary.map(function (item,index,input) {
     return item*10;
})
console.log(res);//-->[120,230,240,420,10];
console.log(ary);//-->[12,23,24,42,1];
array.slice(start,end)函数是取array数组中指定的一些元素:
根据数组下标start和end,两个参数为取值的开始和结束下标,取出的值不包括end位置的值,生成一个新数组作为返回值;
这里end可以为空,为空则取从start位置到数组结尾的元素,生成新数组。
array.splice(start,length,insert_one......)函数则是直接在原数组进行删除、添加、替换元素的操作:
start为数组删除元素的开始下标,
length为从start位置开始array删除元素的个数,
后面参数为删除之后array重新插入的数据内容,插入位置为删除位置,而非数组开头或末尾,
返回值为array删除的元素组成的数组。
显而易见,splice函数可以用来对数组元素进行替换。由splice操作后的数组array,数组中内容如果已经改变,就再也找不回array在splice之前的模样。


25.★★ 将 1234567 转换为 1,234,567

function fun(n){
    return String(n).replace(/(?!^)(?=(\d{3})+\.)/g, ",") 
}


26.★★★ bind 的作用是什么?

bind()方法主要就是将函数绑定到某个对象,

bind()会创建一个函数,函数体内的this对象的值会被绑定到传入bind()第一个参数的值


27.★★Promise.resolve(Promise.resolve(1)).then(console.log) 输出?

// 答案:1


28.★★★ var let const的区别

  1. var声明的变量会挂载在window上,而let和const声明的变量不会
  2. var声明变量存在变量提升,let和const不存在变量提升
  3. let和const声明形成块作用域
  4. 同一作用域下let和const不能声明同名变量,而var可以
  5. 使用let/const声明的变量在当前作用域存在暂存死区
  6. const一旦声明必须赋值,不能使用null占位,声明后不能再修改,如果声明的是复合类型数据,可以修改其属性


29.★★★ document load 和 documen ready的区别

DOM文档解析:

解析html结构

加载脚本和样式文件

解析并执行脚本

构造html的DOM模型 //ready

加载图片等外部资源文件

页面加载完毕 //load


document load:

load是当页面所有资源全部加载完成后(包括DOM文档树,css文件,js文件,图片资源等),

执行一个函数,load方法就是onload事件。


documen ready:

构造html的DOM模型加载完毕后触发


30.★★★ 如何自定义事件?

自定义事件
事件是与DOM交互的最常见的方式。通过实现自定义事件,可以让事件用于非DOM代码中。
思想:创建一个管理事件的对象,让其他对象监听那些事件。
基本模式:
function EventTarget(){
    this.handlers = {};
}
EventTarget.prototype = {
    constructor:EventTarget,
    addHandler:function(type,handler){
        if(typeof this.handlers[type] === "undefined"){
            this.handlers[type] = [];
        }
        this.handlers[type].push(handler);
    },
    fire:function(event){
        if(!event.target){
            event.target = this;
        }
        if(this.handlers[event.type] instanceof Array){
            const handlers = this.handlers[event.type];
            handlers.forEach((handler)=>{
                handler(event);
            })
        }
    },
    removeHandler:function(type,handler){
        if(this.handlers[type] instanceof Array){
            const handlers = this.handlers[type];
            for(var i = 0,len = handlers.length; i < len; i++){
                if(handlers[i] === handler){
                    break;
                }
            }
            handlers.splice(i,1);
        }
    }
}


JavaScript面试题(二) https://developer.aliyun.com/article/1399325

相关文章
|
6天前
|
前端开发 JavaScript
JavaScript新科技:PostCSS的安装和使用,2024年最新2024网易Web前端高级面试题总结
JavaScript新科技:PostCSS的安装和使用,2024年最新2024网易Web前端高级面试题总结
|
6天前
|
前端开发 JavaScript
JavaScript:this-关键字,2024中级前端开发面试解答
JavaScript:this-关键字,2024中级前端开发面试解答
|
6天前
|
JSON JavaScript 前端开发
web前端入门到实战:32道常见的js面试题,2024年最新秋招是直接面试吗
web前端入门到实战:32道常见的js面试题,2024年最新秋招是直接面试吗
|
6天前
|
JavaScript 前端开发
web前端JS高阶面试题(1),高级开发工程师面试
web前端JS高阶面试题(1),高级开发工程师面试
|
6天前
|
JSON 前端开发 JavaScript
【JavaScript】面试手撕深拷贝(2),2024年最新nacos面试题及答案
【JavaScript】面试手撕深拷贝(2),2024年最新nacos面试题及答案
【JavaScript】面试手撕深拷贝(2),2024年最新nacos面试题及答案
|
6天前
|
JSON JavaScript 前端开发
【JavaScript】面试手撕深拷贝(1),面试前必看的一本书书籍是什么
【JavaScript】面试手撕深拷贝(1),面试前必看的一本书书籍是什么
|
6天前
|
缓存 前端开发 JavaScript
Javascript模块化开发基础,最新美团点评前端团队面试题
Javascript模块化开发基础,最新美团点评前端团队面试题
|
7天前
|
JavaScript 前端开发 程序员
javascript基础(入门),当上项目经理才知道,推荐程序员面试秘籍
javascript基础(入门),当上项目经理才知道,推荐程序员面试秘籍
|
8天前
|
自然语言处理 JavaScript 前端开发
三个JavaScript面试题
【5月更文挑战第7天】- 闭包是JavaScript函数能记住词法作用域,即使在外部执行。示例:计数器函数`createCounter()`返回访问`count`的匿名函数,每次调用计数递增。 - 事件循环处理异步操作,通过检查任务队列执行回调。示例:`setTimeout`异步任务在3秒后添加到队列,待执行,输出顺序为同步任务1、2,然后异步任务1。 - 箭头函数是ES6简洁的函数定义方式,如`greet = name => `Hello, ${name}!`。它没有自己的`this`,不适用作构造函数。
32 6
|
8天前
|
存储 JavaScript 前端开发
每日一道javascript面试题(九)函数的参数可以和函数体中的变量重名吗
每日一道javascript面试题(九)函数的参数可以和函数体中的变量重名吗