0.1 + 0.2 === 0.3 嘛?为什么?
JavaScirpt 使用 Number 类型来表示数字(整数或浮点数),
遵循 IEEE 754 标准,
通过 64 位来表示一个数字(1 + 11 + 52)
1 符号位,0 表示正数,1 表示负数 s
11 指数位(e)
52 尾数,小数部分(即有效数字)
最大安全数字:Number.MAX_SAFE_INTEGER = Math.pow(2, 53) - 1,
转换成整数就是 16 位,所以 0.1 === 0.1,是因为通过 toPrecision(16)
去有效位之后,
两者是相等的。
在两数相加时,会先转换成二进制,0.1 和 0.2 转换成二进制的时候尾数会
发生无限循环,
然后进行对阶运算,JS 引擎对二进制进行截断,所以造成精度丢失。
所以总结:精度丢失可能出现在进制转换和对阶运算中
实现函数能够深度克隆基本类型
function shallowClone(obj) {
let cloneObj = {};
for (let i in obj) {
cloneObj[i] = obj[i];
}
return cloneObj;
}
深克隆
function deepCopy(obj) {
if (typeof obj === 'object') {
var result = obj.constructor === Array ? [] : {};
for (var i in obj) {
result[i] = typeof obj[i] === 'object' ?
deepCopy(obj[i]) : obj[i];
}
} else {
var result = obj;
}
return result;
}
事件流
事件流是网页元素接收事件的顺序,"DOM2级事件"规定的事件流包括三个阶段:事件捕获阶段、处于目标阶段、事件冒泡阶段。首先发生的事件捕获,为截获事件提供机会。然后是实际的目标接受事件。最后一个阶段是时间冒泡阶段,可以在这个阶段对事件做出响应。虽然捕获阶段在规范中规定不允许响应事件,但是实际上还是会执行,所以有两次机会获取到目标对象。
我是父元素 我是子元素
parEle.addEventListener(‘click’, function () {
alert(‘父级 冒泡’);
}, false);
parEle.addEventListener(‘click’, function () {
alert(‘父级 捕获’);
}, true);
sonEle.addEventListener(‘click’, function () {
alert(‘子级冒泡’);
}, false);
sonEle.addEventListener(‘click’, function () {
alert(‘子级捕获’);
}, true);
当容器元素及嵌套元素,即在捕获阶段又在冒泡阶段调用事件处理程序时:事件按DOM事件流的顺序执行事件处理程序:
父级捕获
子级冒泡
子级捕获
父级冒泡
且当事件处于目标阶段时,事件调用顺序决定于绑定事件的书写顺序,按上面的例子为,先调用冒泡阶段的事件处理程序,再调用捕获阶段的事件处理程序。依次alert出“子集冒泡”,“子集捕获”。
IE 兼容
attchEvent(‘on’ + type, handler)
detachEvent(‘on’ + type, handler)
事件是如何实现的?
在 Web 端,我们常见的就是 DOM 事件:
DOM0 级事件,直接在 html 元素上绑定 on-event,比如 onclick,取消的话,dom.onclick = null,同一个事件只能有一个处理程序,后面的会覆盖前面的。
DOM2 级事件,通过 addEventListener 注册事件,通过 removeEventListener 来删除事件,一个事件可以有多个事件处理程序,按顺序执行,捕获事件和冒泡事件
DOM3级事件,增加了事件类型,比如 UI 事件,焦点事件,鼠标事件
什么是闭包
闭包是一种特殊的对象,它由两部分组成:执行上下文(代号 A),以及在该执行上下文中创建的函数 (代号 B),当 B 执行时,如果访问了 A 中变量对象的值,那么闭包就会产生,且在 Chrome 中使用这个执行上下文 A 的函数名代指闭包
一般如何产生闭包
返回函数
函数当做参数传递
闭包的应用场景
柯里化 bind
模块
问:了解 this 嘛,bind,call,apply 具体指什么
它们都是函数的方法
call: Array.prototype.call(this, args1, args2])apply: Array.prototype.apply(this, [args1, args2]) :ES6 之前用来展开数组调用, foo.appy(null, []),ES6 之后使用 … 操作符
New 绑定时,如果是 new 一个硬绑定函数,那么会用 new 新建的对象替换这个硬绑定 this,
function foo(a) {
this.a = a;
}
var bar = new foo(2);
console.log(bar.a)
手写 bind、apply、call
// call
Function.prototype.call = function (context, ...args) {
context = context || window;
const fnSymbol = Symbol("fn");
context[fnSymbol] = this;
context[fnSymbol](...args);
delete context[fnSymbol];
}
// apply
Function.prototype.apply = function (context, argsArr) {
context = context || window;
const fnSymbol = Symbol("fn");
context[fnSymbol] = this;
context[fnSymbol](...argsArr);
delete context[fnSymbol];
}
// apply
Function.prototype.apply = function (context, argsArr) {
context = context || window;
const fnSymbol = Symbol("fn");
context[fnSymbol] = this;
context[fnSymbol](...argsArr);
delete context[fnSymbol];
}
手写题:Promise 原理
class MyPromise {
constructor(fn) {
this.resolvedCallbacks = [];
this.rejectedCallbacks = [];
this.state = 'PENDING';
this.value = '';
fn(this.resolve.bind(this), this.reject.bind(this));
}
resolve(value) {
if (this.state === 'PENDING') {
this.state = 'RESOLVED';
this.value = value;
this.resolvedCallbacks.map(cb => cb(value));
}
}
reject(value) {
if (this.state === 'PENDING') {
this.state = 'REJECTED';
this.value = value;
this.rejectedCallbacks.map(cb => cb(value));
}
}
then(onFulfilled, onRejected) {
if (this.state === 'PENDING') {
this.resolvedCallbacks.push(onFulfilled);
this.rejectedCallbacks.push(onRejected);
}
if (this.state === 'RESOLVED') {
onFulfilled(this.value);
}
if (this.state === 'REJECTED') {
onRejected(this.value);
}
}
}
什么是原型链?
当对象查找一个属性的时候,如果没有在自身找到,那么就会查找自身的原型,
如果原型还没有找到,那么会继续查找原型的原型,直到找到 Object.prototype
的原型时,此时原型为 null,查找停止。这种通过 通过原型链接的逐级向上的查
找链被称为原型链
什么是原型继承?
一个对象可以使用另外一个对象的属性或者方法,就称之为继承。具体是通过
将这个对象的原型设置为另外一个对象,这样根据原型链的规则,如果查找
一个对象属性且在自身不存在时,就会查找另外一个对象,相当于一个对象
可以使用另外一个对象的属性和方法了。
数组能够调用的函数有那些?
push
pop
splice
slice
shift
unshift
sort
find
findIndex
map/filter/reduce 等函数式编程方法
还有一些原型链上的方法:toString/valudOf
如何判断数组类型
Array.isArray
PWA使用过吗?serviceWorker的使用原理是啥?
渐进式网络应用(PWA)是谷歌在2015年底提出的概念。基本上算是web应用程序,
但在外观和感觉上与原生app类似。支持PWA的网站可以提供脱机工作、
推送通知和设备硬件访问等功能。
Service Worker是浏览器在后台独立于网页运行的脚本,它打开了通向不需
要网页或用户交互的功能的大门。现在,它们已包括如推送通知和后台同
步等功能。将来,Service Worker将会支持如定期同步或地理围栏等其他功能。
本教程讨论的核心功能是拦截和处理网络请求,包括通过程序来管理缓存中的响应。
function foo(a) {
this.a = a;
}
var bar = new foo(2);
console.log(bar.a)
手写 bind、apply、call
// call
Function.prototype.call = function (context, ...args) {
context = context || window;
const fnSymbol = Symbol("fn");
context[fnSymbol] = this;
context[fnSymbol](...args);
delete context[fnSymbol];
}
// apply
Function.prototype.apply = function (context, argsArr) {
context = context || window;
const fnSymbol = Symbol("fn");
context[fnSymbol] = this;
context[fnSymbol](...argsArr);
delete context[fnSymbol];
}
// apply
Function.prototype.apply = function (context, argsArr) {
context = context || window;
const fnSymbol = Symbol("fn");
context[fnSymbol] = this;
context[fnSymbol](...argsArr);
delete context[fnSymbol];
}
手写题:Promise 原理
class MyPromise {
constructor(fn) {
this.resolvedCallbacks = [];
this.rejectedCallbacks = [];
this.state = 'PENDING';
this.value = '';
fn(this.resolve.bind(this), this.reject.bind(this));
}
resolve(value) {
if (this.state === 'PENDING') {
this.state = 'RESOLVED';
this.value = value;
this.resolvedCallbacks.map(cb => cb(value));
}
}
reject(value) {
if (this.state === 'PENDING') {
this.state = 'REJECTED';
this.value = value;
this.rejectedCallbacks.map(cb => cb(value));
}
}
then(onFulfilled, onRejected) {
if (this.state === 'PENDING') {
this.resolvedCallbacks.push(onFulfilled);
this.rejectedCallbacks.push(onRejected);
}
if (this.state === 'RESOLVED') {
onFulfilled(this.value);
}
if (this.state === 'REJECTED') {
onRejected(this.value);
}
}
}
什么是原型链?
当对象查找一个属性的时候,如果没有在自身找到,那么就会查找自身的原型,如果原型还没有找到,那么会继续查找原型的原型,直到找到 Object.prototype 的原型时,此时原型为 null,查找停止。这种通过 通过原型链接的逐级向上的查找链被称为原型链
什么是原型继承?
一个对象可以使用另外一个对象的属性或者方法,就称之为继承。具体是通过将这个对
象的原型设置为另外一个对象,这样根据原型链的规则,如果查找一个对象属性且在自
身不存在时,就会查找另外一个对象,相当于一个对象可以使用另外一个对象的属
性和方法了。
数组能够调用的函数有那些?
push
pop
splice
slice
shift
unshift
sort
find
findIndex
map/filter/reduce 等函数式编程方法
还有一些原型链上的方法:toString/valudOf
如何判断数组类型
Array.isArray
PWA使用过吗?serviceWorker的使用原理是啥?
渐进式网络应用(PWA)是谷歌在2015年底提出的概念。
基本上算是web应用程序,但在外观和感觉上与原生app类似。
支持PWA的网站可以提供脱机工作、推送通知和设备硬件访问等功能。
Service Worker是浏览器在后台独立于网页运行的脚本,它打开了通向
不需要网页或用户交互的功能的大门。现在,它们已包括如推送通知和
后台同步等功能。将来,Service Worker将会支持如定期同步或地理围栏
等其他功能。本教程讨论的核心功能是拦截和处理网络请求,包括通过
程序来管理缓存中的响应。
function foo() {
return (a) => {
console.log(this.a);
}
}
var obj1 = {
a: 2
}
var obj2 = {
a: 3
}
var bar = foo.call(obj1);
bar.call(obj2);
let 闭包
let 会产生临时性死区,在当前的执行上下文中,会进行变量提升,
但是未被初始化,
所以在执行上下文执行阶段,执行代码如果还没有执行到变量赋值,
就引用此变量就
会报错,此变量未初始化