JavaScript主要作用是什么?

thbcm阅读(180)

学习编程的同学对 JavaScript 并不陌生,JavaScript 是前端技术中非常重要的内容。例如页面的效果切换、动画效果、页面游戏等等。其实我们通过 HTML CSS 技术已经可以搭建各种样式的页面,但是向你要实现页面真正的动态效果,还需要使用 JavaScript 技术。下面小编就为大家详细介绍一下 JavaScript主要作用是什么。

百科定义 JavaScript 是一种直译式的脚本语言、是一种动态类型、弱类型、基于原型的语言,内置支持类型。虽然 JavaScript 使用了 Java 这个名称,但实际上 JavaScript 与 Java 之间并没有任何关系。

JavaScript 主要作用是什么呢?

上文已经提到 JavaScript 可以实现页面的效果切换、动画效果、页面游戏等效果。然而 JavaScript 承担了更多的责任。尤其是当 Ajax 技术兴起之后,网站的用户体验又得到了更大的提升。例如,当人们在百度的搜索框中输入几个字以后,网页会智能感知用户接下来要搜索的内容,出现一个下拉菜单,这个效果的实现离不开 JavaScript。另外,JavaScript 的用途已经不仅局限于浏览器了,Node.js 的出现使得开发人员能够在服务器端编写 JavaScript 代码,使得 JavaScript 的应用更加广泛。

JavaScript日常用途

1、嵌入动态文本与 HTML 页面  
2、对浏览器时间做出相应  
3、读写 HTML 元素  
4、在数据被提交到服务器之前验证数据  
5、检测访客的浏览器信息  
6、控制 cookies,包括创建和修改等。  
7、基于 node.js 技术进行服务器端编程。

目前已经有很多大型的互联网企业单独设立 JavaScript 技术开发岗位。尤其在大前端技术不断的发展的背景下,前端开发工程师从最开始简单的页面开发到现在前后端融合开发、跨平台开发等领域尽显峥嵘。作为一个非常有潜力的技术方向, JavaScript 必定会在未来互联网领域占据更重要的地位。学习前端技术仅仅靠自学是无法适应现在企业真实用人需求的。

推荐JavaScript好课:JavaScript微课JavaScript基础实战

Java后端程序员都做些什么?

thbcm阅读(173)

我刚开始做 Web 开发的时候,根本没有前端,后端之说。

原因很简单,那个时候服务器端的代码就是一切:接受浏览器的请求,实现业务逻辑,访问数据库,用 JSP 生成 HTML,然后发送给浏览器。

即使后来 Javascript 在浏览器中添加了一些 AJAX 的效果,那也是锦上添花,绝对不敢造次。因为页面的 HTML 主要还是用所谓“套模板”的方式生成:美工生成 HTML 模板,程序员用 JSP,Veloctiy,FreeMaker 等技术把动态的内容添加上去,仅此而已。

那个时候最流行的图是这个样子:

在最初的 J2EE 体系中,这个表示层可不仅仅是浏览器中运行的页面,还包括 Java 写的桌面端,只是 Java 在桌面端太不争气, 没有发展起来。

每个程序员都是所谓“全栈”工程师,不仅要搞定 HTML, JavaScript, CSS,还要实现业务逻辑,编写访问数据库的代码。等到部署的时候,就把所有的代码打成一个 WAR 包,往 Tomcat 指定的目录一扔,测试一下没问题,收工回家!

不差钱的公司会把程序部署到 Weblogic,Websphere 这样的应用服务器中,还会用上高大上的 EJB。

虽然看起来生活“简单”又“惬意”,但实际上也需要实现那些多变的、不讲逻辑的业务需求,苦逼的本质并没有改变。

1. 前后端的分离

随着大家对浏览器页面的视觉和交互要求越来越高,“套模板”的方式渐渐无法满足要求,这个所谓的表示层慢慢地迁移到浏览器当中去了,一大批像 Angular, ReactJS 之类的框架崛起,前后端分离了!

后端的工程师只负责提供接口和数据,专注于业务逻辑的实现,前端取到数据后在浏览器中展示,各司其职。

像 Java 这样的语言很适合去实现复杂的业务逻辑,尤其是一些 MIS 系统,行业软件如税务、电力、烟草、金融,通信等等。  所以剥离表示层,只做后端挺合适的。 

但是如果仅仅是实现业务逻辑,那后端也不会需要这么多技术了,搞定 SSH/SSM 就行了。 

2. 后端技术

互联网,尤其是移动互联网开始兴起以后,海量的用户呼啸而来,一个单机部署的小小 War 包肯定是撑不住了,必须得做分布式。 

原来的单个 Tomcat 得变成 Tomcat 的集群,前边弄个 Web 服务器做请求的负载均衡,不仅如此,还得考虑状态问题,session 的一致性。

业务越来越复杂,我们不得不把某些业务放到一个机器(或集群)上,把另外一部分业务放到另外一个机器(或集群)上,虽然系统的计算能力,处理能力大大增强,但是这些系统之间的通信就变成了头疼的问题,消息队列(MQ),RPC框架(如Dubbo)应运而生,为了提高通信效率,各种序列化的工具(如Protobuf)也争先空后地问世。

单个数据库也撑不住了,那就做数据库的读写分离,如果还不行,就做分库和分表,把原有的数据库垂直地切一切,或者水平地切一切, 但不管怎么切,都会让应用程序的访问非常麻烦,因为数据要跨库做 Join/ 排序,还需要事务,为了解决这个问题,又有各种各样“数据访问中间件”的工具和产品诞生。

为了最大程度地提高性能,缓存肯定少不了,可以在本机做缓存(如Ehcache),也可以做分布式缓存(如Redis),如何搞数据分片,数据迁移,失效转移,这又是一个超级大的主题了。

互联网用户喜欢上传图片和文件,还得搞一个分布式的文件系统(如FastDFS),要求高可用,高可靠。

数据量大了,搜索的需求就自然而然地浮出水面,你得弄一个支持全文索引的搜索引擎(如Elasticsearch ,Solr)出来。

林子大了,什么鸟都有,必须得考虑安全,数据的加密/解密,签名、证书,防止 SQL 注入,XSS/CSRF 等各种攻击。

3. “大后端”

前面提到了这么多的系统,还都是分布式的,每次上线,运维的同学说:把这么多系统协调好,把老子都累死了。

得把持续集成做好,能自动化地部署,自动化测试(其实前端也是如此),后来出现了一个革命化的技术 docker, 能够让开发、测试、生成环境保持一致,系统原来只是在环境(如Ngnix, JVM,Tomcat,MySQL等)上部署代码,现在把代码和环境一并打包, 运维的工作一下子就简化了。

公司自己购买服务器比较贵,维护也很麻烦,又难于弹性地增长,那就搞点虚拟的服务器吧,硬盘、内存都可以动态扩展(反正是虚拟的), 访问量大的时候多用点,没啥访问量了就释放一点,按需分配,很方便,这就是云计算的一个场景。

随着时间的推移,各个公司和系统收集的数据越来越多,都堆成一座大山了,难道就放在那里白白地浪费硬盘空间吗?

有人就惊奇地发现,咦,我们利用这些数据搞点事情啊, 比如把数据好好分析一下,预测一下这个用户的购买/阅读/浏览习惯,给他推荐一点东西嘛。

可是这么多数据,用传统的方式计算好几天甚至好几个月才能出个结果,到时候黄花菜都凉了,所以也得利用分布式的技术,想办法把计算分到各个计算机去,然后再把计算结果收回来, 时势造英雄,Hadoop 及其生态系统就应运而生了。

之前听说过一个大前端的概念,把移动端和网页端都归结为“前端”,我这里造个词“大后端”,把那些用户直接接触不到的、发生在服务器端的都归结进来。

4. 怎么学?

现在无论是前端还是后端,技术领域多如牛毛,都严重地细分了,所以我认为真正的全栈工程师根本不存在,因为一个人精力有限,不可能搞定这么多技术领域,太难了。

培训机构所说的“全栈”,我认为就是前后端还在拉拉扯扯,藕断丝连,没有彻底分离的时候的“全栈”工程师。

那么问题来了, 后端这么多东西,我该怎么学?

往深度挖掘,可以成为某个技术领域的专家,如搜索方面的专家、安全方面的专家,分布式文件的专家等等,不管是哪个领域,重点都不是学会使用某个工具和框架, 而是保证你可以自己的知识和技术去搞定这个领域的顶尖问题。

往广度发展,各个技术领域都要了解,对于某种需求,能够选取合适的软件和技术架构来实现它,把需求转化成合适的技术组件,让这些组件以合适的方式连接、部署、运行,这也需要持续地学习和不断的经验积累。

JAVA可以从事哪些岗位?

thbcm阅读(166)

Java 已成为当今市面上很受欢迎的编程软件,对于处于信息高速发达的今天,Java 技术已经无处不在,手机软件、手机 Java 游戏、电脑软件等等都有它的身影。

那么 Java 到底能做什么事情呢?市场上什么工作岗位跟 Java 有关?

 

大家一起看看:

1. Java可以做网站

Java 可以用来编写网站,现在很多大型网站都用 Jsp 写的,JSP 全名 Java Server Pages

它是一种动态网页技术,比如我们熟悉的163,一些政府网站都是采用 JSP 编写的。

所以学习 Java 的同学可以找开发网站方面的工作,而且现在找这方面的岗位比较多。

比如:网站开发,当然就是 JSP+Servlet+JavaBean,一直以来都相当流行。

2. Java可以做Android

Android 是一种基于 Linux 的自由及开放源代码的操作系统,其源代码是 Java。

所以市场上见到的手机系统例如 MIUI ,阿里云,乐蛙等,都是修改源代码再发行的。

Java 做安卓不单单是指系统,还有 APP 对于更多的开发人员来说,他们更多的时间是花在开发APP上面。

3. Java可以做游戏

或者你不知道,在以前诺基亚还很流行的时候,你玩的手机游戏有90%以上都是 Java 开发的。

当然现在已经很少人再去开发了,都转到安卓上去了。

电脑上也有 java 开发的游戏,最经典的是:《我的世界》(minecraft ,简称MC),当今世界最具人气和影响力的网络游戏之一《英雄联盟》(简称lol)。

4. Java可以做软件

一般编程语言都可以做软件的,Java 也不例外,例如 Eclipse,MyEclipse 等知名 Java 开发工具.有关开发软件组件,可以了解 Java Swing 编程 或者 awt 相关知识。

比如:企业级应用开发,这里是 JAVA 的天地,大到全国联网的系统,小到中小企业的应用解决方案,Java 都占有极为重要的地位。

另外还有移动领域,典型的应用是手机游戏(国内主要是这方面),这里是 J2ME 的天地,其实应用范围是很广的。

Java 已成为当今市面上很受欢迎的编程软件,对于处于信息高速发达的今天,Java 技术已经无处不在,手机软件、手机 JAVA 游戏、电脑软件等等。

 

可以这样说,只要你使用手机、电脑等电子产品,你就会用到跟 Java 有关的东西。由此可见,对于我们这些将要面临巨大就业压力的在校大学生来说,掌握这样一款最流行的编程语言是多么重要。

 

不管你以后是从事硬件还是软件的开发,面试官的第一个问题就是“你会不会使用 JAVA 语言编程?”

 

同样,如果掌握了 Java 这门技术,就业面也是很广的,不管是电脑方面的软硬件开发还是手机的软硬件开发 Java 都是必不可少的技术,只要是想从事 IT 方面的工作,必须掌握 Java。

 

除了这些 Java 还有很多用途,家里的洗衣机、微波炉等家电有可能是 java 控制的,这是单片机的知识。找到自己喜欢的一个方向,专攻一个领域,才会做出成绩。

推荐好课:java微课java面试 基础题

用Python分析了5万条相亲网站数据,看相亲男女画像

thbcm阅读(182)

作者:叶庭云

来源:公众号 修炼Python

这短短的一生,我们最终都会失去。你不妨大胆一些,爱一个人,攀一座山,追一个梦。

一、前言

数据来源:www.zhenai.com/zhenghun/ 本文利用 Python 分析了按城市寻找所有地区的征婚信息,看看相亲男女的画像。

二、数据查看和预处理

导入用到的库

import pandas as pd
import re

读取数据,查看前 5 行

df = pd.read_excel('marriage.xlsx')
df.head()

结果如下:

查看索引、数据类型和内存信息

df.info()

可以看到数据都没有缺失值。

获取到的数据里,居住地是各地区的,为了便于分析,需要处理成省级行政区,学历/月薪那一列数据,有些是月薪,有些是学历,可以分别处理成两列数据,是学历的,提取出学历层次,月薪标记为 “未知”;是月薪的,提取出月薪并计算,学历标记为 “未知”。

# 获取34个省级行政区域,包括23个省,5个自治区,4个直辖市,2个特别行政区的名称
with open('地区.txt', 'r', encoding='utf-8') as f:
    area = f.read().split('\\n')


print(area)
print(len(area))

结果如下:

['北京', '上海', '天津', '重庆', '黑龙江', '吉林', '辽宁', '内蒙古', '河北', '新疆', '甘肃', '青海', '陕西', '宁夏', '河南', '山东', '山西', '安徽', '湖北', '湖南', '江苏', '四川', '贵州', '云南', '广西', '西藏', '浙江', '江西', '广东', '福建', '台湾', '海南', '香港', '澳门']
34
areas_list = []
for i in df['居住地']:
    for j in area:
        if j in i:
            areas_list.append(j)
            break
    else:
        areas_list.append('未知')


df['居住地'] = areas_list
df.head()

结果如下:

with open('学历.txt', 'r', encoding='utf-8') as fp:
    edu = fp.read().split('\\n')


print(edu)

结果如下:

['博士', '硕士', '本科', '大专', '中专', '高中', '初中', '小学']
salary_list = []
edu_list = []
for item in df['学历/月薪']:
    if '元' in item:   # 这一列的数据是表达月薪的话  计算
        data = re.findall('\\d+', item)
        data = [int(x) for x in data]
        salary = int(sum(data) / len(data))  # 取整
        salary_list.append(salary)
        edu_list.append('未知')
    else:
        salary_list.append('未知')
        for e in edu:
            if e in item:
                edu_list.append(e)
                break
        else:
            edu_list.append('未知')


print(len(edu_list))
print(len(salary_list))
df['学历'] = edu_list
df['月薪'] = salary_list
df.head()      

结果如下:

这时候数据处理好了,可以删掉学历/月薪这一列,再重新保存到 Excel blank

del df['学历/月薪']
df

df.to_excel('处理后数据.xlsx', index=False)

三、数据分析

相亲男女性别占比?

# -*- coding: UTF-8 -*-
"""
@File    :男女占比情况.py
@Author  :叶庭云
@CSDN    :https://yetingyun.blog.csdn.net/
"""
import pandas as pd
import collections
from pyecharts.charts import Pie
from pyecharts import options as opts
from pyecharts.globals import ThemeType, CurrentConfig


# 引用本地js资源渲染
CurrentConfig.ONLINE_HOST = 'D:/python/pyecharts-assets-master/assets/'
# 提取数据
df = pd.read_excel('处理后数据.xlsx')
gender = list(df['性别'])
# 统计男女人数
gender_count = collections.Counter(gender).most_common()
gender_count = [(k, v) for k, v in gender_count]


pie = Pie(init_opts=opts.InitOpts(theme=ThemeType.MACARONS))
# 富文本效果  环图
pie.add('性别', data_pair=gender_count, radius=["40%", "55%"],
        label_opts=opts.LabelOpts(
            position="outside",
            formatter="{a|{a}}{abg|}\\n{hr|}\\n {b|{b}: }{c}  {per|{d}%}  ",
            background_color="#eee",
            border_color="#aaa",
            border_width=1,
            border_radius=4,
            rich={
                "a": {"color": "#999", "lineHeight": 22, "align": "center"},
                "abg": {
                    "backgroundColor": "#e3e3e3",
                    "width": "100%",
                    "align": "right",
                    "height": 22,
                    "borderRadius": [4, 4, 0, 0],
                },
                "hr": {
                    "borderColor": "#aaa",
                    "width": "100%",
                    "borderWidth": 0.5,
                    "height": 0,
                },
                "b": {"fontSize": 16, "lineHeight": 33},
                "per": {
                    "color": "#eee",
                    "backgroundColor": "#334455",
                    "padding": [2, 4],
                    "borderRadius": 2,
                },
            },
        ),)
pie.set_global_opts(title_opts=opts.TitleOpts(title='相亲男女占比情况'))
pie.set_colors(['red', 'blue'])   # 设置颜色
pie.render('男女占比情况.html')

结果如下:

相亲男女中女士多于男士。男士有 25910 人,占比 45.72%;女士有 30767 人,占比 54.28%。

相亲男女年龄分布?

# -*- coding: UTF-8 -*-
"""
@File    :年龄分布.py
@Author  :叶庭云
@CSDN    :https://yetingyun.blog.csdn.net/
"""
import pandas as pd
import collections
from pyecharts.charts import Bar
from pyecharts.globals import ThemeType, CurrentConfig
from pyecharts import options as opts


CurrentConfig.ONLINE_HOST = 'D:/python/pyecharts-assets-master/assets/'


df = pd.read_excel('处理后数据.xlsx')
age = list(df['年龄'])
age_count = collections.Counter(age).most_common()
# 按年龄排序
age_count.sort(key=lambda x: x[0])
age = [x[0] for x in age_count]
nums = [y[1] for y in age_count]


# print(age_count)
bar = Bar(init_opts=opts.InitOpts(theme=ThemeType.MACARONS))
bar.add_xaxis(age)
bar.add_yaxis('人数', nums)  # 数据多的时候设置不显示标签
bar.set_global_opts(title_opts=opts.TitleOpts(title='相亲男女年龄分布'))
# 标记最大值  最小值  平均值   标记平均线
bar.set_series_opts(label_opts=opts.LabelOpts(is_show=False),
                    markpoint_opts=opts.MarkPointOpts(
                    data=[
                        opts.MarkPointItem(type_="max", name="最大值"),
                        opts.MarkPointItem(type_="min", name="最小值"),
                        opts.MarkPointItem(type_="average", name="平均值")]),
                    markline_opts=opts.MarkLineOpts(
                    data=[
                        opts.MarkLineItem(type_="average", name="平均值")]))
bar.render('年龄分布.html')

结果如下:

31岁的相亲男女人数最多,有 2637 人,各个年龄段都有一定数量的相亲男女,我们可以将年龄小于等于 20 岁,大于等于 70 岁的相亲男女数据单独提取出来看看。

import pandas as pd


df = pd.read_excel('处理后数据.xlsx')
df1 = df[df['年龄'] <= 20]
df2 = df1['婚况'].value_counts()    # 统计小于等于20岁的相亲男女的婚况
print(df2)

结果如下:

未婚    153
离异      6
丧偶      2
Name: 婚况, dtype: int64

大部分是未婚,年纪轻轻就那么急着相亲吗,再看看婚况是离异的数据。

import pandas as pd


df = pd.read_excel('处理后数据.xlsx')
df1 = df[df['年龄'] <= 20]


df3 = df1[df1['婚况'] == '离异']
print(df3)

结果如下:

                网名  性别  ...  学历     月薪
17425          微风轻起  男士  ...  未知  50000
29645            媳妇  女士  ...  大专     未知
30398            仙妹  女士  ...  高中     未知
30485  会员1415395937  男士  ...  未知  35000
36684         微笑着变老  女士  ...  高中     未知
49864        风吹动了风玲  女士  ...  高中     未知


[6 rows x 9 columns]

月薪写着 50000、35000 的男士有些显眼啊,在数据集中查看。

月薪 50000 的微风轻起,征婚信息年龄写的19,征婚宣言里又写到 1994 年 26 岁;月薪 35000 的会员某某某,征婚信息年龄写的 20,征婚宣言里又写到 81 年的,看来网站里年龄、身高这些信息真实性值得怀疑。

相亲男女婚况?

# -*- coding: UTF-8 -*-
"""
@File    :男女占比情况.py
@Author  :叶庭云
@CSDN    :https://yetingyun.blog.csdn.net/
"""
import pandas as pd
import collections
from pyecharts.charts import Pie
from pyecharts import options as opts
from pyecharts.globals import ThemeType, CurrentConfig


# 引用本地js资源渲染
CurrentConfig.ONLINE_HOST = 'D:/python/pyecharts-assets-master/assets/'
# 提取数据  婚况不为未填写的
df = pd.read_excel('处理后数据.xlsx')
data = df[df['婚况'] != '未填写']
# 统计各婚况相亲男女人数
data_count = collections.Counter(data['婚况']).most_common()
print(data)


c = (
    Pie()
    .add(
        "婚况",
        data_count,
        radius=["40%", "55%"],
        label_opts=opts.LabelOpts(
            position="outside",
            formatter="{a|{a}}{abg|}\\n{hr|}\\n {b|{b}: }{c}  {per|{d}%}  ",
            background_color="#eee",
            border_color="#aaa",
            border_width=1,
            border_radius=4,
            rich={
                "a": {"color": "#999", "lineHeight": 22, "align": "center"},
                "abg": {
                    "backgroundColor": "#e3e3e3",
                    "width": "100%",
                    "align": "right",
                    "height": 22,
                    "borderRadius": [4, 4, 0, 0],
                },
                "hr": {
                    "borderColor": "#aaa",
                    "width": "100%",
                    "borderWidth": 0.5,
                    "height": 0,
                },
                "b": {"fontSize": 16, "lineHeight": 33},
                "per": {
                    "color": "#eee",
                    "backgroundColor": "#334455",
                    "padding": [2, 4],
                    "borderRadius": 2,
                },
            },
        ),
    )
    .set_colors(["#8B008B", "#FF1493", "#000000"])
    .set_global_opts(title_opts=opts.TitleOpts(title="相亲男女婚况"))
    .render("pie_rich_label.html")
)

结果如下:

相亲男女婚况。离异的占比57.67%,所占比例最大,未婚占比34.14%,丧偶占比8.19%。

相亲男女学历分布情况?

# -*- coding: UTF-8 -*-
"""
@File    :学历分布.py
@Author  :叶庭云
@CSDN    :https://yetingyun.blog.csdn.net/
"""
import pandas as pd
import collections
from pyecharts.charts import Pie
from pyecharts import options as opts
from pyecharts.globals import CurrentConfig


# 引用本地js资源渲染
CurrentConfig.ONLINE_HOST = 'D:/python/pyecharts-assets-master/assets/'
# 提取数据  学历不为未知的
df = pd.read_excel('处理后数据.xlsx')
data = df[df['学历'] != '未知']
# print(data)
# 统计各学历层次相亲男女数量
data_count = collections.Counter(data['学历']).most_common()
c = (
    # 宽  高  背景颜色
    Pie(init_opts=opts.InitOpts(width="800px", height="500px", bg_color="#2c343c"))
    .add(
        series_name="相亲男女学历",   # 系列名称
        data_pair=data_count,         # 系列数据项,格式为 [(key1, value1), (key2, value2)...]
        rosetype="radius",        # radius:扇区圆心角展现数据的百分比,半径展现数据的大小
        radius="55%",             # 饼图的半径
        center=["50%", "50%"],    # 饼图的中心(圆心)坐标,数组的第一项是横坐标,第二项是纵坐标
        label_opts=opts.LabelOpts(is_show=False, position="center"),   # 标签配置项
    )
    .set_colors(["#00BFFF", "#00FF7F", "#FF1493", "#8B008B", "#FFFF00", "#556B2F"])
    .set_global_opts(
        title_opts=opts.TitleOpts(
            title="相亲男女学历",
            pos_left="center",
            pos_top="20",
            title_textstyle_opts=opts.TextStyleOpts(color="#fff"),
        ),
        legend_opts=opts.LegendOpts(is_show=False),
    )
    .set_series_opts(
        tooltip_opts=opts.TooltipOpts(
            trigger="item", formatter="{a} <br/>{b}: {c} ({d}%)"  # 'item': 数据项图形触发,主要在散点图,饼图等无类目轴的图表中使用
         ),
        label_opts=opts.LabelOpts(color="#fff"),
    )
    .render("相亲男女学历.html")
)

结果如下:

相亲男女学历大部分在高中(35.92%)、大专(24.72%),有近六成的相亲男女。本科占比20.7%,中专占比16.35%,硕士、博士高学历的相亲男女人数很少,分别占比2.14%,0.17%

相亲男女地区分布?

# -*- coding: UTF-8 -*-
"""
@File    :地区分布.py
@Author  :叶庭云
@CSDN    :https://yetingyun.blog.csdn.net/
"""
import pandas as pd
import collections
from pyecharts import options as opts
from pyecharts.charts import Geo
from pyecharts.globals import ChartType
from pyecharts.globals import ThemeType, CurrentConfig


CurrentConfig.ONLINE_HOST = 'D:/python/pyecharts-assets-master/assets/'


df = pd.read_excel('处理后数据.xlsx')
area = list(df['居住地'])
area_count = collections.Counter(area).most_common(34)
print(area_count)


# 初始化配置项  背景颜色  大小  主题
geo = Geo(init_opts=opts.InitOpts(width='1000px', height='600px', theme=ThemeType.DARK))
# 设置是否显示省份
geo.add_schema(maptype='china', label_opts=opts.LabelOpts(is_show=True))
# 绘制什么类型图  热力图  涟漪图等
geo.add('相亲男女人数', data_pair=area_count, type_=ChartType.EFFECT_SCATTER)
geo.set_series_opts(label_opts=opts.LabelOpts(is_show=False))   # 不显示数据标签
geo.set_global_opts(title_opts=opts.TitleOpts(title="相亲男女地区分布"),
                 visualmap_opts=opts.VisualMapOpts(max_=5000, is_piecewise=True,   # 划分区间是否精确
     pieces=[{"max": 1000, "min": 100, "label": "100-1000", "color": "#708090"},  # 分段  添加图例注释  和颜色
                            {"max": 1500, "min": 1001, "label": "1001-1500", "color": "#00008B"},
                            {"max": 2000, "min": 1501, "label": "1501-2000", "color": "#483D8B"},
                            {"max": 2500, "min": 2001, "label": "2001-2500", "color": "#1E90FF"},
                            {"max": 3000, "min": 2501, "label": "2501-3000", "color": "#8B008B"},
                            {"max": 5000, "min": 3001, "label": ">=3000", "color": "#FF0000"}])
                    )
geo.render('地区分布.html')

结果如下:

[('重庆', 4436), ('广东', 2637), ('四川', 2519), ('山东', 2398), ('河南', 2160), ('上海', 2156), ('云南', 2039), ('北京', 2037), ('台湾', 1997), ('安徽', 1920), ('江苏', 1919), ('天津', 1918), ('黑龙江', 1918), ('湖南', 1800), ('新疆', 1799), ('辽宁', 1680), ('甘肃', 1680), ('广西', 1679), ('湖北', 1679), ('内蒙古', 1559), ('山西', 1440), ('福建', 1440), ('江西', 1440), ('浙江', 1440), ('陕西', 1439), ('河北', 1439), ('青海', 1339), ('贵州', 1200), ('吉林', 1080), ('西藏', 942), ('宁夏', 702), ('海南', 360), ('香港', 353), ('澳门', 117)]

重庆、广东、四川等地区的相亲男女人数最多。

征婚宣言一般是介绍自己情况,表达对另一半的要求和期望。下面我们分别来看看相亲男女征婚宣言里关键词都有些什么。

# -*- coding: UTF-8 -*-
"""
@File    :征婚宣言词云.py
@Author  :叶庭云
@CSDN    :https://yetingyun.blog.csdn.net/
"""
import pandas as pd
import jieba
import collections
import re
from wordcloud import WordCloud
import matplotlib.pyplot as plt
import numpy as np
from PIL import Image


# 提取性别  征婚宣言这两列数据就好
df = pd.read_excel('处理后数据.xlsx')[['性别', '征婚宣言']]
# df1 = df[df['性别'] == '女士']['征婚宣言']
df2 = df[df['性别'] == '女士']['征婚宣言']


# 读取停用词数据
with open('stop_words.txt', encoding='utf-8') as f:
    con = f.read().split('\\n')    # 得到每一行的停用词
    stop_words = set()
    for i in con:
        stop_words.add(i)


result_list = []
for data in df2:
    # 文本预处理  去除一些无用的字符   只提取出中文出来
    new_data = re.findall('[\\u4e00-\\u9fa5]+', data, re.S)
    new_data = "/".join(new_data)
    # 文本分词
    seg_list_exact = jieba.cut(new_data, cut_all=True)
    # 去除停用词和单个词
    for word in seg_list_exact:
        if word not in stop_words and len(word) > 1:
            result_list.append(word)


print(result_list)
# 筛选后统计
word_counts = collections.Counter(result_list)
mask_ = 255 - np.array(Image.open('woman_mask.png'))
# 绘制词云
my_cloud = WordCloud(
    background_color='white',  # 设置背景颜色  默认是black
    mask=mask_,
    font_path='simhei.ttf',   # 设置字体  显示中文
    max_font_size=112,        # 设置字体最大值
    min_font_size=12,         # 设置字体最小值
    random_state=88           # 设置随机生成状态,即多少种配色方案
).generate_from_frequencies(word_counts)


# 绘制词云
plt.figure(figsize=(8, 5), dpi=200)
# 显示生成的词云图片
plt.imshow(my_cloud, interpolation='bilinear')
# 显示设置词云图中无坐标轴
plt.axis('off')
plt.savefig('woman_cloud.png', dpi=200)
plt.show()

结果如下:

相亲男女征婚宣言里,喜欢、希望、生活、善良、真诚、真心、幸福、性格等都是出现频率高的词语。

简单介绍一下web开发中用到的一些技术

thbcm阅读(168)

一、标准通用标记语言(SGML)

1.HTML

即超文本标记语言(HyperText Markup Language),超文本指页面内可以包含图片、音乐、链接甚至程序等非文字元素,如果只用HTML 则只能做静态网页。

静态网页:指不含数据库、不含程序和不可交互的网页,适用于更新较少的展示型网页,运行于客户端,通常以 .html 或 .htm 或 .xml 或 .shtml 为后缀。无需经过服务器编译便可直接加载到客户浏览器上显示出来,占用一定的服务器空间。可在静态网页中加入 flash、 java 小程序、ActiveX 控件以及客户端脚本,这些都由程序员事先编写好放到服务器上。

动态网页:动态网页在服务器端运行,在不同时间会根据不同用户返回不同的网页,与服务器发生交互行为。以数据库为基础,可实现用户的注册、登录、用户管理等操作。动态网页并不是独立存在于服务器上的网页文件,只有在客户端发出请求后才返回一个完整的网页。后缀可以为.jsp或.php或.asp或.cgi。

ActiveX控件:在静态页面中加入可以运行在浏览器上的程序,是静态的,现在的浏览器基本以不支持。

applet:“let”词缀表示“小”,applet 表示用 Java 编写的小应用程序(JavaApplet),即静态的,该程序可以包含在 HTML 页面中,与在页面中包含图像的方式大致相同,即<applet></appltet>一对标记。当支持 Java 的浏览器遇到这对标记时,便下载相应的小程序代码在本地运行,已经淘汰,取而代之 JavaFX。

servlet:即 server applet,applet 扩充了网络浏览器的能力,而 servlet 扩充了网络服务器的能力。servlet 的功能在于交互地浏览和修改数据,生成动态 web 内容,其过程为:客户端发送请求到服务器,服务器将请求信息发送到 servlet,servlet 生成相应内容被发送到服务器,服务器将响应发送至客户端。applet 与servlet 均没有 main 函数。(比喻:JSP是服务员,servlet 是看完菜单告知哪个厨师来做饭的前台。)JSP 显示页面和接收用户的信息,而 servlet 主要负责页面和业务层的信息交互。

CGI程序:是运行在网络服务器上的一个程序,作用与 servlet 相似。但已被 servlet 替代,因为 CGI 程序每当客户端发出一个新的请求,便要建立一个新的 CGI 实例,占用了大量的内存资源,用于实际开发很困难。而 servlet 被用户发送的第一个请求激活后,继续运行于后台等待以后的请求,每个请求将生成一个新的线程而不是一个完整的进程,多个客户可以在同一个进程中同时得到服务。

css:即层叠样式表(cascading style sheets)是用于网页排版的标记性语言,能对网页中的排版进行像素级控制,主要用于对网页中的字体、颜色、图像、背景等其他元素进行控制,是对 HTML 的补充。“HTML+CSS”可以实现静态网页。

div+css:div 是 HTML 中的一个标签元素,为布局元素。div 可以理解成一个矩形框,css 控制这个矩形框在什么地方。CSS3 是 CSS 的一个标准,HTML5 是 HTML 的一个标准。

单页面:整个页面就是一个静态的不刷新的 HTML 页面,例如QQ空间中从日志到相册,整个页面并没有刷新,而是中间的主体内容进行局部替换。

图灵机:图灵机可以理解成对人们使用纸笔进行运算的抽象,分为两个步骤,在纸上写或擦出某个符号,下一步动作取决于当前所关注的符号和此时的思维逻辑。

图灵完备:即 Turing Completeness,判断图灵完备的方法就是看该语言能否模拟出图灵机。

2.XML

即可扩展标记语言(Extensible Markup Language),和 html 相比,xml 允许用户对自己的标记语言进行定义。

3.XHTML

即可扩展超文本标记语言,比 HTML 语法更严格

二、前端

1.脚本语言(scripting language)

脚本语言又被称为扩建的语言或者动态语言,通常以文本保存,只有在被调用时才进行解释或编译。

2.JavaScript(js)

是一种脚本语言, 动态类型、弱类型、基于原型的语言,内置支持类型。用于 嵌入 HTML 网页增加动态功能,向 HTML 页面提供交互功能, 亦可写成单独的 js 文件便于结构和行为的分离。最早由 Netscape 公司实现,因与 Sun 公司合作,便取名 JavaScript。微软推出了 JScript,都可以统称兼容 ECMASript。后缀名为.js的文件就是 JavaScript 文件。可用于多平台多操作系统。被大多数浏览器支持。
动态类型:运行期才做类型检查静态类型:编译期进行数据类型检查弱类型:语言运行时会隐式的做数据类型转换强类型:语言运行时确保不会做未授意的类型转换基于原型的语言:如 JavaScript,只有对象没有类,是对象继承对象,而不是类继承类。基于类型的语言:如 Java

特性(动态性):是一种采用事件驱动的脚本语言,不需要服务器的支持,便可直接响应用户的输入。在访问一个页面时,用鼠标上移下移点击都可以通过 JavaScript 对其进行响应。因此早期程序员喜欢通过 JavaScript 减轻服务器的负担,然而不安全,随着服务器的强壮,现在程序员喜欢使用在服务端的脚本来保证安全。有些特殊功能如 ajax 比如依赖 JavaScript 在客户端进行支持。现在 JavaScript 逐渐被用来编写服务器端程序。

3.VBSript(VBS)

basic 语言起初是非结构化语言,后来经过完善成为结构化语言(Visual Basic,即VB),同时VB也是开发环境。

Microsoft Visual C++(简称Visual C++、MSVC、VC++或VC)为微软公司的 C++开发工具。

VBS是微软环境下的轻量级的解释性脚本语言。

4.Ajax

即异步 JavaScript 和 XML(Asynchronous Javascript And XML),是一种能够不刷新整个网页的前提下还能更新部分网页的技术。通过后台与服务器进行少量数据交换,AJAX 可以使网页实现异步更新。

5.JSON

即 JS 对象标记(JavaScript Object Notation),是一种轻量级数据交换格式,能够代替 XML 的工作,即可以处理前端(JavaScript)和后台(web 服务器端)之间的数据交互。特点是易于人们的读写习惯,易于机器的分析和运行,形式为一个以键值对形式表示的字符串。JSON 跨语言,在移动端(Android、IOS)数据都可以由 JSON 来传输。

6.boostrap

Bootstrap,来自 Twitter,是目前最受欢迎的前端框架。Bootstrap 是基于 HTML、CSS、JavaScript的,它在jQuery的基础上进行了更为个性化和人性化的完善,形成一套自己独有的网站风格,并兼容大部分jQuery插件。

7.angular.jsJQuery

AngularJS是为了克服HTML在构建应用上的不足而设计的。AngularJS有着诸多特性,最为核心的是:MVC、模块化、自动化双向数据绑定、语义化标签、依赖注入等等。HTML是一门很好的为静态文本展示设计的声明式语言。

jQuery 使用户可以更加方便地处理 HTML(标准通用标记语言下的一个应用)、events、实现动画效果,而且方便地为网站提供AJAX交互。

8.前端编辑器

Webstorm:重量级编辑器,当前段项目配置了各种的 grunt,bower,angular 后你会发现你很需要它。Brackets:适合写 CSS。Dreamweaver:“所见即所得”HBuilder:适合写 H5,相对厚重。Sublime:相当于一个升级版的记事本,有着强大的插件,建议安装两个(packagecontrol和emmet),轻量级编辑器,小巧智能。notepad++:插件多

三、后台

1.JSP(J2EE)

即 Java 服务器页面(JAVA Server Pages),是一种动态网站开发语言,有点类似于 ASP 技术,在传统的 HTML 页面文件(后缀名为*.htm或*.html)中插入 Java 程序段(Scriptlet)和 JSP 标记(tag),从而形成 JSP 文件,后缀名*.jsp。JSP 开发的 web 应用是跨平台的,可以运行在 Linux 或者其他操作系统下。它实现了 HTML 中的 Java 扩展(以<%,%>形式),jsp 与 servlet 一样运行在服务器端,将一个 HTML 文件返回给客户端,因此客户端有浏览器就可以浏览。servlet 是 JSP 的基础,大型的 web 应用开发众需要 servlet 和 JSP 同时配合。JSP 与 servlet 的关系:JSP 是 servlet 的扩展,在 JSP 之前就有 servlet 了。有客户端, web服务器(web server)和应用服务器(application server),客户端发出请求,web 服务器接受 http 请求,如果是 HTML、css 等静态资源则 web 服务器可以自行处理 ,如果遇到动态资源比如 jsp 时便将请求转至应用服务器中,由应用服务器处理。应用服务器也具有处理http 请求的能力,可能没有 web 服务器那么专业, 应用服务器同时也包含 web 容器。在应用服务器中,jsp 转换成 servlet,在 servlet 容器中检索是否已经存在匹配的 servlet 实例,若没有则由 servlet 容器加载并实例化这个 servlet 类的一个实例对象,再有servlet 容器初始化并运行;若 servlet 容器中已存在,则直接运行。
web服务器:代表Nginx、IIS、Apache。 “相当于前台接待”。
应用服务器:代表Bea WebLogic、IBM WebSphere、JBoss、Tomcat。Tomcat是Apache的扩展可以独立于Apache运行。“相当于真正的价值服务者”。
servlet容器:管理 servlet 的生命周期,存在于应用服务器中。Tomcat 既可以看成是 servlet 容器又可以看成是 web 容器,既可以处理静态资源又可以处理动态的 servlet。 故可以使用两个独立的服务器比如 Nginx 和 WebLogic,也可以只用一个 Tomcat。

2.PHP和ruby

php:超文本预处理器(hypertext preprocessor),是一种 基于对象的开源脚本语言,用于 web 后台开发。
ruby: 面向对象的后台脚本语言。基于对象:不提供抽象、重载和继承面向对象:提供抽象、重载和继承

3.NetBeans

一款 用Java 编写的主要用于后台开发的 IDE。

4.Node.js

是一种 JavaScript 的运行环境(runtime),是目前速度最快的 JavaScript 引擎,使 JavaScript 能脱离浏览器运行。对 Chrome V8 引擎进行了封装。使用事件驱动,非阻塞 I/O 模型而得以轻量而高效。

用处:是 JavaScript 运行环境,也就是说能在服务器上跑 JavaScript 代码,让 JavaScript 实现服务器上的开发。一般是 js 程序员在用,属于后端技术。

JavaScript 引擎:是一种专门处理 JavaScript 脚本的虚拟机,一般会符带在浏览器中。

四、ASPASP.NET与.NET

ASP:类似于JSP和PHP,是一种后台开发技术。
.NET:是一个 平台,不是语言,包括运行时的环境和开发的环境。可以在 .NET 平台上用不同的语言开发,例如 C#,VB.NET,HTML,F#,VC++.NET。有点类似于 java。JAVA 语言也是 java 平台中的一个语言的名字,C# 同样是 .NET 平台中一个语言的名字, 即 java 跨平台,.NET 跨语言。java 开源,.NET 由微软开发不开源。java 编写完一次后可以再 Linux 上或其它操作系统上运行,.NET 只适用于微软,所以  java 跨平台,.NET 不跨平台。
ASP.NET(又称ASP+):是基于 .NET Framework 的 web 开发 平台。一般前端用 HTML+css,后端用 C#。.NET Framework:是 .NET 开发的软件运行所必需的框架(framework)、运行环境。

鸿蒙OS是什么?有什么特点?

thbcm阅读(207)

前言

提示: 2019年8月华为推出鸿蒙 HarmonyOS,并运用在荣耀智慧屏,HDC 2020,华为消费者业务软件部总裁王成录将在9月11日进行《共建、共享 HarmonyOS 生态》的演讲,将分享 HarmonyOS 2.0发布的新进展以及给人们、给行业带来的价值。

提示:以下是本篇文章正文内容,下面案例可供参考

一、鸿蒙OS是什么?

华为公司新近推出的经历十年多时间自主研发的鸿蒙操作系统(HarmonyOS),是基于微内核的全场景分布式 OS,可按需扩展,实现更广泛的系统安全 。目前主要用于智能物联网,在将来无法使用Android时可扩展到智能手机上。HarmonyOS 拥有分布架构、内核安全、生态共享、运行流畅四大优势,鸿蒙 OS 生态的两大核心要素包括自身的微内核结构和方舟编译器。

二、HarmonyOS的特点

1.HarmonyOS的设计与理念

鸿蒙OS 是全新的基于微内核的面向全场景的分布式操作系统。鸿蒙OS 的微内核已发展到seL4,如下图(图1所示)。seL4 的核心非常小,不到9000行C代码。对于微内核,由于用内存管理单元 MMU 对进程空间进行隔离保护,没有授权的进程将无法访问其他进程的空间,从而阻止了恶意程序对其他进程数据的窃取。鸿蒙OS 核心只保留了处理的时间、内存、通信、中断等基本的资源管理,所有其他功能由应用层来管理,以服务的形式去提供功能。服务之间采用进程间通信IPC。
鸿蒙OS实现模块化耦合,对应不同设备可弹性部署;首次将分布式架构用于终端OS,实现跨终端无缝协同体验;采用的确定时延引擎和高性能 IPC 技术使系统更流畅;其基于微内核架构可重塑终端设备安全性;通过统一IDE支撑一次开发,多端部署,实现跨终端生态共享。

2.HarmonyOS的创新

2.1 内部解耦 为适应不同的硬件,鸿蒙OS把每一层内部都解耦,形成几千个模块,每个模块的接口全部用头文件写好,打上标签说明该模块是怎样的设备。可针对应不同设备进行弹性部署,如智慧屏、穿戴设备、车机、音箱、手机等,同时创新的分布式软总线使得拥有不同功能的硬件可以彼此协同。如传统的相机、电视、音响等设备原本相互独立,利用鸿蒙的分布式软总线,这些设备可被虚拟化成摄像模组、显示模组、外放模组,并成为有机整体,用户无需另行设置即可按需调用各种功能,硬件终端之间形成相互协同。

2.2 虚拟硬件 创新性地打破传统终端硬件的边界,使诸如手机中的显示器、处理器芯片、内存等等实体硬件,可以通过软件按需求组合成不同硬件形态的虚拟硬件功能模块。

2.3 一次开发多端部署 通过用户接口UI控件的抽象和解耦,业务逻辑原子化,不同应用的适配,可以快速实现一次开发并进行多端部署。鸿蒙OS从设计之初就为多,终端而生,如边缘计算、IoT、服务器等。

2.4 分布式微内核 鸿蒙OS 的微内核所具有的分布式特点,有利于 IoT 的生态协同。现有各种操作系统只对应于某一种硬件,如Windows 只对应x86 PC、iOS对应苹果手机等,无法满足 IoT 时代众多不同种类终端的需要,也无法针对每种硬件分别开发一种操作系统或应用程序,导致不同硬件终端的生态无法共享协同,开发效率低。因此鸿蒙OS在 IoT应用中的优势更加明显。

3.方舟编译器特点分析

方舟编译器是华为2019年4月在P30系列手机发布会上公布的,定位于多终端系统,可协助鸿蒙操作系统进入更深层次布局边缘计算、服务器等领域,大幅提升手机端安卓系统的运行效率。

3.1 编译点提前方舟编译器能够在应用程序执行之前,就将Java代码编译成机器语言,从而大量释放硬件资源,这对于多终端,尤其是物联网边缘计算尤为重要。克服了传统编译器边执行边翻译导致的程序执行效率低下,以及安卓系统虚拟机程序安装时间长的不足。方舟编译器将编译过程提前至开发环节,开发者能通过方舟预置算法进行代码优化,还可自行开发代码优化算法,未来代码优化甚至有可能迁移至云端。

3.2 开发环境友好开发环境友好是鸿蒙搭建良好生态的重要因素。兼容 Java 和 C、C++等多种语言,增强了鸿蒙OS 的性能,并与自有麒麟、鲲鹏等硬件架构协同,形成类似微软和英特尔联盟的软硬件格局。克服了过去采用 Java 和 C/C++ 等多种语言混合开发应用程序时,传统编译器下跨语言应用执行效率较低的问题。

4.HarmonyOS的应用研究

鸿蒙OS 的出现将导致与 iOS 和 Android 成三足鼎立之势。尽管华为的鸿蒙OS 目前只作为5G手机中 Android 的备胎,据已公开的资料,鸿蒙OS 的 UI 设计、系统逻辑以及 App 安装界面,与现在华为手机上的 EMUI 并没有明显区别,这使现有 EMUI 用户可以尽快习惯新系统,降低学习成本。此外,由于鸿蒙OS与 Android 保持兼容,通过方舟编译系统,原来的应用还能够提速60%以上。

鸿蒙OS 的应用领域如图2所示。可应用于手机专有服务、智慧屏专有服务、穿戴设备专有服务、车机专有服务、音箱专有服务等领域,还可使这些不同设备协同工作,切换设备时实现无缝衔接。

鸿蒙OS 使手机、电脑、汽车、智能穿戴等设备的操作系统实现兼容,有利于物联网的升级管理和兼容,成为将来走向智能社会的一个操作系统。

鸿蒙OS与具有高速、低延时、广接入的5G相结合,为智能手机与智能穿戴设备的联动、智能自动驾驶汽车、物联网系统提供了新的基础技术支撑。

华为鸿蒙(HarmonyOS)支持多种协议混合适配不同业务场景,用100多种品类的控制组件,向开发者提供最丰富的连接方式。由于华为做了30多年通信,连通本来就是强项,这点是意料之中。
用“1+8+N”来总结华为的战略,就显得很直观。

1:手机是一个核心入口;

8:PC、平板、智慧大屏、车机、耳机、音箱、手表、眼镜这八个大小屏入口;

N:摄像头、路由器、冰箱、空调等N种泛物联网设备。

HarmonyOS 把各终端硬件的能力虚拟成可共享的能力资源池,让应用通过系统调用其所需的硬件能力。在这个架构下,硬件能力,类似活字印刷术中的一个个单字字模,可以被无限次重复使用。简单来说,各终端实现了硬件互助,资源共享;应用拥有了调用远程终端的能力(像调用本地终端一样方便);而用户收获一个多设备组成的超级终端。

结束

猛一看,鸿蒙系统占据着绝对的劣势。但从纵观移动操作系统十几年的起起伏伏,鸿蒙系统并非没有机会。在2007年第二季度,塞班系统占据着 63.75% 的市场份额,Windows Mobile 及 BlackBerry OS 则分别占据 10& 左右市场份额

虽然目前主流操作系统大多被国外垄断,我国华为公司的 HarmonyOS 虽然起步不久,但却具有许多独特优势,其改进的跨平台功能、支持多场景应用、可以在各种设备和平台上使用、可以满足消费者对低延迟和强安全性需求的特点,使其具有广阔的应用前景。

在硬件和软件之间,中国产业界一向“重硬轻软“。毕竟,硬件更容易被消费者感知,加一个摄像头、上一个大屏幕,用户一眼就看到了,发布会和营销都好找噱头。但是,软件,尤其是基础软件的革新,用户感知有很大很大的滞后性。因此,企业对于基础软件的投资,常常不被理解,甚至引来冷嘲热讽,这背后,是中国产业界普遍浮躁、急功近利的心态。

从华为的历史来看,它是一家十分耐得住寂寞的公司。往远了说,80年代创业之初代理交换机就很赚钱,任正非却偏偏要赌上一切搞如此高风险的自主研发;往近了说,当年海思何曾被被看好过,最初几代产品也是在你我的嘲笑中成长,最终十年磨一剑,终成大器。

【如果您想学习HarmonyOS 应用开发基础教程 请猛戳】

手动实现vue2.0的双向数据绑定原理

thbcm阅读(158)

一句话概括:数据劫持(Object.defineProperty)+发布订阅模式

双向数据绑定有三大核心模块(dep 、observer、watcher),它们之间是怎么连接的,下面来一一介绍。为了大家更好的理解双向数据绑定原理以及它们之间是如何实现关联的,先带领大家复习一下发布订阅模式。

一.首先了解什么是发布订阅模式

直接上代码:一个简单的发布订阅模式,帮助大家更好的理解双向数据绑定原理

//发布订阅模式
function Dep() {
    this.subs = []//收集依赖(也就是手机watcher实例),
}
Dep.prototype.addSub = function (sub) { //添加订阅者
    this.subs.push(sub); //实际上添加的是watcher这个实例
}
Dep.prototype.notify = function (sub) { //发布,这个方法的作用是遍历数组,让每个订阅者的update方法去执行
    this.subs.forEach((sub) => sub.update())
}

function Watcher(fn) {
    this.fn = fn;
}
Watcher.prototype.update = function () { //添加一个update属性让每一个实例都可以继承这个方法
    this.fn();
}
let watcher = new Watcher(function () {
    alert(1)
});//订阅
let dep = new Dep();
dep.addSub(watcher);//添加依赖,添加订阅者
dep.notify();//发布,让每个订阅者的update方法执行

二.new Vue()的时候做了什么?

只是针对双向数据绑定做说明

<template>
      <div id="app">
        <div>obj.text的值:{{obj.text}}</div>
        <p>word的值:{{word}}</p>
        <input type="text" v-model="word">
    </div>
</template>
<script>
   new Vue({
        el: "#app",
        data: {
            obj: {
                text: "向上",
            },
            word: "学习"
        },
        methods:{
        //  ...
        }
    })
</script>

Vue 构造函数都干什么了?

function Vue(options = {}) {
    this.$options = options;//接收参数
    var data = this._data = this.$options.data;
    observer(data);//对data中的数据进型循环递归绑定
    for (let key in data) {
       let val = data[key];
       observer(val);
       Object.defineProperty(this, key, {
           enumerable: true,
           get() {
               return this._data[key];
           },
           set(newVal) {
               this._data[key] = newVal;
           }
        })
    }
    new Compile(options.el, this)
};

在 new Vue({…})构造函数时,首先获取参数 options ,然后把参数中的 data 数据赋值给当前实例的 _data 属性上(this._data = this.$options.data),重点来了,那下面的遍历是为什么呢?首先我们在操作数据的时候是 this.word 获取,而不是 this._data.word,所以是做了一个映射,在获取数据的时候 this.word,其实是获取的 this._data.word 的值,大家可以在自己项目中输出this查看一下

1.接下来看看 observer 方法干了什么

function observer(data) {
    if (typeof data !== "object") return;
    return new Observer(data);//返回一个实例
}
function Observer(data) {
    let dep = new Dep();//创建一个dep实例
    for (let key in data) {//对数据进行循环递归绑定
        let val = data[key];
        observer(val);
        Object.defineProperty(data, key, {
            enumerable: true,
            get() {
               Dep.target && dep.depend(Dep.target);//Dep.target就是Watcher的一个实例
                return val;
            },
            set(newVal) {
                if (newVal === val) {
                    return;
                }
                val = newVal;
                observer(newVal);
                dep.notify() //让所有方法执行
            }
        })
    }
}

Observer 构造函数,首先 let dep=new Dep(),作为之后的触发数据劫持的 get 方法和 set 方法时,去收集依赖和发布时调用,主要的操作就是通过 Object.defineProperty 对 data 数据进行循环递归绑定,使用 getter/setter 修改其默认读写,用于收集依赖和发布更新。

2.再来看看 Compile 具体干了那些事情

function Compile(el, vm) {
    vm.$el = document.querySelector(el);
    let fragment = document.createDocumentFragment(); //创建文档碎片,是object类型
    while (child = vm.$el.firstChild) {
        fragment.appendChild(child);
    };//用while循环把所有节点都添加到文档碎片中,之后都是对文档碎片的操作,最后再把文档碎片添加到页面中,这里有一个很重要的特性是,如果使用appendChid方法将原dom树中的节点添加到fragment中时,会删除原来的节点。
    replace(fragment);

    function replace(fragment) {
        Array.from(fragment.childNodes).forEach((node) => {//循环所有的节点
            let text = node.textContent;
            let reg = /\{\{(.*)\}\}/;
            if (node.nodeType === 3 && reg.test(text)) {//判断当前节点是不是文本节点且符不符合{{obj.text}}的输出方式,如果满足条件说明它是双向的数据绑定,要添加订阅者(watcher)
                console.log(RegExp.$1); //obj.text
                let arr = RegExp.$1.split("."); //转换成数组的方式[obj,text],方便取值
                let val = vm;
                arr.forEach((key) => { //实现取值this.obj.text
                    val = val[key];
                });
                new Watcher(vm, RegExp.$1, function (newVal) {
                    node.textContent = text.replace(/\{\{(.*)\}\}/, newVal)
                });
                node.textContent = text.replace(/\{\{(.*)\}\}/, val); //对节点内容进行初始化的赋值
            }
            if (node.nodeType === 1) { //说明是元素节点
                let nodeAttrs = node.attributes;
                Array.from(nodeAttrs).forEach((item) => {
                    if (item.name.indexOf("v-") >= 0) {//判断是不是v-model这种指令
                        node.value = vm[item.value]//对节点赋值操作
                    }
                    //添加订阅者
                    new Watcher(vm, item.value, function (newVal) {
                        node.value = vm[item.value]
                    });
                    node.addEventListener("input", function (e) {
                        let newVal = e.target.value;
                        vm[item.value] = newVal;
                    })
                })
            }
            if (node.childNodes) { //这个节点里还有子元素,再递归
                replace(node);
            }
        })
    }

    //这是页面中的文档已经没有了,所以还要把文档碎片放到页面中
    vm.$el.appendChild(fragment);
}

Compile(编译方法)首先解释一下 DocuemntFragment(文档碎片)它是一个 dom 节点收容器,当你创造了多个节点,当每个节点都插入到文档当中都会引发一次回流,也就是说浏览器要回流多次,十分耗性能,而使用文档碎片就是把多个节点都先放入到一个容器中,最后再把整个容器直接插入就可以了,浏览器只回流了1次。
Compile 方法首先遍历文档碎片的所有节点,
1.判断是否是文本节点且符不符合{{obj.text}}的双大括号的输出方式,如果满足条件说明它是双向的数据绑定,要添加订阅者(watcher),new Watcher(vm,动态绑定的变量,回调函数fn)
2.判断是否是元素节点且属性中是否含有 v-model 这种指令,如果满足条件说明它是双向的数据绑定,要添加订阅者(watcher),new Watcher(vm,动态绑定的变量,回调函数fn) ,直至遍历完成。最后别忘了把文档碎片放到页面中

3.Dep构造函数(怎么收集依赖的)

var uid=0;
//发布订阅
function Dep() {
    this.id=uid++;
    this.subs = [];
}
Dep.prototype.addSub = function (sub) { //订阅
    this.subs.push(sub); //实际上添加的是watcher这个实例
}
Dep.prototype.depend = function () { // 订阅管理器
    if(Dep.target){//只有Dep.target存在时采取添加
        Dep.target.addDep(this);
    }
}
Dep.prototype.notify = function (sub) { //发布,遍历数组让每个订阅者的update方法去执行
    this.subs.forEach((sub) => sub.update())
}

Dep 构造函数内部有一个 id 和一个 subs,id=uid++ ,id用于作为 dep 对象的唯一标识,subs 就是保存 watcher 的数组。depend 方法就是一个订阅的管理器,会调用当前 watcher 的 addDep 方法添加订阅者,当触发数据劫持(Object.defineProperty)的 get 方法时会调用 Dep.target && dep.depend(Dep.target)添加订阅者,当数据改变时触发数据劫持(Object.defineProperty)的 set 方法时会调用 dep.notify 方法更新操作。

4.Watcher构造函数干了什么

function Watcher(vm, exp, fn) {
   this.fn = fn;
   this.vm = vm;
   this.exp = exp //
   this.newDeps = [];
   this.depIds = new Set();
   this.newDepIds = new Set();
   Dep.target = this; //this是指向当前(Watcher)的一个实例
   let val = vm;
   let arr = exp.split(".");
   arr.forEach((k) => { //取值this.obj.text
       val = val[k] //取值this.obj.text,就会触发数据劫持的get方法,把当前的订阅者(watcher实例)添加到依赖中
   });
   Dep.target = null;
}
Watcher.prototype.addDep = function (dep) {
   var id=dep.id;
   if(!this.newDepIds.has(id)){
       this.newDepIds.add(id);
       this.newDeps.push(dep);
       if(!this.depIds.has(id)){
           dep.addSub(this);
       }
   }
  
}
Watcher.prototype.update = function () { //这就是每个绑定的方法都添加一个update属性
   let val = this.vm;
   let arr = this.exp.split(".");
   arr.forEach((k) => { 
       val = val[k] //取值this.obj.text,传给fn更新操作
   });
   this.fn(val); //传一个新值
}

Watcher 构造函数干了什么
1.接收参数,定义了几个私有属性( this.newDep ,this.depIds,this.newDepIds)
2. Dep.target = this,通过参数进行 data 取值操作,这就会触发 Object.defineProperty 的 get 方法,它会通过订阅者管理器(dep.depend())添加订阅者,添加完之后再将 Dep.target=null 置为空;
3.原型上的 addDep 是通过id这个唯一标识,和几个私有属性的判断防止订阅者被多次重复添加
4.update 方法就是当数据更新时,dep.notify()执行,触发订阅者的 update 这个方法, 执行发布更新操作。

总结一下 vue2.0 中双向数据绑定,简单来说就是 Observer、Watcher、Dep 三大部分;
1.首先用 Object.defineProperty()循环递归实现数据劫持,为每个属性分配一个订阅者集合的管理数组 dep;
2.在编译的时候,创建文档碎片,把所有节点添加到文档碎片中,遍历文档碎片的所有结点,如果是{{}},v-model 这种,new Watcher()实例并向 dep 的 subs 数组中添加该实例
3.最后修改值就会触发 Object.defineProperty() 的 set 方法,在 set 方法中会执行 dep.notify(),然后循环调用所有订阅者的 update 方法更新视图。

jquery gantt 甘特图

thbcm阅读(178)

一、简介

JQuery.Gantt 是一个开源的基于 JQuery 库的用于实现甘特图效果的可扩展功能的 JS 组件库。

二、JQuery.Gantt

开源的有2个,他们都叫 JQuery.Gantt 这两个在名字上有细微的区别,功能却是大不一样的,可以根据所需功能自行选择【不想自己下载看的,我在下面有截图展示】

(1)jQuery Gantt Chart 下载网址:https://github.com/taitems/jQuery.Gantt
(2)jQuery Gantt editor 原版下载网址:https://github.com/robicch/jQueryGantt
文档说明:https://roberto.twproject.com/2012/08/24/jquery-gantt-editor/

(1)jQuery Gantt Chart展示

(2)jQuery Gantt editor 展示

三、使用

我使用到的是第二个:jQuery Gantt editor 注意:这里的有些功能结合网上各位大神的总结以及教程做了修改,所以跟原版的甘特图稍有差别

四、功能改写

注意:也可下载原版对比着看、这里仅展示了部分

1、将弹出层改为中文显示

解释:打开页面开始均为英文,需要在 gantt.html 内将 TASK_EDITOR 内对应的字段改成中文即可,不需要哪些字段删掉即可

2、table 表头动态拖动可改变列宽、刷新后恢复初始设置值 解释:修改 ganttUtilities.js 文件修改后的代码:

//table表头动态拖动可改变列宽
  head.find("th.gdfColHeader.gdfResizable:not(.gdfied)").mouseover(function () {
    $(this).addClass("gdfColHeaderOver");

  }).bind("mouseout.gdf", function () {
    $(this).removeClass("gdfColHeaderOver");
    if (!$.gridify.columInResize) {
        $("body").removeClass("gdfHResizing");
    }

  }).bind("mousemove.gdf", function (e) {
    if (!$.gridify.columInResize) {
      var colHeader = $(this);
      var mousePos = e.pageX - colHeader.offset().left;

      if (colHeader.width() - mousePos < options.resizeZoneWidth) {
        $("body").addClass("gdfHResizing");
      } else {
        $("body").removeClass("gdfHResizing");
      }
    }

  }).bind("mousedown.gdf", function (e) {
    var colHeader = $(this);
    var mousePos = e.pageX - colHeader.offset().left;
    if (colHeader.width() - mousePos < options.resizeZoneWidth) {
      $("body").unselectable();
      $.gridify.columInResize = $(this);

      $(document).bind("mousemove.gdf", function (e) {

        //调整宽度时导致表头表体宽度不一致,修改为以下设置宽度方式
        var newWidth = (e.pageX - $.gridify.columInResize.offset().left)<5?5:(e.pageX - $.gridify.columInResize.offset().left)
        $.gridify.columInResize.width(newWidth);
        $.gridify.columInResize.data("fTh").width(newWidth);

      }).bind("mouseup.gdf", function () {
        $(this).unbind("mousemove.gdf").unbind("mouseup.gdf").clearUnselectable();
        $("body").removeClass("gdfHResizing");
        delete $.gridify.columInResize;
      });
    }

  }).bind("dblclick.gdf", function () {
    var col = $(this);

    if (!col.is(".gdfResizable"))
      return;

    var idx = $("th", col.parents("table")).index(col);
    var columnTd = $("td:nth-child(" + (idx + 1) + ")", table);
    var w = 0;
    columnTd.each(function () {
      var td = $(this);
      var content = td.children("input").length ? td.children("input").val() : td.html();
      var tmp = $("<div/>").addClass("columnWidthTest").html(content).css({position: "absolute"});
      $("body").append(tmp);
      w = Math.max(w, tmp.width() + parseFloat(td.css("padding-left")));
      tmp.remove();
    });

    w = w + 5;
    col.width(w);
    col.data("fTh").width(w);

    storeGridState();
    return false;

  }).addClass("gdfied unselectable").attr("unselectable", "true");


  function storeGridState() {
    if (localStorage) {
      var gridState = {};

      var colSizes = [];
      $(".gdfTable .gdfColHeader").each(function () {
        colSizes.push($(this).outerWidth());
      });

      gridState.colSizes = colSizes;

      localStorage.setObject("TWPGanttGridState", gridState);
    }
  }

  // 刷新页面恢复初始样式
  table.find("td.gdfCell:not(.gdfied)").each(function () {
    var cell = $(this);
    if (cell.is(".gdfEditable")) {
        // var inp = $("<input type='text'>").addClass("gdfCellInput");
        inp.val(cell.text());
        cell.empty().append(inp);
    } else {
        var wrp = $("<div>").addClass("gdfCellWrap");
        wrp.html(cell.html());
        cell.empty().append(wrp);
    }
  }).addClass("gdfied");

  return box;

3、滚动页面-保持两边滚动一致 解释:修改 ganttUtilities.js 文件修改后的代码:

// 页面滚动-滚动时保持两边一致
    var stopScroll = false;
    var fs = firstBox.add(secondBox);
    
    fs.scroll(function (e) {
      var el = $(this); //右页面
      var top = el.scrollTop(); //右边滚动距离顶部的距离

      if (el.is(".splitBox1") && stopScroll != "splitBox2") {
          stopScroll = "splitBox1";
          secondBox.scrollTop(top); //右
      } else if (el.is(".splitBox2") && stopScroll != "splitBox1") {
          stopScroll = "splitBox2";
          firstBox.scrollTop(top); //左
      }
      // 表头固定
      secondBox.find(".ganttFixHead").css('top', top);
      firstBox.find(".ganttFixHead").css("top" , top);

      where.stopTime("reset").oneTime(100, "reset", function () { stopScroll = ""; })
    });

JAVA基础之关键字、保留字和标识符

thbcm阅读(192)

关键字:

1.关键字(keyword)的定义和特点

  1. 定义:被 Java 语言赋予了特殊含义,用做专门用途的字符串(单词)
  2. 特点:关键字中所有字母都为小写
  3. 官方地址: https://docs.oracle.com/javase/tutorial/java/nutsandbolts/_keywords.html
用于定义数据类型的关键字
class interface enum byte short
int long float double char
boolean void
用于定义流程控制的关键字
if else switch case default
while do for break continue
return
用于定义访问权限修饰符的关键字
private protected public
用于定义类,函数,变量修饰符的关键字
abstract final static synchronized
用于定义类与类之间关系的关键字
extends implements
用于定义建立实例及引用实例,判断实例的关键字
new this super instanceof
用于异常处理的关键字
try catch finally throw throws
用于包的关键字
package import
其他修饰符关键字
native strictfp transient volatile assert
* 用于定义数据类型值的字面值
true false null

2.保留字(reserved word)

  • Java 保留字:现有 Java 版本尚未使用,但以后版本可能会作为关键字使 用。自己命名标识符时要避免使用这些保留字。
  • goto 、const.

3.标识符(Identifier)

标识符:

  • Java 对各种变量、方法和类等要素命名时使用的字符序列称为标识符。
  • 技巧:凡是自己可以起名字的地方都叫标识符。

定义合法标识符规则:

  • 由26个英文字母大小写,0-9 ,_或 $ 组成
  • 数字不可以开头。
  • 不可以使用关键字和保留字,但能包含关键字和保留字。
  • Java 中严格区分大小写,长度无限制。
  • 标识符不能包含空格。

Java中的名称命名规范:

  • 包名:多单词组成时所有字母都小写:xxxyyyzzz
  • 类名、接口名:多单词组成时,所有单词的首字母大写:XxxYyyZzz
  • 变量名、方法名:多单词组成时,第一个单词首字母小写,第二个单词开始每个单词首字母大写:xxxYyyZzz
  • 常量名:所有字母都大写。多单词时每个单词用下划线连接:XXX_YYY_ZZZ
  • 注意1:在起名字时,为了提高阅读性,要尽量有意义,“见名知意”。
  • 注意2:java 采用 unicode 字符集,因此标识符也可以使用汉字声明,但是不建议使用。

js中动态获取页面的script地址

thbcm阅读(190)

前言:(业务逻辑)

在 vue 中,遇到这样的情况,初始化加载太多js,导致页面白屏,为了解决这个情况,决定使用具体组件具体加载相应的 cdn地址。
为啥不用 vue 的按需加载呢,是因为我们项目对性能要求很高,但是按需加载后,引入的插件包,打包以后的大小比 cdn 要大太多了,整体来说是使用他是得不偿失,但是一次性加载太多 cdn 又会导致白屏,所以在这里我使用的方法:具体某个页面使用第三方插件,就在使用的页面 js 动态加载 scirpt,并给他上标签

具体操作:

1、面临第一个问题,要先获取到当前页面所用到的所有引入 的  <script>,下面的 newArr 就是拿到的所有的script地址

 let scriptsArr = document.getElementsByTagName('script')
      let newArr = []
      //获取所有的script地址
      for (var i = 0; i < scriptsArr.length; i++) {
        newArr.push(scriptsArr[i].getAttribute('src', 4))
      }

2、给界面加载我们想放进去的 cdn 地址,因为 vue 是单页面组件,所有我们直接放在 #app上

// 创建script标签,引入外部文件
        let script = document.createElement('script')
        script.type = 'text/javascript'
        script.src = url
        document.getElementById('app').appendChild(script)

分享源码:

mounted 中调用:(必须是 mounted,不能是 created,必须等页面加载完成才能挂载)

let url = '//cktcdn.kaoti100.com/cdn.jsdelivr.net/npm/vue-aplayer/vue-aplayer.js'
    this.app_script(url)//初始化给他添加cdn地址

methods 里面定义方法

/**
     * 获取页面上的所有script地址。来判断是否要加cdn地址
     * */
    app_script(url) {
      let scriptsArr = document.getElementsByTagName('script')
      let newArr = []
      //获取所有的script地址
      for (var i = 0; i < scriptsArr.length; i++) {
        newArr.push(scriptsArr[i].getAttribute('src', 4))
      }
      let isFirst = true //判断是否加载过这个script,有就不加载了
      let cdnUrl = url
      newArr.forEach(item => {
        if (item === cdnUrl) {
          isFirst = false
        }
      })
      if (isFirst) {
        // 创建script标签,引入外部文件
        let script = document.createElement('script')
        script.type = 'text/javascript'
        script.src = url
        document.getElementById('app').appendChild(script)
      }
 
    },

联系我们