Javascript面试常问点

js暂时性死区

在ES6中新增的定义变量的关键字let和const,会带来一个暂时性死区的问题,暂时性死区简单来讲就是变量未定义就调用了。在ES6中letconst定义变量是没有变量提升这一功能的。所以才会造成暂时性死区这个问题。

在ES5中定义变量的关键字var会将变量名称全部提升到代码最前面将变量名进行行定义,再进行赋值。

// 相当于将一行定义变量的代码分成了两行执行

var a = 1;
    ↓
var a; // 在js的最顶部
a = 1;

let和const的区别

let是定义变量的,而const是定义常量的。

cosnt定义的常量如果是基本类型,值是不可以改变的。如果定义的是引用类型,那么引用类型中的值是看以改变的,只要堆地址不改变就行。

那么这里又涉及到了堆和栈。堆和栈其实只是内存存储数据的一个地方。

:一般用来存储引用数据类型的值。

:一般用来存储基本数据类型的变量名和值,引用类型的变量名和堆地址。

所以说const定义的常量的值是存在堆中的,而改变存储的值是可以的,但是栈中存储的堆地址却不会改变

bom包含哪些对象

navigator 包含有关浏览器的信息

localtion Location 对象包含有关当前 URL 的信息。

screen Screen 对象包含有关客户端显示屏幕的信息。

history History 对象包含用户(在浏览器窗口中)访问过的 URL。

window Window 对象表示浏览器中打开的窗口。

数组方法

concat 链接两个数组,返回值是合并后的数组,该方法不改变原数组

indexOf 检索数组中的某个值,如果这个值存在则返回这个值的索引,如果不存在的返回-1

lastIndexOf 从尾部检索数组中的某个值,如果这个值存在返回这个值的索引,不存在则返回-1

every 判断数组中的每一项是否符合条件,如果符合条件则返回true,否则返回false

some 判断数组中是否有符合条件的项,如果有则返回true,若没有则返回false

join 将数组中的每一项通过一个字符进行链接成一个字符串

pop 删除数组的最后一个元素,并返回该元素,此方法会改变原来的数组

shift 删除数组的第一个元素,并返回该元素,此方法会改变原来的数组

push 在数组的尾部添加一个元素,或多个元素,并返回新数组的长度,该方法会改变原数组

sort 数组排序,通过传入一个回调函数进行数组排序,此方法会修改原数组

reverse 反转数组,将数组进行颠倒过来,此方 法会改变原数组

slice 截取数组,传入两个参数一个是起始位置一个是结束位置,此方法不改变原数组,返回值是截取的数组

unshift 在数组的头部添加一个或多个元素,并返回新数组的长度,该方法会改变原数组

splice 截取数组,传入两个参数第一个是起始位置,第二个是数量,返回值是截取的数组,此方法改变原数组

split 将字符串根据某个特定的字符转化成数组。

forEach 遍历数组,将数组循环一遍。

map 映射数组,传入一个回调函数,并写入生成条件,生成对应条件的新数组,并返回这个新数组,此方法不改变原数组

filter 过滤数组,传入一个回调函数,写入筛选条件,返回一个满足条件的数组,此方法不改变原数组

reduce 迭代将数组中的每一项合并,最终计算出一个总值,返回出去

findIndex 查找某个元素的索引

flat 将多维数组转成一维数组。参数可以为数字,可以不传,同样也可以传为Infinity表示不管多少层嵌套均可转化成一维数组

flatMap 对原数组的每一个成员执行一个函数并返回一个新数组并且函数的执行结果均会跟在每一个成员后面

fill 使用制定的元素填充数组,其实就是用默认内容初始化数组。

Includes 函数判断是否包含某一元素,不能定位,它直接返回true或者false表示是否包含元素,对NaN一样能有有效。

静态方法

Array.isArray 判断是否是一个数组,是则返回true,否则返回false

Array.from 将一个类数组对象或者可遍历对象转换成一个真正的数组。

Array.of 将一系列值转换成一个数组

对象方法

Object.is 判断是否全等

Object.assign 浅复制

Object.keys 方法会返回一个由一个给定对象的自身可枚举属性名组成的数组。

Object.values 方法会返回一个由一个给定对象的自身可枚举属性的值组成的数组。

Object.entries 方法会返回一个由一个给定对象的自身可枚举的键值对组成的二维数组。

数值的扩展

Number.parseInt 将parseInt方法添加到了Number对象上,调用方式不变

Number.parseFloat 同上

Number.isNaN 同上

Number.isInteger 判断一个数是不是一个整数

Math.sign 判断一个数的正负 正数返回1负数返回-1

Math.trunc() 取整

Math.cbrt 开立方根

Math.sqrt 开平方根

字符串的扩展

${} 模板字符串

Includes 返回布尔值,表示是否找到了参数字符串。

startsWith 返回布尔值,表示参数字符串是否在原字符串的头部。

endsWith 返回布尔值,表示参数字符串是否在原字符串的尾部。

Repeat 参数值为介于0和正无穷大之间的整数 : [0, +∞) 。表示在新构造的字符串中重复了多少遍原字符串。

扩展运算符/...运算符

数组和对象

可以复制对象和数组

合并对象和数组

解构对象和数组

数组

将类数组转成真数组

将字符串转为字符数组

对象

将数组转换成对象

对象转成数组: Array.keys() Array.from转换

对象转数组必须每一项的键都是数字,并且必须是连续的,必须有length属性

新增数据类型

Set:

概念:

似于数组,但它的一大特性就是所有元素都是唯一的,没有重复。
我们可以利用这一唯一特性进行数组的去重工作。

数组去重实例:

let set6 = new Set([1, 2, 2, 3, 4, 3, 5])
console.log('distinct 1:', set6)

添加元素:

    Set.add(val)

删除元素:

    Set.delete(val)

判断元素是否存在:

    Set.has(val)

清除所有元素:

    Set.clear()

数组转set:

    New Set(arr);

Set转数组:

    […Set]

可以使用Set实例对象的keys()values()entries()方法进行遍历。

Set的键名和键值是同一个值,它的每一个元素的keyvalue是相同的,所有keys()values()的返回值是相同的,entries()返回的元素中的keyvalue是相同的。

在向Set加入值时,Set不会转换数据类型,内部在判断元素是否存在时用的类似于精确等于(===)的方法,“2”和2是不同的,NaN等于其自身。

WeakSet:

概念:

WeakSet和Set类似,同样是元素不重复的集合,它们的区别是WeakSet内的元素必须是对象,不能是其它类型。

特点:

1.元素必须是对象。

2.弱引用,不被计入垃圾回收

添加进WeakSet的元素对象,WeakSet不会对元素对像的引用计数加1,对于被添加进WeakSet的元素对象,只要该元素对象没有被除WeakSet以外的其他对象引用,就会被垃圾回收释放,在WeakSet中的该元素对象自动被释放,不会出现内存泄漏。

因为这一特性,其性能要比map要高,对于存储无顺序要求的,不重复的,临时存储的场景,可以使用它。

例子:

const ws = new WeakSet()
var a = {p1:'1', p2:'2'}

ws.add(a)
a = null
console.log(ws.has(a));

先将对象添加到WeakSet中,然后将对象设成null,然后再下面的has方法判定时,结果显示,表示WeakSet中已经不存在该对象。

3.不能遍历

因为其对内部的元素对象是弱引用,随时会被垃圾回收释放掉,所以其不支持size和forEach等遍历方法。

Map:

概念:

Javascript的Object本身就是键值对的数据结构,但实际上属性和值构成的是”字符串-值“对,属性只能是字符串,如果传个对象字面量作为属性名,那么会默认把对象转换成字符串,结果这个属性名就变成"[object Object]"

ES6提供了"值-值"对的数据结构,键名不仅可以是字符串,也可以是对象。它是一个更完善的Hash结构。

使用:

设置值:

Map.set(key,val)

获取值:

Map.get(key)

获取map的大小:

Map.size

判断是否存在:

Map.has(key)

删除键值对:

Map.delete(key)

清空map对象:

Map.clear()

Map也可以对set进行链式调用,同样可以使用for of 循环,也可以使用object的keys,values,entries的方法,forEach遍历同样可以使用

Symbol:

Symbol,是一种数据类型。在定义时直接调用即可。

例如:

    Var sy = Symbol();

唯一性,通常用作对象的键,永不重复。

深拷贝与浅拷贝

浅复制

object.assign({},obj)

把一个对象克隆一份给另一个对象,只能把元对象的基本数据类型克隆一份,引用类型克隆不了,

也就是说克隆后的对象改变了引用类型的数值,同时也会改变原对象的属性值

深拷贝

原对象的属性值无论是基本类型还是引用类型都是复制给新对象的,任何属性值之间不存在引用关系,也就是复制后的对象改变其中任何一个属性值都不会影响原对象

JSON.parse(JSON.stringify())配合使用

...复制对象

...也可以展开对象

let obj2 = {...obj}

数组合并

Object.assign({},obj1,obj2)

或者是

let obj = {...obj1,...obj2}

解构对象

    let obj = {x:1,y:1,z:3}
    let {x,y,...z}=obj

数组转对象

    let obj = {...[1,2,3,5,9,8]}

数组的每一个下标作为对象的建,

数组的每一个值作为对象的值

异步函数

概念

也叫async函数,解决异步嵌套的问题,异步函数是生成器函数的高级语法糖,也就是生成器函数的高级封装,比生成器函数更好用,一般使用异步函数配合Promise是最佳的消除异步嵌套的方案
语法:

在函数声明的时候添加一个async关键字,表明该函数是异步函数

async关键字是添加在function关键字前面

特性:

1.异步函数调用函数名,会立即执行函数的函数体

2.异步函数默认返回一个异步函数

    如果想要获取return后面的值需要通过返回值`.then(result=>{
    })`
    或者通过过`Promise.resolve`取值
    
    Promise.resolve(返回值).then( result =>{
    })
    
    不能通过返回值['[[PromiseValue]]']取值,这样取出来的值是undefined

3.async经常配合await关键字使用

await是个关键字 只能和异步函数配合使用
也就是await只能出现在异步函数中,否则会报错
await 表示 等待的意思
await 后面可以跟一个具体的数值或一个Promise实例或一个异步函数
异步函数里面的代码会按照同步的方式执行

闭包

ES5闭包:

两个函数嵌套,内(子)函数使用了,外(父)函数的变量或者参数,导致这个变量或者函数参数被保留了袭来,延长了变量或函数参数的使用周期,从而导致这个变量或者函数或者参数被内(子)函数去使用

ES6闭包:

两个作用域嵌套,内(子)作用域使用了,外(父)作用域的变量或者参数,导致这个变量或者参数被保留了袭来,延长了变量或参数的使用周期,从而导致这个变量或者参数被内(子)作用域去使用

Promise消除回调地狱

方法一:

/*需要借助Promise来消除回调嵌套       链式调用*/
let promiseAjax = function(json) {
    return new Promise((resolve, reject) => {
        $.ajax({
            url: json.url,
            dataType: json.dataType,
            type: 'json',
            success(data) {
                resolve(data);
            },
            error(err) {
                reject(err);
            }
        })
    })
}
promiseAjax({
    url: '1.json',
    type: 'get',
    dataType: 'json',
}).then(data => {
    console.log(data);
}).catch(erro => {

})

方法二:

/* 当所有的异步全部成功之后才会执行then,只要有一个异步执行失败,就会执行catch    all([promise,....]).then(allData = >{}).catch(err =>{})  */
let promiseAjax = url => {
    return new Promise((resolve, reject) => {
        $.ajax({
            url,
            dataType: 'json',
            success(data) {
                resolve(data)
            },
            error(err) {
                reject(err)
            }
        })
    })
}
let p1 = promiseAjax('1.json');
let p2 = promiseAjax('2.json');
Promise.all([p1, p2]).then(resolve => {
    console.log(resolve)
})

//jQuery3.X版本之后ajax方法中会自动返回一个Promise对象

Export 和 export default的区别

  1. export与export default均可用于导出常量、函数、文件、模块等
  2. 在一个文件或模块中,export、import可以有多个,export default仅有一个
  3. 通过export方式导出,在导入时要加{ },export default则不需要
    1. 输出单个值,使用export default
    2. 输出多个值,使用export
    3. export default与普通的export不要同时使用

Export 和 module.export的区别

通常exports方式使用方法是:

exports.[function name] = [function name]

moudle.exports方式使用方法是:

moudle.exports= [function name]

这样使用两者根本区别是

exports 返回的是模块函数

module.exports 返回的是模块对象本身,返回的是一个类

使用上的区别是

exports的方法可以直接调用

module.exports需要new对象之后才可以调用

面向对象的继承

ES6继承

Class A extends B{
    Constructor(){
        Super();
    }
    方法名(){
        Super.方法名();
    }
}

ES5继承

// 原型链式继承
function SuperType() {

    this.property = true;
    
}

SuperType.prototype.getSuperValue = function () {

    return this.property;
    
}
function SubType() {

    this.subpropertype = false;
    
}

SubType.prototype = new SuperType();

SubType.prototype.getSubValue = function () {

    return this.subpropertype;
    
}

var ins = new SubType();

console.log(ins.subpropertype);//false

console.log(ins.getSuperValue());//true


//构造函数式继承

function SuperType(){

    this.color=['1','2','3','4'];
    
}
function SubType(){

    SuperType.call(this);
    
}

var ins1=new SubType();

ins1.color.pop()

console.log(ins1.color);//[1,2,3]

var ins2=new SubType()

ins2.color.push('5');

console.log(ins2.color);//[1,2,3,4,5]

优点:可以在子类型构造函数中向超类型构造函数传递参数

缺点:在超类型的原型中定义的方法,对子类型而言也是不可见的,结果所有类型都只能ES6的新特性

Function Parent (){
}
Parent.prototype=function fn(){

}
Function Child(){
        Parent.apply(this,arguments)
}

New关键字的作用

// 因为JS中,对象都是new 对应的函数()创建出来的,

// new 关键字对函数的影响(new关键字到底做了什么):

// 1.在该函数内部创建一个对象

// 2.函数内部的this指向创建出来的的这个对象

// 3.对象的proto指向函数的prototype

// 4. 函数默认返回该对象

作用域链和原型链

作用域链

当代码在一个环境中执行时,会创建变量对象的一个作用域链(scope chain,不简称sc)来保证对执行环境有权访问的变量和函数的有序访问。

简单来说外面的不能访问作用域里定义的变量,作用域里定义的变量可以访问上级作用域的变量。

原型链

当试图访问一个对象的属性时,它不仅仅在该对象上搜寻,还会搜寻该对象的原型,以及该对象的原型的原型,依次层层向上搜索,直到找到一个名字匹配的属性或到达原型链的末尾。原型链的末尾就是Object对象。

防抖节流

防抖节流其实简单来说就是限制请求和函数的执行频率,让其在非常短的时间内达到只执行一次的目的,避免重复操作来浪费资源。

常见的就是使用定时器和时间戳来进行一个处理。

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

推荐阅读更多精彩内容