1、
- CSS3新属性、盒模型、闭包、垃圾回收
- 缓存、HTTP协议、React、Redux、ES6、异步机制、算法、项目经验
- 项目经验、项目难点、对项目管理中内部沟通的建议、还有为啥离开原公司
1、CSS3新属性
transition: CSS属性,花费时间,效果曲线(默认ease),延迟时间(默认0)
/*宽度从原始值到制定值的一个过渡,运动曲线ease,运动时间0.5秒,0.2秒后执行过渡*/
transition:width,.5s,ease,.2stransition-property: width;transition-duration: 1s;transition-timing-function: linear;transition-delay: 2s; animation:动画名称,一个周期花费时间,运动曲线(默认ease),动画延迟(默认0),播放次数(默认1),是否反向播放动画(默认normal),是否暂停动画(默认running)/*无限执行logo2-line动画,每次运动时间2秒,运动曲线为 linear,并且执行反向动画*/animation: logo2-line 2s linear alternate infinite;animation-fill-mode : none | forwards | backwards | both;/*none:不改变默认行为。 forwards :当动画完成后,保持最后一个属性值(在最后一个关键帧中定义)。 backwards:在 animation-delay 所指定的一段时间内,在动画显示之前,应用开始属性值(在第一个关键帧中定义)。 both:向前和向后填充模式都被应用。 */ 形状变换transform:适用于2D或3D转换的元素transform-origin:转换元素的位置(围绕那个点进行转换)。默认(x,y,z):(50%,50%,0)换行 word-break: normal|break-all|keep-all;word-wrap: normal|break-word; 超出省略号这个,主要讲text-overflow这个属性,我直接讲实例的原因是text-overflow的三个写法,clip|ellipsis|string。clip这个方式处理不美观,不优雅。string只在火狐兼容。rgba h:色相”,“s:饱和度”,“l:亮度”,“a:透明度” color: hsla( 112, 72%, 33%, 0.68);background-color: hsla( 49, 65%, 60%, 0.68);渐变 css3的滤镜黑白色filter: grayscale(100%)
弹性布局 body {display:flex} div{flex:1} 等....具体可以百度flex弹性布局栅格布局 grid 百度看一下吧多列布局 .newspaper{ column-count: 3; -webkit-column-count: 3; -moz-column-count: 3; column-rule:2px solid #000; -webkit-column-rule:2px solid #000; -mox-column-rule:2px solid #000;} 盒模型定义 box-sizing:border-box的时候,边框和padding包含在元素的宽高之内! box-sizing:content-box的时候,边框和padding不包含在元素的宽高之内!媒体查询,就在监听屏幕尺寸的变化,在不同尺寸的时候显示不同的样式!在做响应式的网站里面,是必不可少的一环!不过由于我最近的项目都是使用rem布局。@media screen and (max-width: 960px) { body { background-color: darkgoldenrod; }}@media screen and (max-width: 480px) { body { background-color: lightgreen; }}css3的混合模式,两个(background-blend-mode和mix-blend-mode)。这两个写法和显示效果都非常像!区别就在于background-blend-mode是用于同一个元素的背景图片和背景颜色的。mix-blend-mode用于一个元素的背景图片或者颜色和子元素的。复制代码
div{ width: 480px; height: 300px; background:url('test.jpg')no-repeat,#09f;}multiply正片叠底
screen滤色
........复制代码
2、垃圾回收
因为JavaScript 具有自动垃圾收集机制(Garbage collected )。在编写 JS 时,不需要关 心内存使用问题,所需内存分配以及无用内存的回收完全实现了自动管理。
内存泄漏(memory leaks),什么情况下回导致内存泄漏?可以简单理解为有些代码本来要被回收的,但没有被回收,还一直占用着内存,就会越积越多,最终会导致内存泄漏(可以理解为,内存满了,就溢出了)
分配给web浏览器的可用内存数量通常要比分配给桌面应用程序少。这样做的目的主要是处于安全方面考虑,目的是防止运行 JS 的网页耗尽全部系统内存而导致系统崩溃。内存限制问题不仅会影响给变量分配内存,同时还会影响调用栈以及在一个线程中能够同时执行的语句数量。
因此,确保占用最少的内存可以让页面获得更好的性能。而优化内存占用的最佳方式,就是为执行中的代码只保存必要的数据。一旦数据不再有用,最好通过将其值设置为 null 来释放其引用。这个方法叫做解除引用。这一做法适用于大多数的全局变量和全局对象的属性。局部变量会在他们离开执行环境时自动被解除引用。
解除一个值的引用并不意味着自动回收改值所占用的内存。解除引用的真正作用是让值 脱离执行环境,以便垃圾收集器下次运行时将其回收。
垃圾收集器在运行时候会给储存在内存中的所有变量都加上标记。然后,它会去掉环境中的变量以及被环境中的变量引用的变量的标记。而在此之后再被加上标记的变量将被视为准备删除的变量,原因是环境中的变量已经无法访问到这些变量了。最后,垃圾收集器完成内存清除的工作。
那标记清除具体是如何呢?有以下几种算法:
- 在JavaScript 中,全局变量(Global)和window 对象会一直存在,不会被垃圾回收;
- 递归所用到的变量,不会被回收;
- 所有没有被标记为“活跃(active)”,都会被认为是垃圾,收集器释放内存,并把内存还给操作系统。
var n = 123;
// 给数值变量分配内存
var s = "azerty";
// 给字符串分配内存
// 给对象及其包含的值分配内存
var o = { a: 1, b: null };
// 给函数(可调用的对象)分配内存
function f(a){ return a + 2; }
function foo(arg) {
// 此处bar 是全局变量,window.bar 可以访问,所以也不会被回收
bar = "this is a hidden global variable";
}
function foo() {
// 此处this 代表 window
this.variable = "potential accidental global";
}
var someResource = getData();
setInterval(function() {
var node = document.getElementById('Node');
if(node) {
node.innerHTML = JSON.stringify(someResource));
} }, 1000);
// 上面这段代码,定时器setInterval 和 someResource 一直存在,不会被回收。可以改成下面代码
var element = document.getElementById('button');
function onClick(event) {
element.innerHtml = 'text';
}
element.addEventListener('click', onClick); // 手动移除事件监听器和变量 element.removeEventListener('click', onClick); element.parentNode.removeChild(element);
var intervalId = null, params;
function createChunks() {
var div, foo, i, str;
for (i = 0; i < 20; i++) {
div = document.createElement("div");
str = new Array(1000000).join('x');
foo = { str: str, div: div };
div.foo = foo; }
}
function start() {
if (intervalId) { return; }
intervalId = setInterval(createChunks, 1000);
}
function stop() {
if (intervalId) {
// 清除定时器
clearInterval(intervalId);
}
// 清除变量
intervalId = null;
}
3、闭包
function count() { var arr = []; for (var i=1; i<=3; i++) { arr.push(function () { return i * i; }); } return arr;}var results = count();var f1 = results[0];var f2 = results[1];var f3 = results[2];f1(); // 16f2(); // 16f3(); // 16全部都是16!原因就在于返回的函数引用了变量i,但它并非立刻执行。等到3个函数都返回时,它们所引用的变量i已经变成了4,因此最终结果为16。返回闭包时牢记的一点就是:返回函数不要引用任何循环变量,或者后续会发生变化的变量。复制代码
如果一定要引用循环变量怎么办?方法是再创建一个函数,用该函数的参数绑定循环变量当前的值,无论该循环变量后续如何更改,已绑定到函数参数的值不变:
function count() { var arr = []; for (var i=1; i<=3; i++) { arr.push((function (n) { return function () { return n * n; } })(i)); } return arr;}var results = count();var f1 = results[0];var f2 = results[1];var f3 = results[2];f1(); // 1f2(); // 4f3(); // 9复制代码
(function (x) { return x * x;})(3); // 9复制代码
4、异步中的acyns await
任意一个名称都是有意义的,先从字面意思来理解。async 是“异步”的简写,而 await 可以认为是 async wait 的简写。所以应该很好理解 async 用于申明一个 function 是异步的,而 await 用于等待一个异步方法执行完成。
另外还有一个很有意思的语法规定,await 只能出现在 async 函数中。然后细心的朋友会产生一个疑问,如果 await 只能出现在 async 函数中,那这个 async 函数应该怎么调用?
如果需要通过 await 来调用一个 async 函数,那这个调用的外面必须得再包一个 async 函数,然后……进入死循环,永无出头之日……
async 起什么作用
这个问题的关键在于,async 函数是怎么处理它的返回值的!
我们当然希望它能直接通过 return
语句返回我们想要的值,但是如果真是这样,似乎就没 await 什么事了。所以,写段代码来试试,看它到底会返回什么:
async function testAsync() { return "hello async";}const result = testAsync();console.log(result);复制代码
看到输出就恍然大悟了——输出的是一个 Promise 对象。
await 到底在等啥
一般来说,都认为 await 是在等待一个 async 函数完成。不过按,await 等待的是一个表达式,这个表达式的计算结果是 Promise 对象或者其它值(换句话说,就是没有特殊限定)。
因为 async 函数返回一个 Promise 对象,所以 await 可以用于等待一个 async 函数的返回值——这也可以说是 await 在等 async 函数,但要清楚,它等的实际是一个返回值。注意到 await 不仅仅用于等 Promise 对象,它可以等任意表达式的结果,所以,await 后面实际是可以接普通函数调用或者直接量的。所以下面这个示例完全可以正确运行
function getSomething() { return "something";}async function testAsync() { return Promise.resolve("hello async");}async function test() { const v1 = await getSomething(); const v2 = await testAsync(); console.log(v1, v2);}test();await 等到了它要等的东西,一个 Promise 对象,或者其它值,然后呢?我不得不先说,await 是个运算符,用于组成表达式,await 表达式的运算结果取决于它等的东西。如果它等到的不是一个 Promise 对象,那 await 表达式的运算结果就是它等到的东西。如果它等到的是一个 Promise 对象,await 就忙起来了,它会阻塞后面的代码,等着 Promise 对象 resolve,然后得到 resolve 的值,作为 await 表达式的运算结果。看到上面的阻塞一词,心慌了吧……放心,这就是 await 必须用在 async 函数中的原因。async 函数调用不会造成阻塞,它内部所有的阻塞都被封装在一个 Promise 对象中异步执行。复制代码
async/await 帮我们干了啥
作个简单的比较
上面已经说明了 async 会将其后的函数(函数表达式或 Lambda)的返回值封装成一个 Promise 对象,而 await 会等待这个 Promise 完成,并将其 resolve 的结果返回出来。
现在举例,用 setTimeout
模拟耗时的异步操作,先来看看不用 async/await 会怎么写
function takeLongTime() { return new Promise(resolve => { setTimeout(() => resolve("long_time_value"), 1000); });}takeLongTime().then(v => { console.log("got", v);});复制代码
如果改用 async/await 呢,会是这样
function takeLongTime() { return new Promise(resolve => { setTimeout(() => resolve("long_time_value"), 1000); });}async function test() { const v = await takeLongTime(); console.log(v);}test();复制代码
眼尖的同学已经发现 takeLongTime()
没有申明为 async
。实际上,takeLongTime()
本身就是返回的 Promise 对象,加不加 async
结果都一样,如果没明白,请回过头再去看看上面的“async 起什么作用”。
又一个疑问产生了,这两段代码,两种方式对异步调用的处理(实际就是对 Promise 对象的处理)差别并不明显,甚至使用 async/await 还需要多写一些代码,那它的优势到底在哪?
async/await 的优势在于处理 then 链
单一的 Promise 链并不能发现 async/await 的优势,但是,如果需要处理由多个 Promise 组成的 then 链的时候,优势就能体现出来了(很有意思,Promise 通过 then 链来解决多层回调的问题,现在又用 async/await 来进一步优化它)。
假设一个业务,分多个步骤完成,每个步骤都是异步的,而且依赖于上一个步骤的结果。我们仍然用 setTimeout
来模拟异步操作:
/** * 传入参数 n,表示这个函数执行的时间(毫秒) * 执行的结果是 n + 200,这个值将用于下一步骤 */function takeLongTime(n) { return new Promise(resolve => { setTimeout(() => resolve(n + 200), n); });}function step1(n) { console.log(`step1 with ${n}`); return takeLongTime(n);}function step2(n) { console.log(`step2 with ${n}`); return takeLongTime(n);}function step3(n) { console.log(`step3 with ${n}`); return takeLongTime(n);}复制代码
用 Promise 方式来实现这三个步骤的处理function doIt() { console.time("doIt"); const time1 = 300; step1(time1) .then(time2 => step2(time2)) .then(time3 => step3(time3)) .then(result => { console.log(`result is ${result}`); console.timeEnd("doIt"); });}doIt();// c:\var\test>node --harmony_async_await .// step1 with 300// step2 with 500// step3 with 700// result is 900// doIt: 1507.251ms复制代码
输出结果 result
是 step3()
的参数 700 + 200
= 900
。doIt()
顺序执行了三个步骤,一共用了 300 + 500 + 700 = 1500
毫秒,和 console.time()/console.timeEnd()
计算的结果一致。
如果用 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();复制代码
结果和之前的 Promise 实现是一样的,但是这个代码看起来是不是清晰得多,几乎跟同步代码一样
现在把业务要求改一下,仍然是三个步骤,但每一个步骤都需要之前每个步骤的结果。
function step1(n) { console.log(`step1 with ${n}`); return takeLongTime(n);}function step2(m, n) { console.log(`step2 with ${m} and ${n}`); return takeLongTime(m + n);}function step3(k, m, n) { console.log(`step3 with ${k}, ${m} and ${n}`); return takeLongTime(k + m + n);}复制代码
这回先用 async/await 来写:
async function doIt() { console.time("doIt"); const time1 = 300; const time2 = await step1(time1); const time3 = await step2(time1, time2); const result = await step3(time1, time2, time3); console.log(`result is ${result}`); console.timeEnd("doIt");}doIt();// c:\var\test>node --harmony_async_await .// step1 with 300// step2 with 800 = 300 + 500// step3 with 1800 = 300 + 500 + 1000// result is 2000// doIt: 2907.387ms复制代码
除了觉得执行时间变长了之外,似乎和之前的示例没啥区别啊!别急,认真想想如果把它写成 Promise 方式实现会是什么样子?
function doIt() { console.time("doIt"); const time1 = 300; step1(time1) .then(time2 => { return step2(time1, time2) .then(time3 => [time1, time2, time3]); }) .then(times => { const [time1, time2, time3] = times; return step3(time1, time2, time3); }) .then(result => { console.log(`result is ${result}`); console.timeEnd("doIt"); });}后续等待我今天把项目写完复制代码
2、
- HTTP协议、事件委托机制、CSS居中、CSS深入
- 缓存、HTTP协议、React-Redux、react渲染机制、ES6、异步机制、算法、爬虫
- React、React渲染机制、React diff机制、事件监听、addEventListener几个参数干嘛的,都有神马类型,参数里是否还有其他类型,干嘛的