js预编译
function fn(a, c) {console.log(a);var a = 123;console.log(a);console.log(c);function a() {}if (false) {var d = 678;}console.log(d);console.log(b);var b = function () {};console.log(b);function c() {}console.log(c);}fn(1, 2);AO: {a: undefined 1 function a(){}c: undefined 2 function c(){}d: undefinedb: undefined}// [Function: a]// 123// [Function: c]// undefined// undefined// [Function: b]/// [Function: c]
作用域的创建阶段 ==>预编译的阶段
预编译的时候做了哪些事情
js的变量对象 AO对象 供js引擎自己去访问的
- 创建了AO对象
- 找行参和变量的声明,作为AO对象的属性名,值为undefined
- 实参和形参相统一
- 找函数声明,会覆盖变量的声明
this 面试题(阿里)
var name = 222;var a = {name: 111,say: function () {console.log(this, this.name);},};var fun = a.say;fun(); // fun.call(window) 222a.say(); // a.say.call(a) 111var b = {name: 333,say: function (fn) {fun(); // fun.call(window)},};b.say(a.say); // 222b.say = a.say;b.say(); // b.say.call(b) 333
函数中直接使用
// jsfunction get(params) {console.log(params);}get("nihao");get.call(window, "nihao");
函数作为对象的方法被调用(谁调用我 我就指向谁)
// jsvar person = {name: "李四",run: function (time) {console.log(`${this.name} 在喝水 最多${time}min就喝完了`);},};person.run(30);person.run.call(person, 30);
箭头函数中的this
- 箭头函数中的this是在定义函数的时候绑定,而不是在执行函数的时候绑定。
箭头函数中,this指定的固定化,并不是因为箭头函数内部有绑定this的机制,实际原因是箭头函数根本没有自己的this,导致内部的this就是外层代码块的this。正是因为它没有this,所以也就不能用作构造函数。
箭头函数中的this是在定义函数的时候绑定
// jsvar x = 11;var obj = {x: 22,say: () => {console.log(this.x);},};obj.say(); // 11
所谓的定义时候绑定,就是this是继承自父执行上下文中的this,比如这里箭头函数的this.x,箭头函数本身与say平级以key:value的形式,也就是箭头函数本身所在的对象为obj,而obj的父执行上下文就是window,因此这里的this.x实际上表示的是window.x,因此输出是11。
// jsvar obj = {birth: 1990,getAge: function () {var b = this.birth;var fn = () => new Date().getFullYear() - this.birth;return fn;},};obj.getAge();
例子中箭头函数本身是在getAge方法中定义的,因此,getAge方法的父执行上下文是obj,因此这里的this指向则为obj对象。
js作用域
作用域的说明:一般理解指一个变量的作用范围
- 全局作用域
- 全局作用域在页面打开时被创建,页面关闭时被销毁
- 编写在script标签中的变量和函数,作用域为全局,在页面的任意位置都可以访问到
- 在全局作用域中有全局对象window,代表一个浏览器窗口,由浏览器创建,可以直接调用
- 全局作用域中声明的变量和函数会作为window对象的属性和方法保存
- 数据作用域
- 调用函数时,函数作用域被创建,函数执行完毕,函数作用域被销毁
- 每调用一次函数就会创建一个新的函数作用域,他们之间是相互独立的
- 在函数作用域中可以访问到全局作用域的变量,在函数外无法访问到函数作用域内的变量
- 在函数作用域中访问变量、函数时,会先在自身作用域中寻找,若没有找到时,则会到函数的上一级作用域中寻找,一直到全局作用域
- 作用域的深层次理解
- 执行期的上下文
- 当函数代码执行的前期,会创建一个执行期上下文的内部对象AO(作用域)
- 这个内部的对象是预编译的时候创建出来的,因为当函数被调用时,会进行预编译
- 在全局代码执行的前期会创建一个执行期的上下文的对象GO
- 函数作用域预编译
- 创建ao对象 AO{ }
- 找形参和变量声明,将变量和形参名当做AO对象的属性名,值为undefined
- 实参形参相统一
- 在函数体里面找函数声明,值赋予函数体
- 全局作用域的预编译
- 创建GO对象
- 找变量声明,将变量声明作为GO对象的属性名,值为undefined
- 找函数声明,值赋予函数体
- 作用域链
- 会被保存到一个隐式的属性中去[ [ scope ] ] 这个属性是我们用户访问不到的,但是的的确确是存在的,让js引擎来访问的,里面存储的就是作用域链 AO GO AO和GO的集合
闭包的底层原理
```javascript var createLogin = function () { var div = document.createElement(“div”); div.innerHTML = “我是登录的弹窗”; div.style.display = “none”; document.body.appendChild(div); return div; };
var getSingle = function (fn) { var result; return function () { return result || (result = fn.apply(this, arguments)); }; };
var create = getSingle(createLogin);
document.getElementById(“loginBtn”).onclick = function () {
var loginLay = create();
loginLay.style.display = “block”;
};
```
函数防抖就是法师发技能的时候要读条,技能读条没完再按技能就会重新读条。
函数节流就是fps游戏的射速,就算一直按着鼠标射击,也只会在规定射速内射出子弹。
- debounce
- search搜索联想,用户在不断输入值时,用防抖来节约请求资源。
- window触发resize的时候,不断的调整浏览器窗口大小会不断的触发这个事件,用防抖来让其只触发一次
- throttle
- 鼠标不断点击触发,mousedown(单位时间内只触发一次)
- 监听滚动事件,比如是否滑到底部自动加载更多,用throttle来判断
柯里化本质上是降低通用性,提高适用性。
