javascript-深入理解js

本文详细介绍了JavaScript中的预编译机制,包括函数作用域的预编译过程。深入探讨了对象的getter和setter、this的指向,特别是箭头函数中的this绑定规则。此外,还讨论了作用域的概念、script标签的异步和延迟执行选项、性能优化策略以及H5新API,如requestAnimationFrame。最后,提到了严格模式下的额外限制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

预编译

函数作用域预编译
  1. 创建AO对象(活动对象)

  2. 找形参和变量的声明,作为AO对象的属性名,值为undefined

  3. 实参和形参相互统一(也就是将实参的值赋给形参)

  4. 找函数声明,如果与变量同名,会覆盖变量的声明

  5. function fn(a,c){
        console.log(a);     // function a(){}
        var a = 123;
        console.log(a);     // 123
        console.log(c);     // function c(){}
        function a(){}
        if (false){
            var d = 678;
        }
        console.log(d);     // undefined
        console.log(b);     // undefined
        var b = function(){}
        console.log(b);     // function(){}
        function c(){}
        console.log(c);     // function c(){}
    }
    fn(1,2);
    /*
    ao{    第一步       第二步      第三步
    a: undefined    1          function a(){}
    c: undefined    2          function c(){}
    d: undefined
    b: undefined
    }
    */
    

对象的getter和setter函数

var obj = {
    name: "chen",
    age: 12,
    get getterAttr(){
        // 函数不能带参数
        // console.log(this);
        console.log("getter", this.name);
        return "这是调用属性getterAttr的getter函数";
    }
}
Object.defineProperty(obj, "testAttr", {
    get: function(){ console.log("testAttr"); return "testAttr"}
});
// console.log(obj);

console.log(obj.getterAttr);
console.log(obj.testAttr);
// getter chen
// 这是调用属性getterAttr的getter函数
// testAttr
// testAttr

this的指向

在函数执行的时候进行this的绑定

  1. 函数直接调用 func(a) 等价与 func.call(window,a),this指向window

  2. 函数作为对象的方法被调用,就指向这个函数

  3. 如果函数是一个构造函数,则this指向一个新的对象

  4. 在严格模式下:函数直接调用,this不是全局对象,而是undefined

  5. var name = 222;
    var a = {
        name: 111,
        say: function(){
            console.log(this.name);
        }
    };
    var fun = a.say;
    fun();  // 222      fun.call(window);
    a.say();    // 111  a.say.call(a);
    
    var b = {
        name: 333,
        say: function(fn){
            fn();   // fn.call(window);
        }
    }
    b.say(a.say);   // 222  
    b.say = a.say;
    b.say();        // 333  b.say.call(b)
    

箭头函数的this

  1. 箭头函数中的this是在定义函数的时候绑定的,而不是在执行函数的时候绑定,箭头函数this指向固定化,实际原因是因为箭头函数没有this,导致内部的this就是外层代码块(父执行上下文)的this,正因为他没有this,所以不能用作构造函数
  2. 箭头函数没有this,没有arguments,用来设置匿名函数,不能用call/apply改变this的指向,会自动忽略
  3. this:该箭头函数所在的作用域指向的对象,也就是父级的this指针,可以用过修改父级的指针,达到修改箭头函数的this指向。
  4. 或者可以简单理解:然后箭头函数的this指针就是调用外层函数的对象,若箭头函数没有外层函数,那么就是window
var a = 222;
var obj = {
    a: 333,
    fn: ()=>{
        console.log(this.a);
    }
}
obj.fn();   // 222,this指向window
var a = 222;
var obj = {
    a: 333,
    b: {
        fn: ()=>{
            console.log(this.a);
        }
    }
}
obj.b.fn(); // 222
var a = 222;
var obj = {
    a: 333,
    b: function(){
        var fn = () => console.log(this.a);
        return fn;
    }
}
obj.b()();  // 333

作用域

含义:简单来说,就是有效访问变量的集合,js只有函数作用域和全局作用域,当然可以使用let,const定义块级作用域的变量,函数被调用时就会创建函数作用域,在函数作用域创建的前期,会进行函数作用域和全局作用域的预编译,这个函数作用域预编译阶段会创建一个活动对象OA,然后对函数内的形参和变量声明,将变量和形参名当做AO对象的属性,值设置为undefined;然后将函数实参的值赋值给形参,接着在函数体找到函数声明,若存在函数名与变量同名,则覆盖变量的声明;

在函数内对一个未用var声明的变量直接赋值,就会变成全局变量

不同的作用域,变量名可以重复,查找的时候,就是沿着作用域链往上查找,找到最近的

函数声明和变量声明都会提升,且函数声明优先级大于变量声明

var a = "apple";
// var声明的变量没有块级作用域,不要被括号迷惑
if (true) {
    var a = "bananer";
}
console.log(a); // bananer

script标签

asyncdefer不同之处是async加载完成后会自动执行脚本,defer加载完成后需要等待页面也加载完成才会执行代码,defer:异步加载,延迟执行

性能

  1. 注意作用域
    • 避免全局查找,全局变量和函数的查找需要涉及作用域链上的查找
    • 避免使用with语句,因为with语句会创建自己的作用域,因此会增加with语句执行代码的作用域链长度
  2. 选择正确的方法
    • 访问对象的属性O(n),因为要搜索原型链,所以遇到对象的查找,找到后可以存放起来;数组和变量,O(1);
    • 优化循环,例如可以保存len的值,i<len;替换i<arr.len;
    • 展开循环
    • 避免双重解释:就是字符串的内容是js代码;初始解析不能识别,代码运行的时候还得新开启一个解析器来解析新的代码,开销太大
    • 其他:原生方法快,switch语句快,位运算快
  3. 最小化语句数
    • 多个变量声明写成一个语句
    • 插入迭代值:var name = arr[i++];
    • 使用数据和对象字面量
  4. 优化DOM操作
    • 使用innerHTML,文档片段createDocumentFragment();
    • 事件代理(事件委托):利用了事件冒泡,只指定一个事件处理程序,就可以管理某一类型的所有事件
    • HTMLCollection(注意保存):html元素的集合,例如:document.getElementByTagName
  5. 部署:压缩代码

h5的新api

  1. requestAnimationFrame(callback):告诉浏览器——你希望执行一个动画,并且要求浏览器在下次重绘之前调用指定的回调函数更新动画。该方法需要传入一个回调函数作为参数,该回调函数会在浏览器下一次重绘之前执行(为何要引入:因为setTimeout、setInterval设置delay的时间,这个时候不一定跟浏览器的刷新频率一致,所以可能会出现丢帧或者动画效果生硬的问题)

严格模式下的有关限制

  1. this为null,undefined时,不会自动转换为window对象(call,apply,bind)
  2. 不能对为声明的变量进行赋值操作

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值