你不知道的js(一)--作用域与闭包

我们知道编程语言都有变量,变量用来存储值,并能对变量的值进行修改。但是这些值存在哪里?程序如何找到它们?这需要一套设计良好的规则来存储变量,并方便的找到这些变量,这套规则被称为作用域。

比如代码

var a = 2;

js会如何解释这段代码?

编译器会将这段代码分成两个操作进行处理。首先处理var a,编译器会询问作用域是否有一个该名称的变量存在于同一个作用域的集合中,如果有,编译器会忽略该声明继续编译;否则要求当前作用域在它的集合中声明一个新的变量a。然后编译器会为执行引擎生成运行时代码,这些代码用来处理 a = 2这个赋值操作。执行引擎首先询问作用域,当前作用域集合是否存在一个变量a。如果有,引擎使用该变量,并赋值为2;如果没有,引擎会询问外层作用域,直到找到该变量或抵达最外层作用域为止。

所以,在js中作用域是可以嵌套的。例如

function foo(a) {
    console.log(a + b)
}
var b = 2
foo(2);

foo函数调用会打印4,我们分析一下foo函数的调用过程,首先执行引擎在当前作用域查找变量a,找到a为2,然后再当前作用域查找变量b,发现没有,然后引擎到外层查找变量b,发现b为2,然后将a和b的值相加为4,最后打印出相加的结果4。
因为js执行引擎查找变量是从当前作用域开始逐层向外层作用域查找,直到找到第一个匹配的变量为止,所以在多层嵌套作用域中可以定义同名的变量,这叫做遮蔽效应。但是全局变量会自动成为全局对象window的属性,因此可以通过window对象访问被遮蔽的同名变量,例如window.a访问全局变量a。但是非全局变量如果被遮蔽,则无论如何都无法被访问到。

js中有两种机制可以实现“修改”作用域。它们是eval函数和with关键字。
js中eval()函数可以接受一个字符串作为参数,并将字符串内容作为js代码执行。例如:

function foo(str, a) {
    eval(str); // 执行str文本
    console.log(a, b)
}
var b = 2;
foo("var b = 3;", 1);

打印结果不是期盼的1,2,而是1,3。原因就是foo函数调用时传入的str参数是一段js代码,并被eval函数执行,在foo函数的作用域中生成了变量b且赋值为3,遮蔽了赋值为2的全局变量b。

另一种可以修改作用域的是with关键字,with通常被当作重复引用同一个对象中多个属性的快捷方式,可以不需要重复引用对象本身。例如:

var obj = {
    a: 1,
    b: 2,
    c: 3
}
// 重复引用对象
obj.a = 2;
obj.b = 3;
obj.c = 4;
// 快捷方式
with(obj) {
    a = 3;
    b = 4;
    c = 5;
}

考虑如下代码:

function foo(obj) {
    with(obj){
        a = 2;
    } 
}
var o1 = {
    a: 3
}
var o2 = {
    b: 3 
}
foo(o1);
console.log(o1.a); // 2
foo(o2);
console.log(o2.a); // undefined
console.log(a); // 2

第一个和第二个打印结果很好理解,o1有属性a所有可以成被赋值为2,o2没有数据a所有打印结果为undefined。但值为2的a变量是从哪里冒出来的呢?其实在执行foo(o2)时,执行引擎在所有的作用域中都找不到变量a,有因为是非严格模式,所以当执行a=2时,自动创建了一个全局变量a,并赋值为2。
因为eval和with会影响到作用域的变化,所有js执行引擎在编译阶段进行代码优化时产生影响,因为变量的作用域会发生改变,所以最好不要使用它们。

一、函数作用域

函数作用域是指,属于当前函数的全部变量都可以在整个函数的范围内使用及复用,无法从外部作用域访问函数内部的任何内容。
例如:

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

foo函数的console.log打印的是函数内部的值为3的变量a,而不是值为2的变量a。

二、块作用域

也就是使用{}括起来的一段代码区域,其中定义的全部变量只能在该快作用域中使用,无法在外部作用域访问到。

  • for循环
for (var i=0i<10; i++) {
    console.log(i)
}

其中i变量只能在for循环代码块作用域中使用
- if 语句

var foo = true;
if (foo) {
    var bar = foo * 2
    console.log(bar);
}

bar变量只能在if语句块作用域中使用
js中的块作用域还有with语句块、try/catch语句块、let语句块、const语句块等

三、变量声明提升

我们先来看一段代码:

a = 2;
var a;
console.log(a);

这段代码会打印什么?很多开发者可能认为是undefined,因为a的值被var = a;这段代码重新赋于默认值undefined了。但是运行代码后输出的结果却是2。
为什么会这样呢?这是因为编译器会将全部的声明操作在任何代码被执行前首先被处理。而且要注意的是如果同时又函数声明和变量声明,函数声明会首先被提升,然后才是变量声明。
例如:

foo();
var foo;

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

foo = function() {
    console.log(2);
};

运行这段代码,输出的是1,而不是2。因为这段代码会被执行引擎理解为如下形式:

function foo() {
    console.log(1);
}
foo();  // 1
foo = function() {
    console.log(2);
}

注意,var foo尽管在function foo() …的声明之前,但它是重复声明会被忽略。虽然重复的var声明会被忽略,但是出现在后面的函数声明还是可以覆盖前面的。
例如:

foo();  // 3
function foo() {
    console.log(1);
}
var foo = function() {
    console.log(2);
}
function foo() {
    console.log(3);
}

所以在同一个作用域中最好不要重复定义,那样会导致各种奇怪的问题。

四、闭包

当函数可以记住并访问它所定义时的作用域时,就产生了闭包,即使函数是在当前作用域之外执行。
例如:

function foo() {
    var a = 2;

    function bar() {
        console.log(a);
    }
    return bar;
}
var baz = foo();
baz(); // 2

baz函数调用会输出2,也就是说它可以访问foo函数的内部作用域,这就是闭包的效果。
对函数类型的值进行传递,但函数在别处被调用时都可以观察到闭包。

function foo() {
    var a = 2;
    function baz() {
        console.log(a);
    }
    bar(baz);
}

function bar(fn) {
    fn();  // 2
}

如果将函数当作值类型并到处传递,就会看到闭包在这些函数中的应用。
我们还可以通过函数和闭包实现模块化编程
例如:

function MyModule() {
    var something = "cool";
    var array = [1, 2, 3];

    function func1() {
        console.log(something);
    }

    function func2() {
        console.log(array.join(","))
    }

    return {
        func1: func1,
        func2: func2
    }
}

var foo = MyModule();
foo.func1();    // cool
foo.func2();    // 1,2,3

MyModule()只是一个函数,通过调用该函数创建了一个模块实例。如果不执行外部函数,内部作用域和闭包都无法创建。通过调用MyModule()函数返回了一个对象字面量语法,从而创建了一个对象。该对象中含有MyModule()函数内部函数的引用。这样我们做到了保持模块内部数据的隐藏且私有,将返回的对象类型看做模块的公共API进行调用。
我们使用函数的apply()方法来实现一个简单的模块管理器:

var ModuleManager = (function Manager(){
    var modules = {};

    function define(name, deps, impl) {
        for (var i=0; i<deps.length; i++) {
            deps[i] = modules[deps[i]];
        }
        modules[name] = impl.apply(impl, deps);
    }

    function get(name) {
        return modules[name];
    }
})();

ModuleManager.define("bar", [], function(){
    function hello(who) {
        return "Let me introduce:" + who;
    }

    return {
        hello: hello
    };
});

ModuleManager.define("foo", ["bar"], function(){
    var hungry = "hippo";
    function awesome() {
        console.log(bar.hello(hungry).toUpperCase);
    }
    return {
        awesome: awesome
    };
});

var bar = ModuleManager.get("bar");
var foo = ModuleManager.get("foo");

console.log(bar.hello("hippo")); // Let me introduce: hippo
foo.awesome();  // LET ME INTRODUCE: HIPPO

ES6为模块增加了语法级的支持,ES6的模块必须被定义在独立的文件中,一个文件一个模块。
例如,定义一个bar.js,文件内容如下:

function hello(who) {
    return "Let me introduce: " + who;
}

export hello;

这样我们便创建了一个名字为bar的模块。模块有一个函数hello暴露出来可以调用。

智慧旅游解决方案利用云计算、物联网和移动互联网技术,通过便携终端设备,实现对旅游资源、经济、活动和旅游者信息的智能感知和发布。这种技术的应用旨在提升游客在旅游各个环节的体验,使他们能够轻松获取信息、规划行程、预订票务和安排食宿。智慧旅游平台为旅游管理部门、企业和游客提供服务,包括政策发布、行政管理、景区安全、游客流量统计分析、投诉反馈等。此外,平台还提供广告促销、库存信息、景点介绍、电子门票、社交互动等功能。 智慧旅游的建设规划得到了国家政策的支持,如《国家中长期科技发展规划纲要》和国务院的《关于加快发展旅游业的意见》,这些政策强调了旅游信息服务平台的建设和信息化服务的重要性。随着技术的成熟和政策环境的优化,智慧旅游的时机已经到来。 智慧旅游平台采用SaaS、PaaS和IaaS等云服务模式,提供简化的软件开发、测试和部署环境,实现资源的按需配置和快速部署。这些服务模式支持旅游企业、消费者和管理部门开发高性能、高可扩展的应用服务。平台还整合了旅游信息资源,提供了丰富的旅游产品创意平台和统一的旅游综合信息库。 智慧旅游融合应用面向游客和景区景点主管机构,提供无线城市门户、智能导游、智能门票及优惠券、景区综合安防、车辆及停车场管理等服务。这些应用通过物联网和云计算技术,实现了旅游服务的智能化、个性化和协同化,提高了旅游服务的自由度和信息共享的动态性。 智慧旅游的发展标志着旅游信息化建设的智能化和应用多样化趋势,多种技术和应用交叉渗透至旅游行业的各个方面,预示着全面的智慧旅游时代已经到来。智慧旅游不仅提升了游客的旅游体验,也为旅游管理和服务提供了高效的技术支持。
智慧旅游解决方案利用云计算、物联网和移动互联网技术,通过便携终端设备,实现对旅游资源、经济、活动和旅游者信息的智能感知和发布。这种技术的应用旨在提升游客在旅游各个环节的体验,使他们能够轻松获取信息、规划行程、预订票务和安排食宿。智慧旅游平台为旅游管理部门、企业和游客提供服务,包括政策发布、行政管理、景区安全、游客流量统计分析、投诉反馈等。此外,平台还提供广告促销、库存信息、景点介绍、电子门票、社交互动等功能。 智慧旅游的建设规划得到了国家政策的支持,如《国家中长期科技发展规划纲要》和国务院的《关于加快发展旅游业的意见》,这些政策强调了旅游信息服务平台的建设和信息化服务的重要性。随着技术的成熟和政策环境的优化,智慧旅游的时机已经到来。 智慧旅游平台采用SaaS、PaaS和IaaS等云服务模式,提供简化的软件开发、测试和部署环境,实现资源的按需配置和快速部署。这些服务模式支持旅游企业、消费者和管理部门开发高性能、高可扩展的应用服务。平台还整合了旅游信息资源,提供了丰富的旅游产品创意平台和统一的旅游综合信息库。 智慧旅游融合应用面向游客和景区景点主管机构,提供无线城市门户、智能导游、智能门票及优惠券、景区综合安防、车辆及停车场管理等服务。这些应用通过物联网和云计算技术,实现了旅游服务的智能化、个性化和协同化,提高了旅游服务的自由度和信息共享的动态性。 智慧旅游的发展标志着旅游信息化建设的智能化和应用多样化趋势,多种技术和应用交叉渗透至旅游行业的各个方面,预示着全面的智慧旅游时代已经到来。智慧旅游不仅提升了游客的旅游体验,也为旅游管理和服务提供了高效的技术支持。
深度学习是机器学习的一个子领域,它基于人工神经网络的研究,特别是利用多层次的神经网络来进行学习和模式识别。深度学习模型能够学习数据的高层次特征,这些特征对于图像和语音识别、自然语言处理、医学图像分析等应用至关重要。以下是深度学习的一些关键概念和组成部分: 1. **神经网络(Neural Networks)**:深度学习的基础是人工神经网络,它是由多个层组成的网络结构,包括输入层、隐藏层和输出层。每个层由多个神经元组成,神经元之间通过权重连接。 2. **前馈神经网络(Feedforward Neural Networks)**:这是最常见的神经网络类型,信息从输入层流向隐藏层,最终到达输出层。 3. **卷积神经网络(Convolutional Neural Networks, CNNs)**:这种网络特别适合处理具有网格结构的数据,如图像。它们使用卷积层来提取图像的特征。 4. **循环神经网络(Recurrent Neural Networks, RNNs)**:这种网络能够处理序列数据,如时间序列或自然语言,因为它们具有记忆功能,能够捕捉数据中的时间依赖性。 5. **长短期记忆网络(Long Short-Term Memory, LSTM)**:LSTM 是一种特殊的 RNN,它能够学习长期依赖关系,非常适合复杂的序列预测任务。 6. **生成对抗网络(Generative Adversarial Networks, GANs)**:由两个网络组成,一个生成器和一个判别器,它们相互竞争,生成器生成数据,判别器评估数据的真实性。 7. **深度学习框架**:如 TensorFlow、Keras、PyTorch 等,这些框架提供了构建、训练和部署深度学习模型的工具和库。 8. **激活函数(Activation Functions)**:如 ReLU、Sigmoid、Tanh 等,它们在神经网络中用于添加非线性,使得网络能够学习复杂的函数。 9. **损失函数(Loss Functions)**:用于评估模型的预测与真实值之间的差异,常见的损失函数包括均方误差(MSE)、交叉熵(Cross-Entropy)等。 10. **优化算法(Optimization Algorithms)**:如梯度下降(Gradient Descent)、随机梯度下降(SGD)、Adam 等,用于更新网络权重,以最小化损失函数。 11. **正则化(Regularization)**:技术如 Dropout、L1/L2 正则化等,用于防止模型过拟合。 12. **迁移学习(Transfer Learning)**:利用在一个任务上训练好的模型来提高另一个相关任务的性能。 深度学习在许多领域都取得了显著的成就,但它也面临着一些挑战,如对大量数据的依赖、模型的解释性差、计算资源消耗大等。研究人员正在不断探索新的方法来解决这些问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值