《你不知道的JavaScript》笔记

本文是《你不知道的JavaScript》笔记,主要探讨JavaScript的上册内容,涵盖作用域、词法作用域、函数作用域与块作用域、变量提升、作用域闭包以及this的绑定规则。通过深入理解这些概念,有助于提升JavaScript编程技能。
摘要由CSDN通过智能技术生成

前言:虽然敲代码有一段时间了,但是都是在前辈早已写好的基础上进行代码完善的,调用的属性、变量都是被提前封装好的。而自己也发现了对js的知识有点欠缺,从今天开始抽空看这本书,并更新自己的学习笔记。

目录

上册

Ⅰ.作用域和闭包

一、作用域:

二、词法作用域

三、函数作用域和块作用域

四、提升

五、作用域闭包

六、补充

Ⅱ.this和对象原型

一、this


上册

Ⅰ.作用域和闭包

一、作用域:

1.引擎:负责js程序的编译及执行过程

2.编译器:负责语法分析及代码生成

3.作用域:负责收集并维护由所有声明的标识符组成的一系列查询。

  • LHS查询:赋值操作的目标是谁
  • RHS查询:谁是赋值操作的源头

遍历嵌套作用域链的规则:引擎从当前执行作用域开始查找变量,若未找到则向上一级继续查找,当抵达最外层的全局作用域时,不管是否找到,都会停止查找。

4.严格模式:严格模式禁止自动或隐式地创建全局变量。(也就是说,若对一个变量没有提前声明而是直接赋值的话会抛出异常)

5.异常:ReferenceError同作用域判别失败有关;TypeError代表作用域判别成功,但是对结果的操作是非法的或者不合理的(例如对一个非函数类型的值进行函数调用)

二、词法作用域

1.词法作用域:定义在词法阶段的作用域;

2.欺骗词法:运行时修改作用域(不推荐,会降低性能,且在严格模式下eval和with都无意义)

  • eval(...)
  • with(...)

三、函数作用域和块作用域

1.函数作用域:属于这个函数的全部变量都可以在整个函数的范围内使用及复用。

function foo(){
    function bar(a){
        i=3;//这里的i将for中的i覆盖掉了,导致for循环成为了一个无限循环
        console.log(a+i);
       }
    for(var i=0;i<10;i++){
        bar(i*2);
    }
}
foo();

上述代码片段是个无限循环,函数bar中的i将for循环中的i重新赋值了,导致for循环中的i一直为3且小于10,解决方法是:给bar中的i加上关键字var,或者将bar中的i改为j,或者将for中的var改为关键字let

(var没有自己的作用域,而在ES6中关键字let是有自己的作用域的)

2.块作用域:相当于在“块”声明的变量只能在“块”中读取它的值

  • try/catch:catch分句会创建一个块作用域,但不影响静态检查工具对在不同catch中的相同变量名发起警告
  • let:有自己的作用域,因此同var不同,不能进行作用域声明提升。
  • const:与let相同的是能创建块作用域,与let不同的是它创建的是常量,不能修改其值。

四、提升

1.声明提升:只有声明本身会提升,而赋值或其他运行逻辑不会。

2.函数声明:函数声明会被提升但是函数表达式不会。

foo();
function foo(){
    console.log(a); //undefined
    var a=2;
}

==>相当于
function foo(){
    var a;
    console.log(a);
    a=2;
}
foo()

因而第一段的写法不会报错

注意:函数表达式是不能进行声明提升的

foo(); //TypeError
var foo=function bar(){
    ...    
}

==>相当于
var foo;
foo();
foo=function bar(){
    ..
}

3.优先级:函数声明的优先级高于变量声明

foo(); /
var foo;
function foo(){
    console.log(1);
}
foo=function(){
    console.log(2);
}
//最终的输出结果为1

==>相当于
function foo(){
    console.log(1);
}
foo();
foo=function(){
    console.log(2);
}

五、作用域闭包

1.闭包:在函数词法作用域以外的地方被调用。(外部函数在被调用后其作用域应该被销毁,但由于闭包的存在阻止了它的销毁,使函数的内部作用域仍然存在,可以让我们继续访问外部函数的内部变量)

2.闭包的应用:定时器、事件监听器、Ajax请求、跨窗口通信、Web Workers或者其他异步或同步任务中使用了回调函数。

3.模块模式的必备条件:

  • 必须有外部的封闭函数,且该函数至少被调用一次;
  • 封闭函数必须返回至少一个内部函数,这样内部函数才能在私有作用域中形成闭包,并且可以访问或者修改私有的状态。

模块模式可以用来命名将要作为公共API返回的对象:

var foo=(function CoolModule(id){
    function change(){
    //修改公共API
    publicAPI.identify=identify2;
    }

    function identify1(){
        console.log(id);
    }
    function identify2(){
        console.log(id.toUpperCase());
    }
    
    var publicAPI={
        change:change,
        identify:identify1
    }
    
    return publicAPI;
})('foomodule');

foo.identify();//'foomodule'
foo.change();
foo.identify();//'FOOMODULE'

通过在模块示例的内部保留对公共API对象的内部引用,可以从内部对模块实例进行修改,包括增删改查等方法和属性,以及修改他们的值。

ES6的模块没有“行内”格式,必须被定义在单独的文件中(一个文件一个模块)。浏览器能够在导入模块时同步地加载模块文件。

  • import:可以将一个模块中的一个或多个API导入到当前作用域中,并分别绑定在一个变量上(eg.import xx from 'bar');
  • module会将整个模块的API导入并绑定到一个变量上(eg.module foo from 'foo');
  • export会将当前模块的一个标识符(变量、函数)导出为公共API

模块的特征:

  • 为创建内部作用域而调用了一个包装函数;
  • 包装函数的返回值必须匹配一个对内部函数的引用,这样就会创建涵盖整个包装函数内部作用域的闭包。

六、补充

1.词法作用域与动态作用域:词法作用域关注函数在何处声明;动态作用域关注函数从何处调用。

function foo(){
    console.log(a);
}

function bar(){
    var a=3;
    foo();
}
var a=2;
bar();
//最终foo()的输出结果为2

注意:JavaScript并不具有动态作用域,它只有词法作用域,所以上述示例的最终打印结果为2,而不是3。但是this机制在某种程度上很像动态作用域。

2.箭头函数:()=>{}

箭头函数放弃了所有普通this绑定的规则,用当前的词法作用域覆盖了this本来的值。

Ⅱ.this和对象原型

一、this

1.关于this的误解:

①this指向函数自身(误解)

function foo(num){
    console.log('foo:'+num);
    this.count++;
}
foo.count=0;
for(var i=0;i<10;i++){
    if(i>8){
        foo(i);
    }
}

console.log('count:'+foo.count);

最终执行结果为:   foo:9

                                count:0

foo()虽然调用了一次,但是count仍然为0,所以this指向函数自身是不准确的。

②this指向函数的作用域:某些情况是正确的,明确的是this永远不会指向函数的词法作用域。

2.this:this是在运行时绑定的,并不是在编写时绑定的,它的上下文取决与函数调用时的各种条件。也就是说,this的绑定和函数声明的位置没有关系,只取决于函数的调用方式。

  • 调用位置:函数在代码中被调用的位置(不是声明的位置)
  • 调用栈:为了达到当前执行位置所调用的所有函数

3.绑定规则:

①默认绑定:绑定到全局对象上(简单的函数调用)

function foo(){
    console.log(this.a) //这里的this为默认绑定
}
var a=2;
foo(); //2


//严格模式下
function foo(){
    'use strict';
    console.log(this.a) 
}
var a=2;
foo(); //TypeError:this is undefined

注意:严格模式下,不能将全局对象用于默认绑定

②隐式绑定:调用位置是否有上下文对象。在对象属性引用链中只有上一层或者说最后一层在调用位置起作用。

function foo(){
    console.log(this.a);
}
var obj1={
    a:2,
    foo:foo
};
var obj2={
    a:4,
    obj1:obj1
}
obj2.obj1.foo(); //2

③显示绑定:用call、apply方法指定this的绑定对象;ES5中提供了一个内置方法Function.prototype.bind。

bind返回一个硬编码的新韩淑,会把指定的参数设置为this的上下文并调用原始函数。

④new绑定:在JavaScript中的构造函数只是使用new操作符调用的普通函数。

使用new来调用函数时,会自动执行以下操作:

  • 创建一个全新的对象;
  • 这个新对象会被Prototype连接;
  • 这个新对象会绑定到函数调用的this
  • 若函数没有返回其他对象,那么new表达式中的函数调用会自动返回这个新对象。
function foo(a){
    this.a=a;
}
var bar=new foo(2);
console.log(bar.a);//2

4.绑定优先级:new绑定>显示绑定>隐式绑定>默认绑定

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值