环境是你要安装Keras和Tensorflow

先来个network.py,里面定义了生成器网络和鉴别器网络:

 # -*- coding: UTF-8 -*-

 """
DCGAN 深层卷积的生成对抗网络
""" import tensorflow as tf # Hyper parameter(超参数)
EPOCHS = 100
BATCH_SIZE = 128
LEARNING_RATE = 0.0002
BETA_1 = 0.5 # 定义判别器模型
def discriminator_model():
model = tf.keras.models.Sequential() model.add(tf.keras.layers.Conv2D(
64, # 64 个过滤器,输出的深度(depth)是 64
(5, 5), # 过滤器在二维的大小是(5 * 5)
padding='same', # same 表示输出的大小不变,因此需要在外围补零2圈
input_shape=(64, 64, 3) # 输入形状 [64, 64, 3]。3 表示 RGB 三原色
))
model.add(tf.keras.layers.Activation("tanh")) # 添加 Tanh 激活层
model.add(tf.keras.layers.MaxPool2D(pool_size=(2, 2))) # 池化层
model.add(tf.keras.layers.Conv2D(128, (5, 5)))
model.add(tf.keras.layers.Activation("tanh"))
model.add(tf.keras.layers.MaxPool2D(pool_size=(2, 2)))
model.add(tf.keras.layers.Conv2D(128, (5, 5)))
model.add(tf.keras.layers.Activation("tanh"))
model.add(tf.keras.layers.MaxPool2D(pool_size=(2, 2)))
model.add(tf.keras.layers.Flatten()) # 扁平化
model.add(tf.keras.layers.Dense(1024)) # 1024 个神经元的全连接层
model.add(tf.keras.layers.Activation("tanh"))
model.add(tf.keras.layers.Dense(1)) # 1 个神经元的全连接层
model.add(tf.keras.layers.Activation("sigmoid")) # 添加 Sigmoid 激活层 return model # 定义生成器模型
# 从随机数来生成图片
def generator_model():
model = tf.keras.models.Sequential()
# 输入的维度是 100, 输出维度(神经元个数)是1024 的全连接层
model.add(tf.keras.layers.Dense(input_dim=100, units=1024))
model.add(tf.keras.layers.Activation("tanh"))
model.add(tf.keras.layers.Dense(128 * 8 * 8)) # 8192 个神经元的全连接层
model.add(tf.keras.layers.BatchNormalization()) # 批标准化
model.add(tf.keras.layers.Activation("tanh"))
model.add(tf.keras.layers.Reshape((8, 8, 128), input_shape=(128 * 8 * 8, ))) # 8 x 8 像素
model.add(tf.keras.layers.UpSampling2D(size=(2, 2))) # 16 x 16像素
model.add(tf.keras.layers.Conv2D(128, (5, 5), padding="same"))
model.add(tf.keras.layers.Activation("tanh"))
model.add(tf.keras.layers.UpSampling2D(size=(2, 2))) # 32 x 32像素
model.add(tf.keras.layers.Conv2D(128, (5, 5), padding="same"))
model.add(tf.keras.layers.Activation("tanh"))
model.add(tf.keras.layers.UpSampling2D(size=(2, 2))) # 64 x 64像素
model.add(tf.keras.layers.Conv2D(3, (5, 5), padding="same"))
model.add(tf.keras.layers.Activation("tanh")) return model # 构造一个 Sequential 对象,包含一个 生成器 和一个 判别器
# 输入 -> 生成器 -> 判别器 -> 输出
def generator_containing_discriminator(generator, discriminator):
model = tf.keras.models.Sequential()
model.add(generator)
discriminator.trainable = False # 初始时 判别器 不可被训练
model.add(discriminator)
return model

接着我们写个训练模型的文件,train..py

 # -*- coding: UTF-8 -*-

 """
训练 DCGAN
""" import os
import glob
import numpy as np
from scipy import misc
import tensorflow as tf from network import * def train():
# 确保包含所有图片的 images 文件夹在所有 Python 文件的同级目录下
# 当然了,你也可以自定义文件夹名和路径
if not os.path.exists("images"):
raise Exception("包含所有图片的 images 文件夹不在此目录下,请添加") # 获取训练数据
data = []
for image in glob.glob("images/*"):
image_data = misc.imread(image) # imread 利用 PIL 来读取图片数据
data.append(image_data)
input_data = np.array(data) # 将数据标准化成 [-1, 1] 的取值, 这也是 Tanh 激活函数的输出范围
input_data = (input_data.astype(np.float32) - 127.5) / 127.5 # 构造 生成器 和 判别器
g = generator_model()
d = discriminator_model() # 构建 生成器 和 判别器 组成的网络模型
d_on_g = generator_containing_discriminator(g, d) # 优化器用 Adam Optimizer
g_optimizer = tf.keras.optimizers.Adam(lr=LEARNING_RATE, beta_1=BETA_1)
d_optimizer = tf.keras.optimizers.Adam(lr=LEARNING_RATE, beta_1=BETA_1) # 配置 生成器 和 判别器
g.compile(loss="binary_crossentropy", optimizer=g_optimizer)
d_on_g.compile(loss="binary_crossentropy", optimizer=g_optimizer)
d.trainable = True
d.compile(loss="binary_crossentropy", optimizer=d_optimizer) # 开始训练
for epoch in range(EPOCHS):
for index in range(int(input_data.shape[0] / BATCH_SIZE)):
input_batch = input_data[index * BATCH_SIZE : (index + 1) * BATCH_SIZE] # 连续型均匀分布的随机数据(噪声)
random_data = np.random.uniform(-1, 1, size=(BATCH_SIZE, 100))
# 生成器 生成的图片数据
generated_images = g.predict(random_data, verbose=0) input_batch = np.concatenate((input_batch, generated_images))
output_batch = [1] * BATCH_SIZE + [0] * BATCH_SIZE # 训练 判别器,让它具备识别不合格生成图片的能力
d_loss = d.train_on_batch(input_batch, output_batch) # 当训练 生成器 时,让 判别器 不可被训练
d.trainable = False # 重新生成随机数据。很关键
random_data = np.random.uniform(-1, 1, size=(BATCH_SIZE, 100)) # 训练 生成器,并通过不可被训练的 判别器 去判别
g_loss = d_on_g.train_on_batch(random_data, [1] * BATCH_SIZE) # 恢复 判别器 可被训练
d.trainable = True # 打印损失
print("Epoch {}, 第 {} 步, 生成器的损失: {:.3f}, 判别器的损失: {:.3f}".format(epoch, index, g_loss, d_loss)) # 保存 生成器 和 判别器 的参数
# 大家也可以设置保存时名称不同(比如后接 epoch 的数字),参数文件就不会被覆盖了
if epoch % 1 == 0:
g.save_weights("./generator_weight.h5", True)
d.save_weights("./discriminator_weight", True) if __name__ == "__main__":
train()

运行这个文件,就可以产生生成器网络的权重文件  generator_weight.h5, 这里我选择每个训练epoch都保存一次权重文件。你可以按你的喜好来。

  训练好了之后,那么我们就可以用generate.py文件,从随机数据生成好看的花朵了。

 # -*- coding: UTF-8 -*-

 """
用 DCGAN 的生成器模型 和 训练得到的生成器参数文件 来生成图片
""" import numpy as np
from PIL import Image
import tensorflow as tf from network import * def generate():
# 构造生成器
g = generator_model() # 配置 生成器
g.compile(loss="binary_crossentropy", optimizer=tf.keras.optimizers.Adam(lr=LEARNING_RATE, beta_1=BETA_1)) # 加载训练好的 生成器 参数
g.load_weights("generator_weight.h5") # 连续型均匀分布的随机数据(噪声)
random_data = np.random.uniform(-1, 1, size=(BATCH_SIZE, 100)) # 用随机数据作为输入,生成器 生成图片数据
images = g.predict(random_data, verbose=1) # 用生成的图片数据生成 PNG 图片
for i in range(BATCH_SIZE):
image = images[i] * 127.5 + 127.5
Image.fromarray(image.astype(np.uint8)).save("./generated_image/image-%s.png" % i) if __name__ == "__main__":
generate()

附注1: 一些训练过程

C:\ProgramData\Anaconda3\python.exe D:/threeTFproject/Case2_AI_Photoshop/train.py
C:\ProgramData\Anaconda3\lib\site-packages\h5py\__init__.py:36: FutureWarning: Conversion of the second argument of issubdtype from `float` to `np.floating` is deprecated. In future, it will be treated as `np.float64 == np.dtype(float).type`.
from ._conv import register_converters as _register_converters
2018-11-01 09:29:35.205667: I tensorflow/core/platform/cpu_feature_guard.cc:141] Your CPU supports instructions that this TensorFlow binary was not compiled to use: AVX2
Epoch 0, 第 0 步, 生成器的损失: 0.169, 判别器的损失: 0.732
Epoch 0, 第 1 步, 生成器的损失: 0.258, 判别器的损失: 0.577
Epoch 0, 第 2 步, 生成器的损失: 0.680, 判别器的损失: 0.534
Epoch 0, 第 3 步, 生成器的损失: 1.493, 判别器的损失: 0.451
Epoch 0, 第 4 步, 生成器的损失: 1.484, 判别器的损失: 0.513
Epoch 0, 第 5 步, 生成器的损失: 2.465, 判别器的损失: 0.350
Epoch 0, 第 6 步, 生成器的损失: 4.008, 判别器的损失: 0.313
Epoch 0, 第 7 步, 生成器的损失: 2.139, 判别器的损失: 0.494
Epoch 0, 第 8 步, 生成器的损失: 2.939, 判别器的损失: 0.501
Epoch 0, 第 9 步, 生成器的损失: 3.805, 判别器的损失: 0.415
Epoch 0, 第 10 步, 生成器的损失: 3.413, 判别器的损失: 0.590
Epoch 0, 第 11 步, 生成器的损失: 2.520, 判别器的损失: 0.486
Epoch 0, 第 12 步, 生成器的损失: 2.286, 判别器的损失: 0.471
Epoch 0, 第 13 步, 生成器的损失: 1.228, 判别器的损失: 0.670
Epoch 0, 第 14 步, 生成器的损失: 0.561, 判别器的损失: 0.655
Epoch 0, 第 15 步, 生成器的损失: 0.560, 判别器的损失: 0.517
Epoch 0, 第 16 步, 生成器的损失: 0.643, 判别器的损失: 0.490
Epoch 0, 第 17 步, 生成器的损失: 0.727, 判别器的损失: 0.488
Epoch 0, 第 18 步, 生成器的损失: 1.003, 判别器的损失: 0.734
Epoch 0, 第 19 步, 生成器的损失: 1.235, 判别器的损失: 0.379
Epoch 0, 第 20 步, 生成器的损失: 1.869, 判别器的损失: 0.377
Epoch 0, 第 21 步, 生成器的损失: 2.073, 判别器的损失: 0.384
Epoch 0, 第 22 步, 生成器的损失: 1.185, 判别器的损失: 0.613
WARNING:tensorflow:This model was compiled with a Keras optimizer (<tensorflow.python.keras.optimizers.Adam object at 0x0000019D240A8BA8>) but is being saved in TensorFlow format with `save_weights`. The model's weights will be saved, but unlike with TensorFlow optimizers in the TensorFlow format the optimizer's state will not be saved. Consider using a TensorFlow optimizer from `tf.train`.
Epoch 1, 第 0 步, 生成器的损失: 2.079, 判别器的损失: 0.590
Epoch 1, 第 1 步, 生成器的损失: 1.161, 判别器的损失: 0.506
Epoch 1, 第 2 步, 生成器的损失: 1.137, 判别器的损失: 0.451
Epoch 1, 第 3 步, 生成器的损失: 1.538, 判别器的损失: 0.346
Epoch 1, 第 4 步, 生成器的损失: 1.733, 判别器的损失: 0.362
Epoch 1, 第 5 步, 生成器的损失: 2.059, 判别器的损失: 0.275
Epoch 1, 第 6 步, 生成器的损失: 2.376, 判别器的损失: 0.243
Epoch 1, 第 7 步, 生成器的损失: 2.260, 判别器的损失: 0.300
Epoch 1, 第 8 步, 生成器的损失: 3.750, 判别器的损失: 0.240
Epoch 1, 第 9 步, 生成器的损失: 3.422, 判别器的损失: 0.222
Epoch 1, 第 10 步, 生成器的损失: 4.694, 判别器的损失: 0.275
Epoch 1, 第 11 步, 生成器的损失: 2.299, 判别器的损失: 0.411
Epoch 1, 第 12 步, 生成器的损失: 4.065, 判别器的损失: 0.547
Epoch 1, 第 13 步, 生成器的损失: 1.834, 判别器的损失: 0.470
Epoch 1, 第 14 步, 生成器的损失: 0.398, 判别器的损失: 1.344
Epoch 1, 第 15 步, 生成器的损失: 1.134, 判别器的损失: 0.973
Epoch 1, 第 16 步, 生成器的损失: 2.866, 判别器的损失: 0.374
Epoch 1, 第 17 步, 生成器的损失: 1.056, 判别器的损失: 0.767
Epoch 1, 第 18 步, 生成器的损失: 0.916, 判别器的损失: 0.603
Epoch 1, 第 19 步, 生成器的损失: 1.151, 判别器的损失: 0.645
Epoch 1, 第 20 步, 生成器的损失: 1.947, 判别器的损失: 0.411
Epoch 1, 第 21 步, 生成器的损失: 3.122, 判别器的损失: 0.314
Epoch 1, 第 22 步, 生成器的损失: 1.805, 判别器的损失: 0.642
WARNING:tensorflow:This model was compiled with a Keras optimizer (<tensorflow.python.keras.optimizers.Adam object at 0x0000019D240A8BA8>) but is being saved in TensorFlow format with `save_weights`. The model's weights will be saved, but unlike with TensorFlow optimizers in the TensorFlow format the optimizer's state will not be saved. Consider using a TensorFlow optimizer from `tf.train`.
Epoch 2, 第 0 步, 生成器的损失: 1.240, 判别器的损失: 0.569
Epoch 2, 第 1 步, 生成器的损失: 1.151, 判别器的损失: 0.449
Epoch 2, 第 2 步, 生成器的损失: 1.395, 判别器的损失: 0.332
Epoch 2, 第 3 步, 生成器的损失: 1.649, 判别器的损失: 0.258
Epoch 2, 第 4 步, 生成器的损失: 1.777, 判别器的损失: 0.277
Epoch 2, 第 5 步, 生成器的损失: 1.562, 判别器的损失: 0.268
Epoch 2, 第 6 步, 生成器的损失: 2.229, 判别器的损失: 0.224
Epoch 2, 第 7 步, 生成器的损失: 2.432, 判别器的损失: 0.272
Epoch 2, 第 8 步, 生成器的损失: 4.502, 判别器的损失: 0.229
Epoch 2, 第 9 步, 生成器的损失: 4.549, 判别器的损失: 0.211
Epoch 2, 第 10 步, 生成器的损失: 4.481, 判别器的损失: 0.263
Epoch 2, 第 11 步, 生成器的损失: 3.766, 判别器的损失: 0.423
Epoch 2, 第 12 步, 生成器的损失: 2.195, 判别器的损失: 0.562
Epoch 2, 第 13 步, 生成器的损失: 1.682, 判别器的损失: 2.144
Epoch 2, 第 14 步, 生成器的损失: 0.911, 判别器的损失: 0.543
Epoch 2, 第 15 步, 生成器的损失: 0.301, 判别器的损失: 0.342
Epoch 2, 第 16 步, 生成器的损失: 0.159, 判别器的损失: 0.429
Epoch 2, 第 17 步, 生成器的损失: 0.208, 判别器的损失: 0.392
Epoch 2, 第 18 步, 生成器的损失: 0.241, 判别器的损失: 0.390
Epoch 2, 第 19 步, 生成器的损失: 0.826, 判别器的损失: 0.224
Epoch 2, 第 20 步, 生成器的损失: 1.065, 判别器的损失: 0.204
Epoch 2, 第 21 步, 生成器的损失: 0.824, 判别器的损失: 0.226
Epoch 2, 第 22 步, 生成器的损失: 4.178, 判别器的损失: 0.579
WARNING:tensorflow:This model was compiled with a Keras optimizer (<tensorflow.python.keras.optimizers.Adam object at 0x0000019D240A8BA8>) but is being saved in TensorFlow format with `save_weights`. The model's weights will be saved, but unlike with TensorFlow optimizers in the TensorFlow format the optimizer's state will not be saved. Consider using a TensorFlow optimizer from `tf.train`.
Epoch 3, 第 0 步, 生成器的损失: 0.122, 判别器的损失: 0.613
Epoch 3, 第 1 步, 生成器的损失: 1.310, 判别器的损失: 0.799
Epoch 3, 第 2 步, 生成器的损失: 1.949, 判别器的损失: 0.168
Epoch 3, 第 3 步, 生成器的损失: 1.606, 判别器的损失: 0.167
Epoch 3, 第 4 步, 生成器的损失: 1.433, 判别器的损失: 0.281
Epoch 3, 第 5 步, 生成器的损失: 1.427, 判别器的损失: 0.323
Epoch 3, 第 6 步, 生成器的损失: 2.604, 判别器的损失: 0.292
Epoch 3, 第 7 步, 生成器的损失: 2.925, 判别器的损失: 0.377
Epoch 3, 第 8 步, 生成器的损失: 4.519, 判别器的损失: 0.292
Epoch 3, 第 9 步, 生成器的损失: 4.978, 判别器的损失: 0.415
Epoch 3, 第 10 步, 生成器的损失: 5.062, 判别器的损失: 0.506
Epoch 3, 第 11 步, 生成器的损失: 2.873, 判别器的损失: 0.648
Epoch 3, 第 12 步, 生成器的损失: 3.078, 判别器的损失: 0.610
Epoch 3, 第 13 步, 生成器的损失: 2.059, 判别器的损失: 0.783
Epoch 3, 第 14 步, 生成器的损失: 0.750, 判别器的损失: 1.088
Epoch 3, 第 15 步, 生成器的损失: 1.064, 判别器的损失: 0.898
Epoch 3, 第 16 步, 生成器的损失: 0.329, 判别器的损失: 0.714
Epoch 3, 第 17 步, 生成器的损失: 0.133, 判别器的损失: 0.446
Epoch 3, 第 18 步, 生成器的损失: 0.401, 判别器的损失: 0.476
Epoch 3, 第 19 步, 生成器的损失: 0.419, 判别器的损失: 0.374
Epoch 3, 第 20 步, 生成器的损失: 0.960, 判别器的损失: 0.225
Epoch 3, 第 21 步, 生成器的损失: 1.431, 判别器的损失: 0.203
Epoch 3, 第 22 步, 生成器的损失: 1.061, 判别器的损失: 0.717
WARNING:tensorflow:This model was compiled with a Keras optimizer (<tensorflow.python.keras.optimizers.Adam object at 0x0000019D240A8BA8>) but is being saved in TensorFlow format with `save_weights`. The model's weights will be saved, but unlike with TensorFlow optimizers in the TensorFlow format the optimizer's state will not be saved. Consider using a TensorFlow optimizer from `tf.train`.
Epoch 4, 第 0 步, 生成器的损失: 2.778, 判别器的损失: 0.743
Epoch 4, 第 1 步, 生成器的损失: 0.179, 判别器的损失: 0.724
Epoch 4, 第 2 步, 生成器的损失: 2.880, 判别器的损失: 0.836
Epoch 4, 第 3 步, 生成器的损失: 2.585, 判别器的损失: 0.290
Epoch 4, 第 4 步, 生成器的损失: 2.781, 判别器的损失: 0.339
Epoch 4, 第 5 步, 生成器的损失: 2.925, 判别器的损失: 0.517
Epoch 4, 第 6 步, 生成器的损失: 5.254, 判别器的损失: 0.537

 

 附注2:这是train了一个epoch的generate_weight.ht拿来给generate.py生成花朵用的,效果如下:

用34 epoch的generate_weight.ht试试,效果如下:

如果你epoch到200以上,那么就可以看到如下的效果:

通过DCGAN进行生成花朵的更多相关文章

  1. 卷积生成对抗网络(DCGAN)---生成手写数字

    深度卷积生成对抗网络(DCGAN) ---- 生成 MNIST 手写图片 1.基本原理 生成对抗网络(GAN)由2个重要的部分构成: 生成器(Generator):通过机器生成数据(大部分情况下是图像 ...

  2. DCGAN生成目标训练图片

    前言: GAN的原理很简单,但是它有很多变体,如:DCGAN.CycleGAN.DeblurGAN等,它们也被用在不同地方,本文将用到DCGAN来生成头像图片,可以做到以假乱真的地步. 1.首先调用程 ...

  3. 第九讲_图像生成 Image Captioning

    第九讲_图像生成 Image Captioning 生成式对抗网络 Generative Adversarial network 学习数据分布:概率密度函数估计+数据样本生成 生成式模型是共生关系,判 ...

  4. 【神经网络与深度学习】生成式对抗网络GAN研究进展(五)——Deep Convolutional Generative Adversarial Nerworks,DCGAN

    [前言]      本文首先介绍生成式模型,然后着重梳理生成式模型(Generative Models)中生成对抗网络(Generative Adversarial Network)的研究与发展.作者 ...

  5. 深度学习算法 之DCGAN(写得不系统,后期再总结,大家可简单阅览一下)

    目录 1.基本介绍 2.模型 3.优缺点/其他 参考 1.基本介绍 DCGAN是生成对抗网络GAN中一种常见的模型结构.其中的生成器和判别器都是神经网络模型. GAN是一种生成式对抗网络,即通过对抗的 ...

  6. CNCC2017中的深度学习与跨媒体智能

    CNCC2017中的深度学习与跨媒体智能 转载请注明作者:梦里茶 目录 机器学习与跨媒体智能 传统方法与深度学习 图像分割 小数据集下的深度学习 语音前沿技术 生成模型 基于贝叶斯的视觉信息编解码 珠 ...

  7. 深度学习----现今主流GAN原理总结及对比

    原文地址:https://blog.csdn.net/Sakura55/article/details/81514828 1.GAN 先来看看公式:             GAN网络主要由两个网络构 ...

  8. Oracle 11g数据库详解(2)

    FAILED_LOGIN_ATTEMPTS 用于指定连续登陆失败的最大次数 达到最大次数后,用户会被锁定,登陆时提示ORA-28000 UNLIMITED为不限制 精确无误差 是 实时 PASSWOR ...

  9. Tensorflow:DCGAN生成手写数字

    参考地址:https://blog.csdn.net/miracle_ma/article/details/78305991 使用DCGAN(deep convolutional GAN):深度卷积G ...

随机推荐

  1. uva 11992

    题意: 给定一个r*c(r<=20,r*c<=1e6)的矩阵,其元素都是0,现在对其子矩阵进行操作. 1 x1 y1 x2 y2 val 表示将(x1,y1,x2,y2)(x1<=x ...

  2. uva 1232

    题意: 建筑物在多长的部分是最高的成为该建筑物的覆盖度.求所有建筑物的覆盖度之和. 链接: https://vjudge.net/contest/202699#problem/E 题解: 这道题还是挺 ...

  3. Newtonsoft.Json 高级用法

    基本用法 Json.NET是支持序列化和反序列化DataTable,DataSet,Entity Framework和Entity的.下面分别举例说明序列化和反序列化. DataTable: //序列 ...

  4. 【AtCoder】AGC031

    A - Colorful Subsequence 答案是 \(\prod_{c = 'a'}^{'z'} (cnt[c] + 1)\) #include <bits/stdc++.h> # ...

  5. 一起学Hadoop——TotalOrderPartitioner类实现全局排序

    Hadoop排序,从大的范围来说有两种排序,一种是按照key排序,一种是按照value排序.如果按照value排序,只需在map函数中将key和value对调,然后在reduce函数中在对调回去.从小 ...

  6. Bash远程代码执行漏洞(CVE-2014-6271)案例分析

    Web服务器和CGI的关系 什么是WEB服务器(IIS.Nginx.Apache) WEB服务器也称为WWW(WORLD WIDE WEB)服务器,主要功能是提供网上信息浏览服务.(1)应用层使用HT ...

  7. Centos创建定时任务和开机启动运行脚本

    aaarticlea/png;base64,iVBORw0KGgoAAAANSUhEUgAAArYAAADlCAIAAAAp5CPLAAAgAElEQVR4nNS8d3cj15nuW/wq91vc8d ...

  8. day 35 协程与gil概念

    博客链接: http://www.cnblogs.com/linhaifeng/articles/7429894.html 今日概要: 1 生产者消费者模型(补充) 2 GIL(进程与线程的应用场景) ...

  9. 了解一下vue源码中vue 的由来

     我们之前提到过 Vue.js 构建过程,在 web 应用下,我们来分析 Runtime + Compiler 构建出来的 Vue.js,它的入口是 src/platforms/web/entry-r ...

  10. javascript 作用域详解

    作用域理解:定义的变量.函数生效的范围.javascript 有全局作用域和函数作用域两种.注:es6实现let 块级作用域不是js原生的,底层同样是通过var实现的.如果想了解具体细节,请访问bab ...