js脚本加载问题,async、defer问题
- 如果依赖其他脚本和DOM结果,使用defer
- 如果与DOM和其他脚本依赖不强时,使用async
如何判断一个对象不是空对象
Object.keys(obj).length === 0
在线编程,getUrlParams(url,key);就是简单的获取url的某个参数的问题,但是要考虑多个便捷,多个返回值等
getUrlParams(url) {
const _url = url || window.location.href;
console.log(_url)
const _urlParams = _url.match(/([?&])(.+?=[^&]+)/igm);
console.log(_urlParams)
return _urlParams ? _urlParams.reduce((a, b) => {
const value = b.slice(1).split('=');
a[value[0]] = value[1]
return a;
}, {}) : {};
}
console.log(this.getUrlParams('?name=wuweigang&age=25&school=bj university'))
<script src='xxx' />
外部js文件先加载还是onload先执行,为什么?
onload是左右加载完成之后才执行的
怎么是事件监听,两种
onclick和addEventListener
事件传播机制(事件流)
冒泡和捕获
原型链和原型链的继承?
- 其实
[[prototype]]
和__proto__
意义相同,均表示对象的内部属性,其值指向对象原型。所有[[prototype]]链最终都会指向内置的Object.prototype,其包含了javascript中许多通用的功能 - 为什么能创建‘类’,借助一种特殊的属性:所有的函数默认都会拥有一个名为prototype的共有且不可枚举的属性,它会执行另一个对象,这个对象通常被称为函数的原型。
function Person(name){
this.name = name
}
Person.prototype.constructor = Person
- 在发生new构造函数调用时,会将创建的新对象[[prototype]]链接到Person.prototype指向的对象,这个机制被称为原型链继承
- 方法定义在原型上,属性定义在构造函数上
- 首先要说下js原型和实例的关系:每一个构造函数(constructor)都有一个原型对象(prototype),这个原型对象包含一个指向此构造函数的指针属性,通过new进行构造函数调用生成的实例,此实例包含一个指向原型对象的指针,也就是通过[[prototype]]链接到了这个原型对象
- 然后说一下js中属性的查找:当我们试图引用实例对象的某个属性时,是按照这样的方式去查找的,首先查找实例对象上是否有这个属性,如果没有找到,就去构造这个实例对象的prototype所指向的对象上查找,如果还找不到,就从这个prototype对象所指的构造函数的prototype原型对象上查找
- 什么是原型链:这样逐级查找形似一个链条,且通过[[Prototype]]属性链接,所以被称为原型链
- 什么是原型链继承,类比类的继承:当有两个构造函数A和B,将一个构造函数A的原型对象,通过其[[Prototype]]属性链接到另外一个B构造函数的原型对象时,这个过程被称之为原型继承
什么是原型链(标准答案更正确的解释)
当对象查找一个属性时,如果没有在自身找到,那么就会查找自身的原型,如果原型还没有找到,那么会继续查找原型的原型,直到找到Object.prototype的原型是,此原型为null,查找停止。这种通过原型链接的逐级向上的查找链被称为原型链
什么是原型继承?
一个对象可以使用另一个对象的属性或者方法,就称之为继承。具体是通过将这个对象的原型设置为另一个对象,这样根据原型链的规则,如果查找一个对象属性且在自身不存在时,就会查找另一个对象,相当于一个对象可以使用另一个对象的属性和方法
说下对js的了解
javascript是一种轻量级的解释执行的而非编译的脚本语言。
不需要预先编译而是在程序运行中逐行解释并执行。由ECNAScript、文档对象模型(DOM)和浏览器对象模型(BOM)组成
是基于原型的动态语言,主要独特特性有this、原型和原型链。严格意义上来说分为语言标准部分(ECMAScript)+宿主环境部分
语言标准部分
2015年发布ES6,引入诸多新特性使得能够编写大型项目变成可能,标准自2015之后以年号代号,每年一更
宿主环境部分
- 在浏览器宿主环境包括DOM+BOM
- 在node,宿主环境包括一些文件、数据库、网络、与操作系统的交互等
数组能够调用的函数有哪些?
- push 向数组的末尾添加一个或多个元素,并返回新的长度
- pop 向删除并返回数组的最后一个元素
- splice 删除元素,并向数组添加新元素
- slice 从某个已有的数组返回选定元素
- shift 删除并返回数组的第一个元素
- unshift 向数组的开头添加一个或更多元素,并返回新的长度
- sort 排序
- reverse 颠倒数组中的元素
- concat 链接两个或者更多的数组,并返回结果
- join 将数组所有元素放入一个字符串
- find
- findindex
- map/filter/reduce等函数式编程方法
- 还有一些原型链上的方法:toString/valueOf
如何判断数组的类型
Array.isArray
函数中的arguments是数组吗?类数组转数组的方法
是类数组,伪数组,是属于鸭子类型的范畴,长的像数组,
- …运算符
- Array.from
- Array.prototype.slice.apply(arguments)
用过typeScript嘛?它的作用是什么?
为js添加类型支持,以及提供罪行的es语法的支持,是利于团队协作和排错,开发大型项目
PWA使用过吗?serviceWorker的使用原理是啥?
渐进式网络应用(PWA
是谷歌在2015年底提出的概念。基本上算是web应用程序,但在外观和感觉上与原生app
类似。支持PWA
的网站可以提供脱机工作、推送通知和设备硬件访问等功能。
Service Worker
是浏览器在后台独立于网页运行的脚本,他打开了通向不需要网页或用户交互的功能的阀门。现在,它们已包括如推送通知和后台同步等功能。将来,Service Worker
将会支持如定期同步或地理围栏等其他功能。
如果一个构造函数,bind了一个对象,用这个构造函数创建出的实例会继承这个对象的属性吗?为什么?
不会继承。因为根据this绑定四大规则,new绑定的优先级高于bind显示绑定,通过new进行构造函数调用时,会创建一个新对象,这个新对象会代替bind的对象绑定,作为函数的this,并且在此函数没有返回对象的情况下,返回这个新建的对象
箭头函数和普通函数有啥区别,箭头函数能当构造函数嘛?
- 普通函数通过function关键字定义,this无法结合词法作用域使用,在运行绑定,只取决于函数的调用方式,在哪里被调用,调用位置。(取决于调用者,和是否独立运行)
- 箭头函数使用被称为‘胖箭头’的操作
=>
定义,箭头函数不应用普通函数this绑定的四种规则,而是根据外层(函数或全局)的作用域来决定this,且箭头函数的绑定无法被修改(new也不行) - 箭头函数常用与回调函数中,包括时间处理器或定时器
- 箭头函数和
var self = this
,都试图取代传统的this运行机制,将this的绑定拉回到词法作用域 - 箭头函数没有原型、this、super、arguments、new.target
- 不能通过new关键字调用
- 一个函数内部有两种方法:[[call]]和[[Construct]],在通过new进行函数调用时,会执行[[construct]]方法,创建一个实例对象,然后再执行这个函数体,将函数的this绑定在这个实例对象上
- 当直接调用时,执行[[Call]]方法,直接执行函数体
- 箭头函数没有[[Construct]]方法,不能被用作构造函数调用,当使用new进行函数调用
知道ES6的class嘛?static关键字有了解嘛?
被static修饰的属性和方法都是静态方法和属性,只能被类名调用,不能被实例化对象调用。同时也不能被子类继承,换句话说它属于当前这个类的。
ES6
的 class
可以看作只是一个语法糖 ,它的绝大部分功能,ES5
都可以做到,新的 class
写法只是让对象原型的写法更加清晰、更像面向对象编程的语法
事件循环机制(Event Loop)
事件循环机制从整体上高速我们javascript代码的执行循序,Event Loop
即事件循环,是指浏览器或Node
的一种解决javascript
单线程运行时不会阻塞的一种机制,也就是我们经常使用异步
的原理。
先执行宏任务队列,然后执行微任务队列,然后开始下一轮事件循环、继续先执行宏任务,再执行微任务队列。
- 宏任务:script/setTimeout/setInterval/setImmediate/I/O/UI Rendering
- 微任务:process.nextTick()/Promise
上述的setTimeout
和setInterval
等都是任务源,真正进入任务队列的是他们发布的任务
优先级
- setTimeout = setInterval 一个队列
- setTimeout > setImmediate
- process.nextTick > Promise
扁平化数组
数组扁平化是指将一个多维数组变为一维数组
function flatten(arr){
let result = []
for(let i = 0; i< arr.length;i++){
if(Array.isArray(arr[i])){
result = result.concat(flatten(arr[i]))
}else{
result = result.concat(arr[i])
}
}
return result
}
const a = [1,[2,[3,4]]]
console.log(flatten(a))
实现柯里化
维基百科上说道:柯里化,英语:Currying(果然是满满的英译中的既视感),是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数而且返回结果的新函数的技术。
通俗一点:是指这样一个函数,它接收函数A,并且能返回一个新的函数,这个新的函数能够处理函数A的剩余参数。
// 普通的add函数
function add(x, y) {
return x + y
}
// Currying后
function curryingAdd(x) {
return function (y) {
return x + y
}
}
add(1, 2) // 3
curryingAdd(1)(2) // 3
function createCurry(func,args){
var argity = func.length;
var args = args || []
return function(){
var _args = [].slice.apply(arguments)
args.push(..._args)
if(args.length < argity){
return createCurry.call(this,func,args)
}
return func.apply(this.,args)
}
}
数组去重
Array.from(new set([1,1,2,2,]))
let闭包
let会产生临时性死区,在当前的执行上下文中,会进行变量提升,但是未被初始化,所以在执行上下文执行阶段,执行代码如果还没有执行到变量赋值,就引用此变量就会报错,此变量未初始化