一.js原始范例:
在js中,存在着6种原始值:
* boolean
* number
* string
* undefined
* null
* symbol
注重: 虽然typeof null输出的是object,然则null并非object范例,由于初期的bug;
number范例是浮点数范例,所以才会有js精度题目涌现。0.1+0.2 !== 0.3。 原始范例存储的都是值,是没有函数可以挪用的。
- symbol范例: symbol范例的对象永久不相等,即使建立他们的时刻传入了雷同的值,可以借助此特征处置惩罚属性名的争执题目。
for…in..拿不到symbol范例的属性值,而且要用[]的体式格局来读取symbol范例的属性值,用点的体式格局读不到。
二.对象(Object)范例:
在js中,除了原始范例其他的就是对象范例了。
Q1:对象范例和原始范例的差别之处?
答:对象范例和原始范例差别的是,原始范例存贮的是值,对象谁人范例存储的是地点(指针)。当建立了一个对象范例的时刻,计算机回在内存
中拓荒一个空间赖寄存值,然则我们须要找到这个空间,这个控件会具有一个地点(指针)。当我们将变量赋值给别的一个变量时,复制的是底本变量的地点(指针)。
Q2:函数参数是对象会发作什么?
答:函数参数是对象的话,在函数内部可能会转变这个参数对象,天生新对象。
三.typeof VS instanceof
Q1:typeof是不是能准确推断范例?
答:关于原始范例来讲,typeof除了null都可以准确显现范例,typeof null显现的是object是毛病的。关于其他的,除了function会返回function,其他都邑返回object。
Q2. instanceof能准确推断对象的道理是什么?
答:instanceof内部机制是经由历程原型链来推断对象范例的。
eg: const Person = function () {}
const p1 = new Person() p1
instanceof Person // true
var str = 'hello world' str instanceof String // false
四.范例转换:
1.转Boolean: 在前提推断时,除了undefined,null,0,-0,NaN,”,false,其他一切值都转化为true,包括一切对象。
2.对象转原始范例: 对象在转换范例的时刻,会挪用内置的[[ToPrimitive]]函数,关于该函数来讲,
算法逻辑一般来讲以下:
* 假如已经是原始范例了,就不须要换砖了
* 挪用x.valueof(),假如转换为基础范例,就返回转换的值
* 挪用x.toString(),假如转化为基础范例,就返回转换的值
* 假如都没有返回原始范例,就会报错 1)四则运算符: 加法运算符特性:
*运算中假如一方为字符串,那末就会把另一方恭弘=叶 恭弘转换为字符串,1 + '1' // '11'
*假如一方不是字符串或许数字,那末会将它转化为数字或许字符串:true+ true // 2 ; 4 + [1,2,3] // '41,2,3'
注重: + 'a'是快速将'a'转化成number范例的写法;'a' + + 'b' // 'aNaN' 那末关于除了加法运算符其他运算符来讲,只需一方是数字,那末另一方就会被转化为数字。横竖终究都是要转化为数字来运算。
4 * '3' // 12 4 * [] // 0 4 * [1,2] // NaN 2)比较运算符 大于小于运算都邑转化为数字举行运算。
关于 ==:
*undefined 即是 null
*字符串和数字比较时,字符串转数字
*数字和布尔范例比较时,布尔转数字
*字符串和布尔比较时,二者转数字
五.this
this永久指向末了挪用它的谁人对象。
1.转变this指向:
* 运用es6箭头函数
* 在函数内部运用 _this = this
* 运用 apply,call,bind
* new 实例化一个对象
2.箭头函数: 箭头函数的this一直指向函数定义时的this,而非实行时(意味着假如箭头函数被非箭头函数包括,this绑定的就是近来一层非箭头函数的this)。
箭头函数中没有this绑定,必需经由历程查找作用域链来决议其值。
3.apply,call,bind区分
apply和call只是传入的参数差别。call接收的是若干个参数列表,而apply接收的是一个包括多个参数的数组。
bind和apply,call区分:
bind建立了一个新的函数,须要手动去挪用它;
六.new的历程:
- 建立一个空对象obj;
- 将新建立的空对象的隐式原型指向其组织函数的显现原型;
- 运用call转变this的指向;
- 假如无返回值或许返回一个非对象值,则将obj返回作为新对象;假如返回值时一个新对象的华那末直接返回该对象。
七. == VS ===
Q1: ==和 === 有什么区分?
答: 关于 == 来讲,假如两边的范例不一样的华,就会举行范例转换。
流程:
* 起首推断二者范例是不是雷同
* 推断是不是为 undefined == null //true
* string转number比较 * boolean转number比较
* object转原始范例比较 然则,=== 的比较只须要推断二者范例和值是不是雷同。
八.闭包:
Q1: 什么是闭包?
答:函数A内部有一个函数B,函数B可以接见到函数A中的变量,那末函数B就是闭包。
Q2:典范面试题:轮回中运用闭包处置惩罚var定义函数的题目:
答:第一种:运用闭包的体式格局: for (var i = 1; i <=5 ; i++) { ;(function(j) { setTimeout(function timer() { console.log(j) }, j * 1000) })(i)}
第二种:用let定义的体式格局: for (let i=1 ; i <=5 ; i++) { setTimeout(function timer() { console.log(i) }, i * 1000) } Q3:闭包的优瑕玷? 闭包作用(长处):可以读取到函数内部的变量,可以让这些变量的值一直保持在内存中,不会被渣滓回收掉。
闭包瑕玷:由于闭包会使得函数中变量保留在内存中,所以会增大内存运用量,运用不当很轻易形成内存走漏。糟蹋内存。
消灭闭包:退出函数之前,将不运用的局部变量删除。
九.深浅拷贝:
1.堆和栈:栈(stack)为自动分派的内存空间,它由体系自动开释;而堆(heap)则是动态分派的内存,大小不定也不会自动开释。
2.基础数据范例寄存在栈中,数据大小肯定,内存空间大小可以分派,是直接按值寄存的,所以可以直接接见。基础范例的比较是值的比较。
3.援用范例寄存在堆中,变量实际上寄存的是栈1内存的指针,援用范例的值可变。援用范例的比较是援用的比较。所以比较两个援用范例,是看其的援用是不是指向统一个对象。
Q1.浅拷贝?
答:浅拷贝只复制一层对象的属性,并不包括对象内里的为援用范例的数据。
Q2.深拷贝?
答: 深拷贝递归复制了对象的一切层级属性。
Q3.深拷贝,浅拷贝以及赋值的区分?
答:浅拷贝,深拷贝和原数据都不是指向统一对象,而赋值对象和原对象是指向统一对象。
第一层数据为基础范例,转变会使原数据转变,深拷贝以及浅拷贝不会。 原数据中包括子对象,转变子对象会使赋值对象以及浅拷贝对象转变,不会使深拷贝对象转变。
Q4.怎样完成浅拷贝?
答:1.可以经由历程Object.assign来处置惩罚。(Object.assign()要领用于将一切可罗列的值从一个或多个源对象复制到目的对象。它将返回目的对象。)
eg:
let a={ age: 1 }
let b=O bject.assign({}, a)
a.age=2 console.log(b.age) // 1
2.可以经由历程睁开运算符...来完成浅拷贝
eg:
let a={ age: 1}
let b={ ...a }
a.age=2 console.log(b.age) // 1
Q5.怎样完成深拷贝?
答:1.该题目可以经由历程JSON.parse(JSON.stringify(object))来处置惩罚。
eg: let a={age: 1, jobs: { first: 'FE' } }
let b=J SON.parse(JSON.stringify(a))
a.jobs.first='native'
console.log(b.jobs.first) // FE
然则该要领也是有局限性的:
* 会疏忽undefined
* 会疏忽symbol
* 不能序列化函数
* 不能处置惩罚轮回援用的对象
十:原型和原型链:
js是基于原型的继续。
1.运用组织函数建立对象后,新对象与组织函数没有关联了,新对象的[[prototype]]属性指向的是组织函数的原型对象。
2.组织函数、原型和实例的关联:
* 组织函数都有一个属性prototype,这个属性是一个对象(Object的实例)
* 原型对象内里有个constractor属性,该属性指向原型对象所属的组织函数。当原型对象被修悛改,constractor就不肯定指向本来的组织函数了。
* 实例对象都有一个_proto_属性,该属性也指向组织函数的原型对象,它是一个非标准属性,不可以用于编程,它用于浏览器本身运用。
3.prototype和_proto_的关联:
* prototype是组织函数的属性;
* _proto_是实例对象的属性;
* 这二者都邑指向统一个对象。
总结:*函数也是对象,对象不肯定是函数;
* 对象的实质:无序的键值对鸠合,键值对当中的值可以是恣意数据范例的值;
*对象就是一个容器,这个容器当中放的是属性和要领。
4.原型链:
原型链就是可以理解为有限的实例对象和原型之间构成的有限链,就是用来完成属性同享和继续的。
5.属性搜刮:
* 在接见对象的某个成员的时刻在对象中查找是不是存在;
* 假如当前对象中没有就在组织函数的原型对象中查找;
* 假如原型对象中没有就在原型对象的原型上找;
* 直到找到Object的原型对象的原型是null为止。
eg:
var arr = []
原型链:arr -> Array.prototype -> Object.prototype -> null
Q1:什么是原型?
答: 原型也是一个对象,而且这个对象中包括了许多函数。原型的constract属性指向组织函数,组织函数又经由历程prototype属性指回原型,到那时并非一切函数都具有这个属性。
十一:js继续:
1.原型链继续:将父类的实例作为子类的原型。
eg:Cat.prototype = new Animal()
瑕玷:子类没法给父类传参,子类要新增属性和要领的话,必需要在new Parent()如许的语句以后实行,不然会被掩盖。
2.组织继续:运用父类的组织函数来加强子类的实例,即是是在子类的组织函数内部实行Parent.call(this)。
eg:function Cat(name) {
Animal.call(this);
this.name = name || 'Tom';
}
var cat = new Cat();
瑕玷:没有原型,每次建立一个子类实例都要实行一遍Parent函数。
3.组合式继续:连系原型链继续和组织继续,组合式继续在运用历程中会被挪用两次:一次是建立子类的时刻,一次是在子类组织函数的内部。
eg: function Cat(name){
Animal.call(this);
this.name = name || 'Tom';
}
Cat.prototype = new Animal();
3.class继续:
class继续的中心在于运用extends表明继续自哪一个父类,而且在子类组织函数中必需挪用super,由于这段代码可以算作Parent.call(this,value).
eg:
class Parent {
constructor(value) {
this.val = value
}
getValue() {
console.log(this.val)
}
}
class Child extends Parent {
constructor(value) {
super(value)
this.val = value
}
}
let child = new Child(1)
child.getValue() // 1
child instanceof Parent // true
十二:var、let及const区分:
1.var和let区分:
* let有块级作用域的说法,也就是let声明的变量只能在这个块内部运用,别的处所不能运用。var声明的变量可以在全局运用,var在函数内部声明的变量只能在函数内部运用。
* let没有变量提拔,var有变量提拔
* let声明的变量存在“暂时性死区”,而var声明的变量没有
* let不允许在统一个快内反复声明一个变量。因而也不能在函数内部反复声明一个变量。
* var声明的变量会挂载到window上,而let声明的对象不会挂载到window上。
const特征:
- const声明一个只读的常量。一旦声明,常量的值就不能转变;
- const声明的变量必需初始化,不然会报错;
- const声明的变量也存在暂时性死区;
- const声明的变量只在所声明的块级作用域内有效;
- const声明的常量也与let一样不可反复声明。
Q1.什么是提拔?
答:就是变量可以在神明之前运用,而且值为undefined。
Q2. 什么是暂时性死区?
答:在let敕令声明之前,该变量都素hi不可用的。
十三.模块化:
Q1.为何要运用模块化?
答:运用模块化可以带来以下优点:
* 处置惩罚定名争执;
* 供应复用性;
* 进步代码可维护性。
Q2.完成模块化的体式格局?
CommonJS AMD CMD
1.require/exports:
遵照CommonJS/AMD,只能在运行时肯定模块的依靠关联及输入/输出的变量,没法举行静态优化。
2.import/export:
遵照ES6范例,支撑编译时静态剖析,便于JS引入宏和范例磨练,动态绑定。
十四、JS异步编程:
1. 并发(concurrency)和并行(parallelism)区分:
Q1:并发与并行的区分?
答:并发是宏观观点,我离别有使命A和使命B,在一段时间内经由历程使命间的切换完成了这个使命。
并行是微观观点,假定CPU中存在两个中心,那末我就可以同时完成使命A和使命B。同时完成多个使命的状况可以称之为并行。
2.回调函数(callback):
Q1.什么是回调函数?
答:ajax(url,() => {
//处置惩罚逻辑;
})
Q2.回调函数有什么瑕玷?
答:1)回调函数有一个致命的缺点就是轻易写出回调地狱(callback hell)。
eg:
ajax(url, () => {
// 处置惩罚逻辑
ajax(url1, () => {
// 处置惩罚逻辑
ajax(url2, () => {
// 处置惩罚逻辑
})
})
})
回调地狱根本题目:
* 嵌套函数存在耦合性,一旦有所修改,就会牵一发而动全身;
* 嵌套函数一多,就很难处置惩罚毛病。
2)回调函数不能运用trycatch捕捉毛病,不能直接return。
Q3.怎样处置惩罚“地狱回调”?
答:* function拆解
* promise
* generater
* async/await
3. Generator:
4. promise:
Q1:Promise的特性?
答:对象的状况不受外界影响,只要三种状况:pending resolved rejected
状况一旦转变,就不会再变,任何时刻都可以获得这个结果。
Q2. Promise的优瑕玷?
答:瑕玷:* promise没法作废,一旦新建就会马上实行,没法半途作废;
* 假如不设置回调函数,promise内部会抛出毛病,不会反应到外部;
* 当处于pending状况时,没法得知现在希望到哪一个阶段(刚刚开始照样行将完成)。
长处:可以处置惩罚回调地狱题目。
Q3. 什么是Promise链?
答:就是在Promise组织函数内里经由历程then来一步一步运用promise,由于then要领返回的也是一个全新的promise实例。
Q4. Promise组织函数实行和then函数实行有什么区分?
答:then要领每次都返回一个promise实例。
5. Async/Await:
Q1.async的特性?
答:一个函数假如加上async,那末该函数就会返回一个promise。async就是将函数返回值运用Promise.resolve()包裹了一下,和then中处置惩罚返回值一样,而且await只能配套在async函数内部运用。
Q2.优瑕玷?
答: 长处:处置惩罚then的挪用链可以更清楚的写出代码,而且可以文雅的处置惩罚回调地狱题目。
瑕玷:由于await将一部代码改形成了同步代码,假如多个异步代码没有依靠性却运用了await会致使性能上的下降。
Q3.await道理是什么?
答:await内部完成了generator。
完成async/await:
async function doIt() {
console.time("doIt");
const time1 = 300;
const time2 = await step1(time1);
const time3 = await step2(time2);
const result = await step3(time3);
console.log(`result is ${result}`);
console.timeEnd("doIt");
}
doIt();
6.经常使用定时器函数: setTimeout() setInterval() requestAnimationFrame()
requestAnimationFrame自带函数撙节功用,基础可以保证在16.6毫秒内只实行一次,而且该函数的延时结果是精准的。假如有轮回定时器的需求,requestAnimationFrame是最好的挑选。