前言
记录一些知识,方便巩固,不定时更新。
简单的3D动画
知识点:
perspective 属性定义 3D 元素距视图的距离,以像素计。
当为元素定义 perspective 属性时,其子元素会获得透视效果,而不是元素本身。
perspective 属性只影响 3D 转换元素。
与 perspective-origin 属性一同使用该属性,能够改变 3D 元素的底部位置。
transform-style: flat | preserve-3d; 属性指定嵌套元素是怎样在三维空间中呈现。
flat 表示所有子元素在2D平面呈现。
preserve-3d 表示所有子元素在3D空间中呈现。
transform 属性应用于元素的2D或3D转换。
演示:代码演示
简单的拖拽
知识点:
鼠标事件:
-
onmousedown 按下
-
onmousemove 移动
-
onmouseup 鼠标按键被松开
原理:元素按下时,监听文档拖拽位置,松开清空。
Mouse事件的event对象
-
offsetX/offsetY 相对于“自身”的水平/垂直坐标
-
clientX/clientY 相对于“当前窗口”的水平/垂直坐标 (不包含滚动距离)
-
pageX/pageY 相对于“文档”的水平/垂直坐标 (包含滚动距离)
-
screenX/screenY 相对于“屏幕”的水平/垂直坐标
演示:代码演示
事件循环 EventLoop
原作者讲的很详细,具体请参考:原文链接
事件循环
Event Loop,这是目前浏览器和NodeJS处理JavaScript代码的一种机制,而这种机制存在的背后,就有因为JavaScript是一门单线程的语言。
- 调用栈的概念
- 同步任务 / 异步任务 之间的差别和不同的执行机制
- 任务队列 (任务入队、宏任务/微任务)
- 事件循环的具体流程
事件循环的具体流程如下:
- 从宏任务队列中,按照入队顺序,找到第一个执行的宏任务,放入调用栈,开始执行;
- 执行完该宏任务下所有同步任务后,即调用栈清空后,该宏任务被推出宏任务队列,然后微任务队列开始按照入队顺序,依次执行其中的微任务,直至微任务队列清空为止;
- 当微任务队列清空后,一个事件循环结束;
- 接着从宏任务队列中,找到下一个执行的宏任务,开始第二个事件循环,直至宏任务队列清空为止。
这里有几个重点:
当我们第一次执行的时候,解释器会将整体代码
script放入宏任务队列中,因此事件循环是从第一个宏任务开始的;如果在执行微任务的过程中,产生新的微任务添加到微任务队列中,也需要一起清空;微任务队列没清空之前,是不会执行下一个宏任务的。
JavaScript call和apply 的模拟实现
原作者讲的很详细,具体请参考:冴羽大大的 - JavaScript深入之call和apply的模拟实现
O M G! 我真是不得了哇,这我都看懂了,先给自己鼓个掌,哈哈哈哈哈.....,咳咳,赶紧记一下,不然过会就忘了。
一句话介绍 call :
call()方法在使用一个指定的 this 值,和若干个指定的参数值,的前提下,调用某个函数或方法。
示例:
var foo = {
value:1
};
function bar() {
console.log(this.value)
}
bar.call(foo); // 1
两个知识点:
- call 改变了 this 的指向,指向到 foo
- bar 函数执行了
call 模拟实现步骤:
- 将函数设为对象的属性
- 执行该函数
- 删除该函数 另外再处理三种情况:
- this参数为null的情况
- 有多个参数的情况
- 函数有返回值的情况
call 模拟实现代码:
Function.prototype.call2 = function(context){
// 第一种情况:this 参数可以传 null,当为 null 的时候,视为指向 window
var context = context || window;
// 第一步:将函数设为对象的属性
// 这里的this指向的是bar,因为this是在运行时绑定的
// 根据 bar.call2(obj,'kevin',18) 调用得知 context.fn = this 相当于 obj.fn = bar
context.fn = this;
// 第二种情况:函数接受未知长度的参数
// arguments = {
// 0:foo,
// 1:'kevin',
// 2:18,
// length:3
// }
// 利用 arguments 对象,接受所有参数,然后从第二个参数开始循环,
// 因为第一个参数是传入的是要改变的this指向的参数,从第二位开始才是函数中要用到的参数。
// 这里执行后 args 为 ["arguments[1]","arguments[2]"]
var args = [];
for(var i = 1, len = arguments.length; i < len; i++){
args.push('arguments[' + args + ']');
}
// 第二步:执行 context.fn() 这个函数
// eval() 函数会将传入的字符串当做 JavaScript 代码进行执行。
var result = eval('context.fn(' + args + ')')
// 此时的写法相当于 context.fn(arguments[1],arguments[2]) 这样带参数的执行了一下。
// 第三步:删除 context.fn() 函数
delete context.fn;
// 第三种情况:函数有返回值
return result;
}
// 测试一下
var value = 2;
var obj = {
value: 1
}
function bar(name,age){
console.log(this.value)
return {
value: this.value,
name: name,
age: age
}
}
bar.call2(null); // 2 this参数为null,默认指向window
bar.call2(obj,'kevin',18)
// 1
// Object {
// value: 1,
// name: 'kevin'
// age: 18
// }
apply的模拟实现:
apply 的参数是放在数组里的。
Function.prototype.apply = function(context,arr){
var context = Object(context) || window;
context.fn = this;
var result;
if (!arr) {
result = context.fn();
} else {
var args = [];
for(var i = 0, len = arr.length; i < len; i++){
args.push('arr[' + i + ']');
}
result = eval('context.fn(' + args + ')')
}
delete context.fn;
return result;
}
未完待续......