👇 内容速览 👇javascript
this
仍是一道经典题目,下面的这段代码的输出是什么?(为了方便解释,输出放在了注释中)html
function fn() { console.log(this); // 1. {a: 100} var arr = [1, 2, 3]; (function() { console.log(this); // 2. Window })(); // 普通 JS arr.map(function(item) { console.log(this); // 3. Window return item + 1; }); // 箭头函数 let brr = arr.map(item => { console.log("es6", this); // 4. {a: 100} return item + 1; }); } fn.call({ a: 100 });
其实诀窍很简单,常见的基本是3种状况:es5普通函数、es6的箭头函数以及经过bind
改变过上下文返回的新函数。前端
① es5普通函数:java
window
obj.foo()
,上下文就是对象自己obj
new
调用,this
绑定在返回的实例上② es6箭头函数: 它自己没有this
,会沿着做用域向上寻找,直到global
/ window
。请看下面的这段代码:webpack
function run() { const inner = () => { return () => { console.log(this.a) } } inner()() } run.bind({a: 1})() // Output: 1
③ bind绑定上下文返回的新函数:就是被第一个bind绑定的上下文,并且bind对“箭头函数”无效。请看下面的这段代码:css3
function run() { console.log(this.a) } run.bind({a: 1})() // output: 1 // 屡次bind,上下文由第一个bind的上下文决定 run .bind({a: 2}) .bind({a: 1}) () // output: 2
最后,再说说这几种方法的优先级:new > bind > 对象调用 > 直接调用git
至此,这道题目的输出就说能够解释明白了。es6
题目:JS中的原始数据类型?
ECMAScript 中定义了 7 种原始类型:github
注意:原始类型不包含Object和Function
题目:经常使用的判断方法?
在进行判断的时候有typeof
、instanceof
。对于数组的判断,使用Array.isArray()
:
typeof:
typeof null
和typeof [1, 2, 3]
均返回"object"typeof Symbol()
返回"symbol"instanceof:
专门用于实例和构造函数对应
function Obj(value){ this.value = value; } let obj = new Obj("test"); console.log(obj instanceof Obj); // output: true
[1, 2, 3] instanceof Array
Array.isArray({})
返回false
。当咱们对一个“对象”进行数学运算操做时候,会涉及到对象 => 基础数据类型的转化问题。
事实上,当一个对象执行例如加法操做的时候,若是它是原始类型,那么就不须要转换。不然,将遵循如下规则:
valueOf()
方法,若是有返回的是基础类型,中止下面的过程;不然继续toString()
方法,若是有返回的是基础类型,中止下面的过程;不然继续请看下面的测试代码:
let a = { toString: function() { return 'a' } } let b = { valueOf: function() { return 100 }, toString: function() { return 'b' } } let c = Object.create(null) // 建立一个空对象 console.log(a + '123') // output: a123 console.log(b + 1) // output: 101 console.log(c + '123') // 报错
除了valueOf
和toString
,es6还提供了Symbol.toPrimitive
供对象向原始类型转化,而且它的优先级最高!!稍微改造下上面的代码:
let b = { valueOf: function() { return 100 }, toString: function() { return 'b' }, [Symbol.toPrimitive]: function() { return 10000 } } console.log(b + 1) // output: 10001
最后,其实关于instanceof
判断是不是某个对象的实例,es6也提供了Symbol.hasInstance
接口,代码以下:
class Even { static [Symbol.hasInstance](num) { return Number(num) % 2 === 0; } } const Odd = { [Symbol.hasInstance](num) { return Number(num) % 2 !== 0; } }; console.log(1 instanceof Even); // output: false console.log(1 instanceof Odd); // output: true
题目:实现对象的深拷贝。
在JS中,函数和对象都是浅拷贝(地址引用);其余的,例如布尔值、数字等基础数据类型都是深拷贝(值引用)。
值得提醒的是,ES6的Object.assign()
和ES7的...
解构运算符都是“浅拷贝”。实现深拷贝仍是须要本身手动撸“轮子”或者借助第三方库(例如lodash
):
extend(true, result, src1, src2[ ,src3])
、lodash的cloneDeep(src)
JSON.parse(JSON.stringify(src))
:这种方法有局限性,若是属性值是函数或者一个类的实例的时候,没法正确拷贝借助HTML5的MessageChannel
:这种方法有局限性,当属性值是函数的时候,会报错
<script> function deepClone(obj) { return new Promise(resolve => { const {port1, port2} = new MessageChannel(); port2.onmessage = ev => resolve(ev.data); port1.postMessage(obj); }); } const obj = { a: 1, b: { c: [1, 2], d: '() => {}' } }; deepClone(obj) .then(obj2 => { obj2.b.c[0] = 100; console.log(obj.b.c); // output: [1, 2] console.log(obj2.b.c); // output: [100, 2] }) </script>
事件流分为:冒泡和捕获,顺序是先捕获再冒泡。
事件冒泡:子元素的触发事件会一直向父节点传递,一直到根结点中止。此过程当中,能够在每一个节点捕捉到相关事件。能够经过stopPropagation
方法终止冒泡。
事件捕获:和“事件冒泡”相反,从根节点开始执行,一直向子节点传递,直到目标节点。
addEventListener
给出了第三个参数同时支持冒泡与捕获:默认是false
,事件冒泡;设置为true
时,是事件捕获。
<div id="app" style="width: 100vw; background: red;"> <span id="btn">点我</span> </div> <script> // 事件捕获:先输出 "外层click事件触发"; 再输出 "内层click事件触发" var useCapture = true; var btn = document.getElementById("btn"); btn.addEventListener( "click", function() { console.log("内层click事件触发"); }, useCapture ); var app = document.getElementById("app"); app.onclick = function() { console.log("外层click事件触发"); }; </script>
DOM2级:前面说的addEventListener
,它定义了DOM
事件流,捕获 + 冒泡。
DOM0级:
on
事件on
系列事件注意:如今通用DOM2
级事件,优势以下:
没什么好说的,跑一下下面的代码就能够理解了:
// map: 生成一个新数组,遍历原数组, // 将每一个元素拿出来作一些变换而后放入到新的数组中 let newArr = [1, 2, 3].map(item => item * 2); console.log(`New array is ${newArr}`); // filter: 数组过滤, 根据返回的boolean // 决定是否添加到数组中 let newArr2 = [1, 2, 4, 6].filter(item => item !== 6); console.log(`New array2 is ${newArr2}`); // reduce: 结果汇总为单个返回值 // acc: 累计值; current: 当前item let arr = [1, 2, 3]; const sum = arr.reduce((acc, current) => acc + current); const sum2 = arr.reduce((acc, current) => acc + current, 100); console.log(sum); // 6 console.log(sum2); // 106
《前端知识体系》
《设计模式手册》
《Webpack4渐进式教程》