前端面试题(JS)

目录

1.js的内置类型

2.为什么 typeof 对象和数组以及null 都是object类型

3.let , const ,var 的区别

4.

5.

6.什么是原型链

7.什么是promise

8.new 做了什么 

9.什么是闭包

10.关于this指向问题

改变this的指向 

 11.箭头函数与普通函数的区别


1.js的内置类型

number ,string , boolean , 数组,对象 ,null  ,undefined ,symbol


2.为什么 typeof 对象和数组以及null 都是object类型

只设计了五种数据类型(对象、整数、浮点数、字符串和布尔值),完全没考虑null 。

typeof是底层用的二进制进行对比 object 的前三位是 000 ,null 机器数据是空 也是0 所以null 就是object 类型。

补充:

区分 (array , object ,null)

    判断数组的方式

    1.Array.isArray(arr)

    2.Object.prototype.toString.call(arr)

    3.arr instanceof Array

    4.Object.getPrototypeOf(arr) === Array.prototype

    5.arr.constructor == Array

    区分null

    1.null === null


3.let , const ,var 的区别

首先 const 和 let 都是 es6新增加的 let 是声明变量的

 const 是声明常量的 在声明的时候必须初始化 一旦初始化,就不能重新赋值了

let num = 10 ;
const name  = "张三"
//name ="李四" ; //报错

let不可以重复定义 ,var 可以

let num = 10 ;
//let num = 10 ; //报错

let 没有变量提升 , 在let 上面定义的话会报错

    console.log(num) //num is not defined

    let num = 10 ;

    暂时性死区 在一个作用域中 只要定义了let ,const  就会只在这个区域找不会向上查找了

    如果在let  const 之前调用 则会报错

let age = 19;
getAge()
function getAge() {
    console.log(age);//报错 age is not difined
    let age = '哈哈哈';
}

var没有块级作用域,let和const有块级作用域

    for (var i = 0; i <= 10; i++) {}

    console.log(i); //11

     for (let i = 0; i <= 10; i++) {}

    console.log(i); //报错


4.

var obj = {
    n:10,
    m:obj.n

}
console.log(obj);

会报错//

1.第一种解释 (不知道对不对) 

基本数据类型存栈,引用数据类型在堆里,堆里存的是obj的内容,  然后堆里是个新的内存空间吧  是先声明 然后再定义 然后在堆里查找 obj 的时候 堆的地址还没有形成 还没有赋值给obj  就是Undefined 

2.第二种解释

用对象的说法,就是 当使用花括号字面量表示的时候,JS引擎后台会使用new Object()来进行包装,最后赋值给 obj ,而这个时候obj还没创建,所以无法访问。


5.

var test = (function(i){
    return function(){
        console.log(i * 2)
    }
})(2)
test(5)

答案 :输出 4

6.什么是原型链

首先每个对象上都有一个__proto __属性 ,指向了父类的prototype。 当我们在一个对象上查找一个属性的时候 ,先去对象上去查找 ,找不到时去对象的__proto__ 也就是父类的prototype上去查找,直到找到Object.prototype上,找不到的话就返回为null ,这就是原型链

7.什么是promise

promise 是一种解决异步程序的方案 ,比之前传统的解决方法更合理更强大。

其实promise相当于一个容器,里面装着异步请求的结果。

promise有三种状态:pending(进行中) ,resolve(成功) ,reject(失败)。

状态一旦改变就不会再受外界影响,只有异步操作的结果可以决定当前是哪种状态。

状态一旦改变就不会再次改变 。状态只会从pending到resolve 或者从pending到reject ,只要状态一旦改变 ,做任何操作都不会再次改变。

在项目中promise虽然解决了传统的回调地狱的问题 ,但是也需要不断地.then()去形成一个回调链,这样的代码其实很不美观,所以我们一般在项目中都会使用async  await ,使代码看起来像是同步的代码一样。

8.new 做了什么 

class Person {
    name:string,
    getName(){
        return this.name ;
    }
}

let p1 =  new Person();
  1. 首先创建一个新对象  var obj = {} ;
  2. 新对象继承构造函数的原型即 obj.__proto == Person.prototype
  3. 将Person对象的this指向新对象 ,相当于将属性和方法都加到新对象上去。Person.call(obj)
  4. 返回一个新对象 ,如果没有的话 返回this

9.什么是闭包

我的理解:

 在一个函数内返回一个变量或者函数,导致这个变量或者函数不会因为函数的调用结束而销毁的函数叫做闭包。

闭包可以在外部访问函数内部的变量,我们的程序中会经常用到闭包,但是闭包的使用不当同样会导致内存泄漏,所以我们要将所调用的方法置为null。

别人的理解:

函数嵌套函数,且内部函数调用父级作用域的变量就可以称之为闭包

闭包的优点可以读取外层函数内部的变量。延长局部变量的生命周期,实现变量数据共享。

缺点是由于闭包执行完成之后会把外层函数中的变量保存到了内存中,消耗内存,以及数据泄漏,存在安全隐患所以不能滥用闭包否则影响性能。

最好的方法就是在退出函数之前,将不使用的局部变量全部删除,这样减少内存消耗,优化性能

闭包的应用场景:防抖,节流,计时器

10.关于this指向问题

this永远指向最后一个调用他的对象

  • 在对象中定义的函数中的this指向调用的对象
let obj = {
    name:'zs',
    getName(){
        return this.name;
    }
}

obj.getName() // zs
  • 在普通函数中 、匿名函数自调回调函数中的this指向window(严格模式(use strict)下,this指向undefined 
getName(){
    console.log(this) //window对象
}
getName()
  • 在构造方法中 this指向被创建的对象的实例
class people{
    name ='zss' 
    constructor(name){
        console.log(this); //People{name:'zss'}
        this.name = name

    }
}
const p = new people('zs');
  • 在事件调用中 this指向dom元素
let box = document.getElementById('box')
box.onclick = function(){
    console.log(this); //<div id="box"> </div>
}
  • 箭头函数没有this指向 ,永远指向他的父级的this指向
let obj = {
    name:'zs',
    age:18 ,
    getName:()=>{
        console.log(this); //window
    }
}
obj.getName();
  • 其他的情况指向window或者undefined

改变this的指向 

this 指向可以改变的使用apply ,call ,bind都可以改变this 的指向

// 箭头函数没有this,所以不能使用call、apply、bind来改变this的指向
// const getNameFn = ()=>{
//     console.log(this); //window
// }
const getNameFn = function(){
    console.log(this); //obj
}
getNameFn.apply(obj);
getNameFn.call(obj);

区别:

  • apply:可以立即执行函数调用 ,接受两个参数 ,第一个参数是this的指向,第二个参数是数组,里面存放函数的参数
  • call:立即执行函数的调用 ,可以接收多个参数,第一个参数是this的指向,后面的参数按顺序传给函数
  • bind:创建了一个与原函数一样的函数,不会立即执行,需要手动调用 ,第一个也是this指向 ,改变了this是永久的不会再被改变  ,传入多个参数,传入的参数会被当成实参永久保存
const getNameFn = function(...ars){
    console.log(ars);
    console.log(this); //obj
}
getNameFn.apply(obj,[19]);
getNameFn.call(obj,18,19);

const a  = getNameFn.bind(obj ,10 ,20) ;
a()
const b =a.bind(Window );
b() //仍然指向obj 其中仍然存在 10 ,20

 11.箭头函数与普通函数的区别

  • 箭头函数没有this指向,箭头函数中的this是他的执行上下文的this指向 ,所以不能使用call、apply、bind来改变this的指向
  • 箭头函数没有caller,arguments,prototype

  • 箭头函数不能作为构造函数 ,不能使用new来调用
//普通函数
const Animal = function(name,age){
   this.name = name ;
   this.age = age ;
}
//箭头函数 
// const Animal = (name,age)=>{
//     this.name = name ;
//     this.age = age ;
//  }
const cat = new Animal('zs' ,18 )

console.log(cat);
  • 箭头函数不能重复命名参数
function fn(name,name) {
    console.log('fn:',name)
}
var fn2 = (name,name) => {
    console.log('fn2',name)
}
fn('zs','ls') // 'ls'
fn2('zs','ls') // 报错

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值