This is a note library for Web.
lastpoem / notes Goto Github PK
View Code? Open in Web Editor NEWThis is a note library
This is a note library
在JS中,类的数据类型就是函数。它是由构造函数改造而来的。类本身就指向构造函数。
使用的时候,也是直接对类使用new命令,跟构造函数的用法完全一致。
构造函数的prototype属性,在 ES6 的“类”上面继续存在。事实上,类的所有方法都定义在类的prototype属性上面。
class Point {
constructor() {
// ...
}
toString() {
// ...
}
toValue() {
// ...
}
}
// 等同于
Point.prototype = {
constructor() {},
toString() {},
toValue() {},
};
在类的实例上面调用方法,其实就是调用原型上的方法。
实例的construct方法就是它所属类的prototype(原型)的constructor方法。
由于类的方法都定义在prototype对象上面,所以类的新方法可以添加在prototype对象上面。Object.assign方法可以很方便地一次向类添加多个方法。
prototype对象的constructor属性,直接指向“类”的本身,这与 ES5 的行为是一致的。
类内部所有方法的定义,都是不可枚举的
constructor方法是类的默认方法,通过new命令生成对象实例时,自动调用该方法。一个类必须有constructor方法,如果没有显式定义,一个空的constructor方法会被默认添加。
constructor方法默认返回实例对象(即this),完全可以指定返回另外一个对象。
类必须使用new调用,否则会报错。这是它跟普通构造函数的一个主要区别,后者不用new也可以执行。
实例的属性除非显式定义在其本身(即定义在this对象上),否则都是定义在原型上(即定义在class上)。
类的所有实例共享一个原型对象。这也意味着,可以通过实例的__proto__属性为“类”添加方法。
proto 并不是语言本身的特性,这是各大厂商具体实现时添加的私有属性,虽然目前很多现代浏览器的 JS 引擎中都提供了这个私有属性,但依旧不建议在生产中使用该属性,避免对环境产生依赖。生产环境中,我们可以使用 Object.getPrototypeOf 方法来获取实例对象的原型,然后再来为原型添加方法/属性。
在“类”的内部可以使用get和set关键字,对某个属性设置存值函数和取值函数,拦截该属性的存取行为
存值函数和取值函数是设置在属性的 Descriptor 对象上的。
与函数一样,类也可以使用表达式的形式定义。
类和模块的内部,默认就是严格模式,所以不需要使用use strict指定运行模式。只要你的代码写在类或模块之中,就只有严格模式可用。考虑到未来所有的代码,其实都是运行在模块之中,所以 ES6 实际上把整个语言升级到了严格模式。
类不存在变量提升(hoist),这一点与 ES5 完全不同。
类的方法内部如果含有this,它默认指向类的实例。但是,必须非常小心,一旦单独使用该方法,很可能报错。
类相当于实例的原型,所有在类中定义的方法,都会被实例继承。如果在一个方法前,加上static关键字,就表示该方法不会被实例继承,而是直接通过类来调用,这就称为“静态方法”。
如果静态方法包含this关键字,这个this指的是类,而不是实例。
静态方法虽然不会被实例继承,但是父类的静态方法,可以被子类继承。
实例属性除了定义在constructor()方法里面的this上面,也可以定义在类的最顶层。
静态属性指的是 Class 本身的属性,即Class.propName,而不是定义在实例对象(this)上的属性。
new是从构造函数生成实例对象的命令。ES6 为new命令引入了一个new.target属性,该属性一般用在构造函数之中,返回new命令作用于的那个构造函数。如果构造函数不是通过new命令或Reflect.construct()调用的,new.target会返回undefined,因此这个属性可以用来确定构造函数是怎么调用的。
Class 内部调用new.target,返回当前 Class。需要注意的是,子类继承父类时,new.target会返回子类。利用这个特点,可以写出不能独立使用、必须继承后才能使用的类。
Vue组件化是为了实现代码复用,一个组件实际上就是一个模块。但是组件和模块是有区别的,组件中可能包含模块,模块中也可能包含组件。组件也是页面和功能的复合体。比如一个输入框组件,一个返回顶部组件,都是UI和业务逻辑的组合。当某个功能模块重复使用次数较多时,就可以把其**有部分抽象出来做成组件,这和面向对象中的抽象一个概念。当共有部分抽象出来后再次使用的时候只需要关注差异化的事物,而不用再次从头写共有部分。
实现组件化,关键是对于整体怎么拆分。
为了实现独立特性,组件需要考虑的是解耦。所以一般组件只会和它的父组件进行通信,这时就会用props和emit/on来实现父子通信。而子组件间的通信尽量通过父组件调度。 并且在组件化时一个原则就是从上到下传递状态(即数据),从下到上传递事件。
为了实现可复用,在封装组件时要考虑到组件所有的应用场景,让组件可应用的范围更大。这就要考虑从上到下需要传递哪些状态,子组件哪些属性是父组件可以定制的,以应对不同应用场景。
在webpack4.0以上版本中,需要先安装 webpack 再安装 webpack-cli .
在一个新项目中先用npm init 初始化项目,生成package.json ,再局部安装webpack 和 webpack-cli.
由于webpack作为一个打包工具,在生产环境中是不需要的,因此要在安装时加上 --save-dev
对于非js文件,webpack是无法直接打包的。这时候需要用loader把CSS,SCSS以及各种图片和文件资源加载进去。常用的有
css-loader style-loader file-loader 等。这些也是开发依赖。
css-loader或sass-loader要和style-loader一起用。下载sass-loader必须也要下载node-sass.
这是webpack的配置文件。在里面可以配置:
入口 出口 loader 插件 模式等。
使用postcss进行处理:
把样式提取成单独文件后在html里不引用css就没有样式。
步骤:
1.安装mini-css-extract-plugin
2.新建一个生产环境的配置文件:webpack.product.config.js并把mode改为production。开头
const MiniCssExtractPlugin = require('插件')
3.把module里的style-loader(用于注入样式到HTML中)换成引入的MiniCssExtractPlugin.loader
4.添加插件
plugins:[
new MiniCssExtractPlugin({
filename:'[name].css',
chunkFilename:'[id].css'
}),
]
另外在webpack时要指定配置文件为新建的生产环境的配置文件。
压缩css
1.安装optimize-css-assets-webpack-plugin,
并const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');
2.添加:
optimization:{
minimizer:[new OptimizeCSSAssetsPlugin({})]
}
压缩js
使用插件:
uglifyjs-webpack-plugin .使用这个的前提条件就是要在生产环境中使用
然后require进来
optimization:{
minimizer:[
new OptimizeCSSAssetsPlugin({}), //压缩css
new UglifyJsPlugin({
cache:true, parallel:true, sourceMap:true
//cache指js没变就不会重复压缩
})
]
在输出文件名时带上[hash].
为了让带Hash值的js和css文件可以引入到html中且不用随hash值变动而手动更改引入,需要使用HtmlWebpackPlugin。
使用此插件会生产新的HTML文件,因此需要在配置插件时把原有HTML文件作为模板引入到新HTML里。模板HTML不需要引入任何js和css,打包后会自动把打包的css和js引入。
在开发阶段,只需要在开发配置文件里添加
devtool:'inline-source-map',
就可以开启。
在启动webpack时添加--watch
webpack-dev-server提供了一个简单的web服务器,并可以实时热更新。
Vue路由作用:
路由用于设定访问路径,把路径和组件映射起来。
因为在vue单页面应用中,一个页面实际上就是一个组件。
1.基本使用
使用router-link to类似于a标签(本身就被渲染成a标签),to属性是要跳转的组件。跳转的组件渲染到上。其它内容不变。
router-view是组件渲染的地方。
2.路由默认值
在router配置中,使用重定向改变默认
{
path: "",
redirect: "/Login" // 需要的默认页面
},
3.去除路径中#的方法:
在router配置中加入:
mode: "history"
4.router-link其他属性:
tag属性:可以指定把渲染成什么标签。
比如渲染成button标签:
tag = "button"
replace属性:直接添加replace,就没有historystate历史记录
active-class: 当router-link 对应的路由匹配成功时,会自动给当前元素设置一个 router-link-active的class。 active-class可以改变默认的名称。也可以在路由配置里用LinkActiveClass设置。
5.编程式路由:
通过代码跳转路由this.$router.push("/路径")
或者this.$router.replace
6.动态路由
在某些情况下,要跳转的页面不确定,此时需要动态路由。
比如: /user/zhangsan 或者 /user/lisi
实现动态路由:
首先在路由配置里: { path: '/user/:id', component: User }
然后在router-link里绑定to属性,并在user/后来一个变量以实现动态路由
可以用this.$route.params.id 来访问路径所配置的id
注意router和route。
7.路由嵌套
比如在/home路径下同时又有home/news和home/message这两个路径。它们是home的子路径。
在路由配置中,
children里的path不能有/
home路径中配置children: [{
path: "news",
component: ()=> import ("路径")
},{
path: "message"
}]
注意:嵌套路由中也有默认路径。在嵌套的组件中也要用router-view作为容器显示组件。
8.路由传递参数
传递参数有两种类型: params 和 query.
params的类型: /router:id
传递方式:在path后加上对应的值。比如 /router/zhangsanID. (动态路由就使用params.)
然后再组件中通过this.$route.params.id来访问
query的类型:/router
传递方式:对象中使用query的key作为传递方式、
传递后的路径:/router?id=zhangsanID
具体操作:
在router-link 中绑定to属性,
this.$route.query
9.懒加载
再配置路由时,每个路径下的component: ( )=> import ("路径")
10.$router和$route的区别
this.$router实际上和在router文件中创造的全局router路由实例是同一个对象。
this.$route表示当前路由信息对象。表示当前激活的路由的状态信息,包含了当前 URL 解析得到的信息,还有 URL 匹配到的 route records(路由记录)。
路由信息对象:即$router会被注入每个组件中,可以利用它进行一些信息的获取。
扩展运算符(spread)是三个点(...)。它好比 rest 参数的逆运算,将一个数组转为用逗号分隔的参数序列。
主要用于函数调用,将一个数组变为参数序列。可与正常的函数参数一起使用
由于扩展运算符可以展开数组,所以不再需要使用apply方法将数组转为函数参数了。
[...'hello'] // [ "h", "e", "l", "l", "o" ]
Array.from方法用于将两类对象转为真正的数组:类似数组的对象(array-like object)和可遍历(iterable)的对象(包括 ES6 新增的数据结构 Set 和 Map)。
对于还没有部署该方法的浏览器,可以用Array.prototype.slice方法替代。
Array.from还可以接受第二个参数,作用类似于数组的map方法,用来对每个元素进行处理,将处理后的值放入返回的数组。
Array.of方法用于将一组值,转换为数组.这个方法的主要目的,是弥补数组构造函数Array()的不足。因为参数个数的不同,会导致Array()的行为有差异。
数组实例的copyWithin()方法,在当前数组内部,将指定位置的成员复制到其他位置(会覆盖原有成员),然后返回当前数组。也就是说,使用这个方法,会修改当前数组。
它接受三个参数。
数组实例的find方法,用于找出第一个符合条件的数组成员。它的参数是一个回调函数,所有数组成员依次执行该回调函数,直到找出第一个返回值为true的成员,然后返回该成员。如果没有符合条件的成员,则返回undefined。
使用定值填充一个数组。
ES6 提供三个新的方法——entries(),keys()和values()——用于遍历数组。它们都返回一个遍历器对象,可以用for...of循环进行遍历,唯一的区别是keys()是对键名的遍历、values()是对键值的遍历,entries()是对键值对的遍历。
Array.prototype.includes方法返回一个布尔值,表示某个数组是否包含给定的值,与字符串的includes方法类似。ES2016 引入了该方法。该方法的第二个参数表示搜索的起始位置,默认为0。如果第二个参数为负数,则表示倒数的位置,如果这时它大于数组长度(比如第二个参数为-4,但数组长度为3),则会重置为从0开始。
数组的成员有时还是数组,Array.prototype.flat()用于将嵌套的数组“拉平”,变成一维的数组。该方法返回一个新数组,对原数据没有影响。
数组的空位指,数组的某一个位置没有任何值。比如,Array构造函数返回的数组都是空位。
空位不是undefined,一个位置的值等于undefined,依然是有值的。空位是没有任何值,in运算符可以说明这一点。
对距离,面积,坡度,体积的基本测量和分析,以及通视线,阴影,高程对比,横截面,缓冲区分析,洪水分析,地形剖面
影像,高程等展示,坐标系统,地形,提供2d, 3d, dynamic, buildings, models, point cloud等可以放置到地形上。
操纵要素和3DML数据,分析空间关系。包括合并要素,剪切多边形,将多要素拆分成单要素,导出选择要素。
复杂的空间和属性查询。通过属性或(点线面对象间的)空间关系来过滤要素
server的功能
展示工具可以创建三维场景浏览。只要包括当前摄影机的位置和角度,图层和对象的显隐,系统时间,以及弹窗消息和标题。场景浏览可以转为视频文件。
高级工具允许将模型文件和点云数据从各种格式转换为aa流优化的skyline专有格式,以提高显示性能和下载速率.
添加了遍历器接口使得字符串可被for of遍历
根据标准,JSON 数据必须是 UTF-8 编码。但是,现在的JSON.stringify()方法有可能返回不符合 UTF-8 标准的字符串。
模板字符串(template string)是增强版的字符串,用反引号(`)标识。它可以当作普通字符串使用,也可以用来定义多行字符串,或者在字符串中嵌入变量。如果在模板字符串中需要使用反引号,则前面要用反斜杠转义。
如果使用模板字符串表示多行字符串,所有的空格和缩进都会被保留在输出之中。
所有模板字符串的空格和换行,都是被保留的,比如
let x = 1;
let y = 2;
`${x} + ${y} = ${x + y}`
// "1 + 2 = 3"
`${x} + ${y * 2} = ${x + y * 2}`
// "1 + 4 = 5"
let obj = {x: 1, y: 2};
`${obj.x + obj.y}`
// "3"
大括号内部可以放入任意的 JavaScript 表达式,可以进行运算,以及引用对象属性。如果大括号中的值不是字符串,将按照一般的规则转为字符串。比如,大括号中是一个对象,将默认调用对象的toString方法。
由于模板字符串的大括号内部,就是执行 JavaScript 代码,因此如果大括号内部是一个字符串,将会原样输出。
let template = `
<ul>
<% for(let i=0; i < data.supplies.length; i++) { %>
<li><%= data.supplies[i] %></li>
<% } %>
</ul>
`;
上面代码在模板字符串之中,放置了一个常规模板。该模板使用<%...%>放置 JavaScript 代码,使用<%= ... %>输出 JavaScript 表达式。
compile函数的用法如下
let parse = eval(compile(template));
div.innerHTML = parse({ supplies: [ "broom", "mop", "cleaner" ] });
// <ul>
// <li>broom</li>
// <li>mop</li>
// <li>cleaner</li>
// </ul>
它可以紧跟在一个函数名后面,该函数将被调用来处理这个模板字符串。这被称为“标签模板”功能(tagged template)。
标签模板其实不是模板,而是函数调用的一种特殊形式。“标签”指的就是函数,紧跟在后面的模板字符串就是它的参数。但是,如果模板字符里面有变量,就不是简单的调用了,而是会将模板字符串先处理成多个参数,再调用函数。
alert`123`
// 等同于
alert(123)
标签模板里面,可以内嵌其他语言。但是,模板字符串默认会将字符串转义,导致无法嵌入其他语言。
String.fromCodePoint()
ES5 提供String.fromCharCode()方法,用于从 Unicode 码点返回对应字符,但是这个方法不能识别码点大于0xFFFF的字符。
ES6 提供了String.fromCodePoint()方法,可以识别大于0xFFFF的字符,弥补了String.fromCharCode()方法的不足。在作用上,正好与下面的codePointAt()方法相反。
String.fromCodePoint(0x20BB7)
// "𠮷"
String.fromCodePoint(0x78, 0x1f680, 0x79) === 'x\uD83D\uDE80y'
// true
上面代码中,如果String.fromCodePoint方法有多个参数,则它们会被合并成一个字符串返回。
注意,fromCodePoint方法定义在String对象上,而codePointAt方法定义在字符串的实例对象上。
ES6 还为原生的 String 对象,提供了一个raw()方法。该方法返回一个斜杠都被转义(即斜杠前面再加一个斜杠)的字符串,往往用于模板字符串的处理方法。
String.raw`Hi\n${2+3}!`;
// 返回 "Hi\\n5!"
String.raw`Hi\u000A!`;
// 返回 "Hi\\u000A!"
如果原字符串的斜杠已经转义,那么String.raw()会进行再次转义。
String.raw`Hi\\n`
// 返回 "Hi\\\\n"
String.raw`Hi\\n` === "Hi\\\\n" // true
String.raw()方法可以作为处理模板字符串的基本方法,它会将所有变量替换,而且对斜杠进行转义,方便下一步作为字符串来使用。
String.raw()方法也可以作为正常的函数使用。这时,它的第一个参数,应该是一个具有raw属性的对象,且raw属性的值应该是一个数组。
String.raw({ raw: 'test' }, 0, 1, 2);
// 't0e1s2t'
// 等同于
String.raw({ raw: ['t','e','s','t'] }, 0, 1, 2);
作为函数,String.raw()的代码实现基本如下。
String.raw = function (strings, ...values) {
let output = '';
let index;
for (index = 0; index < values.length; index++) {
output += strings.raw[index] + values[index];
}
output += strings.raw[index]
return output;
}
ES6 提供了codePointAt()方法,能够正确处理 4 个字节储存的字符,返回一个字符的码点。
codePointAt()方法是测试一个字符由两个字节还是由四个字节组成的最简单方法。
传统上,JavaScript 只有indexOf方法,可以用来确定一个字符串是否包含在另一个字符串中。ES6 又提供了三种新方法。
这三个方法都支持第二个参数,表示开始搜索的位置。
repeat方法返回一个新字符串,表示将原字符串重复n次。
如果某个字符串不够指定长度,会在头部或尾部补全。padStart()用于头部补全,padEnd()用于尾部补全。
'x'.padStart(5, 'ab') // 'ababx'
'x'.padStart(4, 'ab') // 'abax'
'x'.padEnd(5, 'ab') // 'xabab'
'x'.padEnd(4, 'ab') // 'xaba'
上面代码中,padStart()和padEnd()一共接受两个参数,第一个参数是字符串补全生效的最大长度,第二个参数是用来补全的字符串
ES2019 对字符串实例新增了trimStart()和trimEnd()这两个方法。它们的行为与trim()一致,trimStart()消除字符串头部的空格,trimEnd()消除尾部的空格。它们返回的都是新字符串,不会修改原始字符串。
const s = ' abc ';
s.trim() // "abc"
s.trimStart() // "abc "
s.trimEnd() // " abc"
在浏览器端使用Babel会降低用户端体验,因此从Babel 6版本开始不再直接支持浏览器端。因此要在node.js上运行
无连接的含义:
无状态的含义:
ES5 的对象属性名都是字符串,这容易造成属性名的冲突。比如,你使用了一个他人提供的对象,但又想为这个对象添加新的方法(mixin 模式),新方法的名字就有可能与现有方法产生冲突。如果有一种机制,保证每个属性的名字都是独一无二的就好了,这样就从根本上防止属性名的冲突。这就是 ES6 引入Symbol的原因。
ES6 引入了一种新的原始数据类型Symbol,表示独一无二的值。它是 JavaScript 语言的第七种数据类型,前六种是:undefined、null、布尔值(Boolean)、字符串(String)、数值(Number)、对象(Object)。
Symbol 值通过Symbol函数生成。这就是说,对象的属性名现在可以有两种类型,一种是原来就有的字符串,另一种就是新增的 Symbol 类型。凡是属性名属于 Symbol 类型,就都是独一无二的,可以保证不会与其他属性名产生冲突。
let s = Symbol();
typeof s
// "symbol"
Symbol函数前不能使用new命令,否则会报错。这是因为生成的 Symbol 是一个原始类型的值,不是对象。也就是说,由于 Symbol 值不是对象,所以不能添加属性。基本上,它是一种类似于字符串的数据类型。
Symbol函数可以接受一个字符串作为参数,表示对 Symbol 实例的描述,主要是为了在控制台显示,或者转为字符串时,比较容易区分
如果 Symbol 的参数是一个对象,就会调用该对象的toString方法,将其转为字符串,然后才生成一个 Symbol 值。
注意,Symbol函数的参数只是表示对当前 Symbol 值的描述,因此相同参数的Symbol函数的返回值是不相等的。Symbol 值不能与其他类型的值进行运算,会报错。但是,Symbol 值可以显式转为字符串。Symbol 值也可以转为布尔值,但是不能转为数值。
创建 Symbol 的时候,可以添加一个描述。
const sym = Symbol('foo');
上面代码中,sym的描述就是字符串foo。这个用法不是很方便,因此ES2019 提供了一个实例属性description,直接返回 Symbol 的描述。
const sym = Symbol('foo');
sym.description // "foo"
由于每一个 Symbol 值都是不相等的,这意味着 Symbol 值可以作为标识符,用于对象的属性名,就能保证不会出现同名的属性。这对于一个对象由多个模块构成的情况非常有用,能防止某一个键被不小心改写或覆盖。
Symbol 值作为对象属性名时,不能用点运算符。只能用方括号
Symbol 作为属性名,该属性不会出现在for...in、for...of循环中,也不会被Object.keys()、Object.getOwnPropertyNames()、JSON.stringify()返回。但是,它也不是私有属性,有一个Object.getOwnPropertySymbols方法,可以获取指定对象的所有 Symbol 属性名。
Object.getOwnPropertySymbols方法返回一个数组,成员是当前对象的所有用作属性名的 Symbol 值。
有时,我们希望重新使用同一个 Symbol 值,Symbol.for方法可以做到这一点。它接受一个字符串作为参数,然后搜索有没有以该参数作为名称的 Symbol 值。如果有,就返回这个 Symbol 值,否则就新建并返回一个以该字符串为名称的 Symbol 值。
Symbol.for()与Symbol()这两种写法,都会生成新的 Symbol。它们的区别是,前者会被登记在全局环境中供搜索,后者不会。
除了定义自己使用的 Symbol 值以外,ES6 还提供了 11 个内置的 Symbol 值,指向语言内部使用的方法。
Symbol.hasInstance
对象的Symbol.hasInstance属性,指向一个内部方法。当其他对象使用instanceof运算符,判断是否为该对象的实例时,会调用这个方法。比如,foo instanceof Foo在语言内部,实际调用的是FooSymbol.hasInstance。
这是指协议对于交互性场景没有记忆能力。
举个例子:
1.点击一个纯HTML页面,发送请求获取HTML资源时每次返回的响应都是相同的。这就是一种无交互场景。在无交互场景中,无状态不会带来什么问题,因为无论是谁访问页面,内容都一样,每次请求也相互独立。
2.但是随着网络发展,在网页应用中,有些内容的访问是需要权限的。比如只有登录QQ空间你才能看到自己发的动态。此时无状态会带来很大的问题:当你登录成功后页面跳转到了首页。这时你在首页中点击相册,会返回错误信息。因为无状态,HTTP不知道你是谁,你又成了未登录的状态。
解决:
HTTP本身是记不住你有没有登录的,因此需要前端告诉后端自己是否登录了。解决办法就是登录后后端返回一些验证信息,前端保存验证信息,下次再发送请求时把验证信息也放进去,后端拿到验证信息后发现是某个账号已经登录了,于是返回应有的响应。这个验证信息就放在Cookies里。而登录使用的验证信息一般都是token。
vue应用中的登录
在vue中,可以通过Vuex,localStorage, router以及axios共同实现登陆后一段时间内不需要再次输入用户名密码也能记住登录状态。
思路:
第一部分:存储token
以上保证了最新token的保存以及在vue各组件中都能访问到。
第二部分:路由设置
以上确保了只有登录了才能访问内容。
第三部分:请求设置
在使用axios发送请求时设置请求拦截和响应拦截。
在使用axios时配置请求拦截,可以在请求前把token等信息放到请求头里以让后端验证。
配置响应拦截,这样在后端发现没有token或者token过期后返回401时就跳转到登录页面重新登录。
以上保证了后端对token的检验。
异步JavaScript和XML
请求报文 :请求行 请求头 请求正文
响应报文 :状态行 响应头 响应正文
状态
2xx:成功
3xx:重定向
4xx:客户端错误
5xx:服务器错误
1.创建一个XMLHttpRequest对象
2.调用open方法
3.用onreadystatechange设置响应请求状态变化函数
4 .send数据
GET和POST区别
GET是用于获取数据的,POST,一般用于将数据发给服务器之用.传文件必须要用POST.
事实上,GET也可以把参数放到请求体中,POST也可以通过URL传递参数。但是浏览器和服务器可能不接受这种请求。GET的URL长度也并没有限制,长度限制来自于浏览器的限制。
此API是基于Dojo和AMD加载实现的。首先需要在require里引入所需要的模块,在回调函数中把模块暴露的类作为参数。然后再回调函数中使用这些对象完成各种操作。
重要的类:Map,MapView, SceneView,Layer,LayerView,FeatureLayer,GraphicsLayer,Renderer, Graphic,Geometry,Symbol,Widgets等。
map:在map里指定底图。但是只有用view创建一个视图并把地图加载到view中才能在浏览器看到地图。view实际上就是map的容器。
二维地图需要二维容器,即MapView。三维地图就要使用SceneView,即三维场景。
底图属性:light-gray-vector,dark-gray-vector,satellite,streets-relief-vector,和streets-navigation-vector。
首先要把API放到本地服务器上。需要注意的是要给服务器设置跨域请求。
把init.js和dojo.js 里的路径也要改成本地服务器下的路径。
最后可以直接在项目中引入API。
在 ES5 中,RegExp构造函数的参数有两种情况。
第一种情况是,参数是字符串,这时第二个参数表示正则表达式的修饰符(flag)。
var regex = new RegExp('xyz', 'i');
// 等价于
var regex = /xyz/i;
第二种情况是,参数是一个正则表示式,这时会返回一个原有正则表达式的拷贝。
var regex = new RegExp(/xyz/i);
// 等价于
var regex = /xyz/i;
但是,ES5 不允许此时使用第二个参数添加修饰符,否则会报错。
var regex = new RegExp(/xyz/, 'i');
// Uncaught TypeError: Cannot supply flags when constructing one RegExp from another
ES6 改变了这种行为。如果RegExp构造函数第一个参数是一个正则对象,那么可以使用第二个参数指定修饰符。而且,返回的正则表达式会忽略原有的正则表达式的修饰符,只使用新指定的修饰符。
字符串对象共有 4 个方法,可以使用正则表达式:match()、replace()、search()和split()。
ES6 将这 4 个方法,在语言内部全部调用RegExp的实例方法,从而做到所有与正则相关的方法,全都定义在RegExp对象上。
ES6 对正则表达式添加了u修饰符,含义为“Unicode 模式”,用来正确处理大于\uFFFF的 Unicode 字符。也就是说,会正确处理四个字节的 UTF-16 编码。
一旦加上u修饰符号,就会修改下面这些正则表达式的行为
1.点(.)字符
在正则表达式中,含义是除了换行符以外的任意单个字符。对于码点大于0xFFFF的 Unicode 字符,点字符不能识别,必须加上u修饰符。
2.Unicode 字符表示法
ES6 新增了使用大括号表示 Unicode 字符,这种表示法在正则表达式中必须加上u修饰符,才能识别当中的大括号,否则会被解读为量词。
3.量词
使用u修饰符后,所有量词都会正确识别码点大于0xFFFF的 Unicode 字符
4.预定义模式
u修饰符也影响到预定义模式,能否正确识别码点大于0xFFFF的 Unicode 字符。
5.i 修饰符
有些 Unicode 字符的编码不同,但是字型很相近,比如,\u004B与\u212A都是大写的K。
正则实例对象新增unicode属性,表示是否设置了u修饰符。
除了u修饰符,ES6 还为正则表达式添加了y修饰符,叫做“粘连”(sticky)修饰符。
y修饰符的作用与g修饰符类似,也是全局匹配,后一次匹配都从上一次匹配成功的下一个位置开始。不同之处在于,g修饰符只要剩余位置中存在匹配就可,而y修饰符确保匹配必须从剩余的第一个位置开始,这也就是“粘连”的涵义。
var s = 'aaa_aa_a';
var r1 = /a+/g;
var r2 = /a+/y;
r1.exec(s) // ["aaa"]
r2.exec(s) // ["aaa"]
r1.exec(s) // ["aa"]
r2.exec(s) // null
实际上,y修饰符号隐含了头部匹配的标志^。
与y修饰符相匹配,ES6 的正则实例对象多了sticky属性,表示是否设置了y修饰符。
返回正则表达式的修饰符
// ES5 的 source 属性
// 返回正则表达式的正文
/abc/ig.source
// "abc"
// ES6 的 flags 属性
// 返回正则表达式的修饰符
/abc/ig.flags
// 'gi'
正则表达式中,点(.)是一个特殊字符,代表任意的单个字符,但是有两个例外。一个是四个字节的 UTF-16 字符,这个可以用u修饰符解决;另一个是行终止符(line terminator character)。
所谓行终止符,就是该字符表示一行的终结。以下四个字符属于“行终止符”。
U+000A 换行符(\n)
U+000D 回车符(\r)
U+2028 行分隔符(line separator)
U+2029 段分隔符(paragraph separator)
ES2018 引入s修饰符,使得.可以匹配任意单个字符。这被称为dotAll模式,即点(dot)代表一切字符。所以,正则表达式还引入了一个dotAll属性,返回一个布尔值,表示该正则表达式是否处在dotAll模式。
JavaScript 语言的正则表达式,只支持先行断言(lookahead)和先行否定断言(negative lookahead),不支持后行断言(lookbehind)和后行否定断言(negative lookbehind)。ES2018 引入后行断言
“先行断言”指的是,x只有在y前面才匹配,必须写成/x(?=y)/。比如,只匹配百分号之前的数字,要写成/\d+(?=%)/。“先行否定断言”指的是,x只有不在y前面才匹配,必须写成/x(?!y)/。比如,只匹配不在百分号之前的数字,要写成/\d+(?!%)/。
“后行断言”正好与“先行断言”相反,x只有在y后面才匹配,必须写成/(?<=y)x/。比如,只匹配美元符号之后的数字,要写成/(?<=$)\d+/。“后行否定断言”则与“先行否定断言”相反,x只有不在y后面才匹配,必须写成/(?<!y)x/。比如,只匹配不在美元符号后面的数字,要写成/(?<!$)\d+/。
“后行断言”的实现,需要先匹配/(?<=y)x/的x,然后再回到左边,匹配y的部分。这种“先右后左”的执行顺序,与所有其他正则操作相反,导致了一些不符合预期的行为。
ES2018 引入了一种新的类的写法\p{...}和\P{...},允许正则表达式匹配符合 Unicode 某种属性的所有字符。Unicode 属性类要指定属性名和属性值。\P{…}是\p{…}的反向匹配,即匹配不满足条件的字符。
正则表达式使用圆括号进行组匹配。
const RE_DATE = /(\d{4})-(\d{2})-(\d{2})/;
上面代码中,正则表达式里面有三组圆括号。使用exec方法,就可以将这三组匹配结果提取出来。
const RE_DATE = /(\d{4})-(\d{2})-(\d{2})/;
const matchObj = RE_DATE.exec('1999-12-31');
const year = matchObj[1]; // 1999
const month = matchObj[2]; // 12
const day = matchObj[3]; // 31
组匹配的一个问题是,每一组的匹配含义不容易看出来,而且只能用数字序号(比如matchObj[1])引用,要是组的顺序变了,引用的时候就必须修改序号。
ES2018 引入了具名组匹配(Named Capture Groups),允许为每一个组匹配指定一个名字,既便于阅读代码,又便于引用。
const RE_DATE = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/;
const matchObj = RE_DATE.exec('1999-12-31');
const year = matchObj.groups.year; // 1999
const month = matchObj.groups.month; // 12
const day = matchObj.groups.day; // 31
上面代码中,“具名组匹配”在圆括号内部,模式的头部添加“问号 + 尖括号 + 组名”(?),然后就可以在exec方法返回结果的groups属性上引用该组名。同时,数字序号(matchObj[1])依然有效。
具名组匹配等于为每一组匹配加上了 ID,便于描述匹配的目的。如果组的顺序变了,也不用改变匹配后的处理代码。
如果具名组没有匹配,那么对应的groups对象属性会是undefined。
const RE_OPT_A = /^(?<as>a+)?$/;
const matchObj = RE_OPT_A.exec('');
matchObj.groups.as // undefined
'as' in matchObj.groups // true
上面代码中,具名组as没有找到匹配,那么matchObj.groups.as属性值就是undefined,并且as这个键名在groups是始终存在的。
有了具名组匹配以后,可以使用解构赋值直接从匹配结果上为变量赋值。
字符串替换时,使用$<组名>引用具名组。
AMD模块是一种非常规范化的模块,只需要两个方法:require和define。
define方法用于定义模块,RequireJS要求每个模块放在一个单独的文件里。
按照是否依赖其他模块,可以分成两种情况讨论。第一种情况是定义独立模块,即所定义的模块不依赖其他模块;第二种情况是定义非独立模块,即所定义的模块依赖于其他模块。
define需要三个参数:模块名,需要依赖的模块,以及回调函数。第一个参数可以省略,此时模块的文件名就是模块名。
require方法用于调用模块。它的参数与define方法类似。
require方法的第一个参数,是一个表示依赖关系的数组。第二个参数是回调函数。可以传入第三个参数,一个用于错误处理的回调函数。
包含三个参数
name: 是一个字符串,表示模块标识;
depend: 是一个数组,表示模块的依赖文件列表;
constructor: 当此参数是字符串,对象时,返回的接口就是本身。当为函数时,成这个函数为模块的构造函数,执行此函数,得到向外提供的接口。此函数默认接受三个参数:require、exports、module,下文会详细介绍这三个参数分别是什么。
require是一个方法,根据模块标识,获取其他模块提供的接口。
使用方法:
require(name);
//demo
define(function(require){
var a = require("a");
a.sayHello();
})
CMD 推崇依赖就近,AMD 推崇依赖前置。对于依赖的模块,AMD 是提前执行,CMD 是延迟执行。
AMD 是将需要使用的模块先加载完再执行代码,而 CMD 是在 require 的时候才去加载模块文件,加载完再接着执行。
JSON是原生JS里的一种数据格式。是用大括号括起来的键值对,但是和对象的区别是它的键名必须要加双引号
方法:
JSON.parse(json字符串):把json字符串转化为JSON对象。
JSON.stringify({} , [ ] , ""): 把数据序列化为json字符串。
配置路由插座
路由的跳转使用标签router-link
word页面
其中的to也可以绑定
子路由
{
path:'/word',
component:Word,
children:[
{
path:'router1',
component:Router1
},
{
path:'router2',
component:Router2
}
]
}
重定向
{
path:'router', // path路径
redirect:'/word/router3' // 重定向指向的路径
}
ES6 允许为函数的参数设置默认值,即直接写在参数定义的后面。
function log(x, y = 'World') {
console.log(x, y);
}
log('Hello') // Hello World
log('Hello', 'China') // Hello China
log('Hello', '') // Hello
参数默认值可以与解构赋值的默认值,结合起来使用。
function foo({x, y = 5}) {
console.log(x, y);
}
foo({}) // undefined 5
foo({x: 1}) // 1 5
foo({x: 1, y: 2}) // 1 2
foo() // TypeError: Cannot read property 'x' of undefined
上面代码只使用了对象的解构赋值默认值,没有使用函数参数的默认值。只有当函数foo的参数是一个对象时,变量x和y才会通过解构赋值生成。如果函数foo调用时没提供参数,变量x和y就不会生成,从而报错。通过提供函数参数的默认值,就可以避免这种情况。
function foo({x, y = 5} = {}) {
console.log(x, y);
}
foo() // undefined 5
指定了默认值以后,函数的length属性,将返回没有指定默认值的参数个数。也就是说,指定了默认值后,length属性将失真。
如果设置了默认值的参数不是尾参数,那么length属性也不再计入后面的参数了。
一旦设置了参数的默认值,函数进行声明初始化时,参数会形成一个单独的作用域(context)。等到初始化结束,这个作用域就会消失。这种语法行为,在不设置参数默认值时,是不会出现的。
利用参数默认值,可以指定某一个参数不得省略,如果省略就抛出一个错误。
ES6 引入 rest 参数(形式为...变量名),用于获取函数的多余参数,这样就不需要使用arguments对象了。rest 参数搭配的变量是一个数组,该变量将多余的参数放入数组中。
从 ES5 开始,函数内部可以设定为严格模式。ES2016 做了一点修改,规定只要函数参数使用了默认值、解构赋值、或者扩展运算符,那么函数内部就不能显式设定为严格模式,否则会报错。
返回该函数的函数名
=>
var f = v => v;
// 等同于
var f = function (v) {
return v;
};
如果箭头函数不需要参数或需要多个参数,就使用一个圆括号代表参数部分。
var f = () => 5;
// 等同于
var f = function () { return 5 };
var sum = (num1, num2) => num1 + num2;
// 等同于
var sum = function(num1, num2) {
return num1 + num2;
};
如果箭头函数的代码块部分多于一条语句,就要使用大括号将它们括起来,并且使用return语句返回。
var sum = (num1, num2) => { return num1 + num2; }
由于大括号被解释为代码块,所以如果箭头函数直接返回一个对象,必须在对象外面加上括号,否则会报错。
箭头函数的一个用处是简化回调函数。
(1)函数体内的this对象,就是定义时所在的对象,而不是使用时所在的对象。
(2)不可以当作构造函数,也就是说,不可以使用new命令,否则会抛出一个错误。
(3)不可以使用arguments对象,该对象在函数体内不存在。如果要用,可以用 rest 参数代替。
(4)不可以使用yield命令,因此箭头函数不能用作 Generator 函数。
箭头函数导致this总是指向函数定义生效时所在的对象,即和外部保持一致
由于箭头函数使得this从“动态”变成“静态”,下面两个场合不应该使用箭头函数。
尾调用(Tail Call)指某个函数的最后一步是调用另一个函数。
函数调用自身,称为递归。如果尾调用自身,就称为尾递归。
尾递归的实现,往往需要改写递归函数,确保最后一步只调用自身。做到这一点的方法,就是把所有用到的内部变量改写成函数的参数。
ES6 的尾调用优化只在严格模式下开启,正常模式需要自己实现。
js有六种数据类型,其中有5种基本数据类型:Number,String,Boolean,Null,Undefined。以及一种复杂(引用)数据类型:Object。
typeof是一种操作符,可以检测数据类型。使用后返回被检测量的类型,可以作用于变量和常量。
1.undefined表示未定义。但你声明一个变量但是没有给它初始化时,这个变量的值就是undefined。当你用typeof检测的时候它是undefined类型。但是用typeof检测未声明变量时也会返回undefined。不推荐变量赋值为undefined,但是显示的初始化声明变量可以帮助分辨变量是否初始化而不是未声明。
2.null也只有null这一个值。表示空对象。当你声明一个变量准备用它保存一个对象时,最好先把它初始化为null。
由于它是指向一个空的对象,用typeof会返回object。
3.Boolean只有true和false两个值。并且都是小写字母。可以用Boolean()把其他类型转为Boolean类型。非空字符串,0,NaN,null和undefined会转为false。
4.number默认十进制,可以用八进制(必须以零开头,严格模式下无效).十六进制里前两位是0x。在js里有正零和负零。
Number.MAX_VALUE或者MIN,可以表示的最大值和最小值。超出数值范围会转为Infinity或-Infinity
可以用isFinite()函数检测是否在最大值和最小值之间
NaN:非数值。表示一个本来要返回数值的操作数未返回数值的情况。例如,任何数除以零会返回NaN。任何涉及NaN的操作返回NaN。NaN和任何值都不相等,包括它自己。
强制类型转换里转为数值:Number(),parseInt()和parseFloat()
5.String类型,字符串。字符串是不可变的,一旦创建,它们的值就不能改变,要改变某个保存的字符串,首先要销毁原来的字符串。
转换为字符串:使用toString()方法。但null和undefined没有这个方法。String()可以把null和undefined变为null和undefined
6.Object类型。
暂时留坑。
var 如果在函数内声明它的变量的作用域就是函数内部,除此之外就是全局作用域了。
let和const 声明的变量都是块级作用域。可用大括号形成代码块以划定作用域范围。
let 所声明的变量只在它所在的代码块中有效(块级作用域)。因此for循环的计数器就非常适用let
const和let作用域一样
ES5只有全局作用域和函数作用域
ES6多了块级作用域
关于for循环:for循环中设置循环变量的部分是一个父作用域,而循环体内部是一个子作用域
var声明的变量可以重复声明,虽然这可能会造成bug.
let不允许在同作用域内重复声明同一个变量。用let声明后的变量不能再用let或var再次声明。
因此不能在函数内部重新声明参数。
var声明的变量存在变量提升,let和const不存在变量提升。因此用let和const会存在暂时性死区(TDZ)即在let声明变量前使用它是非法的
顶层对象,在浏览器环境指的是window对象,在 Node 指的是global对象。ES5 之中,顶层对象的属性与全局变量是等价的。ES6 为了改变这一点,一方面规定,为了保持兼容性,var命令和function命令声明的全局变量,依旧是顶层对象的属性;另一方面规定,let命令、const命令、class命令声明的全局变量,不属于顶层对象的属性。也就是说,从 ES6 开始,全局变量将逐步与顶层对象的属性脱钩。
JavaScript 语言存在一个顶层对象,它提供全局环境(即全局作用域),所有代码都是在这个环境中运行。但是,顶层对象在各种实现里面是不统一的。
浏览器里面,顶层对象是window,但 Node 和 Web Worker 没有window。
浏览器和 Web Worker 里面,self也指向顶层对象,但是 Node 没有self。
Node 里面,顶层对象是global,但其他环境都不支持。
同一段代码为了能够在各种环境,都能取到顶层对象,现在一般是使用this变量,但是有局限性。
全局环境中,this会返回顶层对象。但是,Node 模块和 ES6 模块中,this返回的是当前模块。
函数里面的this,如果函数不是作为对象的方法运行,而是单纯作为函数运行,this会指向顶层对象。但是,严格模式下,这时this会返回undefined。
不管是严格模式,还是普通模式,new Function('return this')(),总是会返回全局对象。但是,如果浏览器用了 CSP(Content Security Policy,内容安全策略),那么eval、new Function这些方法都可能无法使用。
综上所述,很难找到一种方法,可以在所有情况下,都取到顶层对象。下面是两种勉强可以使用的方法。
方法一
(typeof window !== 'undefined'
? window
: (typeof process === 'object' &&
typeof require === 'function' &&
typeof global === 'object')
? global
: this);
方法二
var getGlobal = function () {
if (typeof self !== 'undefined') { return self; }
if (typeof window !== 'undefined') { return window; }
if (typeof global !== 'undefined') { return global; }
throw new Error('unable to locate global object');
};
现在有一个提案,在语言标准的层面,引入globalThis作为顶层对象。也就是说,任何环境下,globalThis都是存在的,都可以从它拿到顶层对象,指向全局环境下的this。
垫片库global-this模拟了这个提案,可以在所有环境拿到globalThis。
ES5 比较两个值是否相等,只有两个运算符:相等运算符(==)和严格相等运算符(===)。它们都有缺点,前者会自动转换数据类型,后者的NaN不等于自身,以及+0等于-0。
ES6 提出“Same-value equality”(同值相等)算法,用来解决这个问题。Object.is就是部署这个算法的新方法。它用来比较两个值是否严格相等,与严格比较运算符(===)的行为基本一致。
不同之处只有两个:一是+0不等于-0,二是NaN等于自身。
+0 === -0 //true
NaN === NaN // false
Object.is(+0, -0) // false
Object.is(NaN, NaN) // true
基本用法
Object.assign方法用于对象的合并,将源对象(source)的所有可枚举属性,复制到目标对象(target)。
const target = { a: 1 };
const source1 = { b: 2 };
const source2 = { c: 3 };
Object.assign(target, source1, source2);
target // {a:1, b:2, c:3}
Object.assign方法的第一个参数是目标对象,后面的参数都是源对象。
注意,如果目标对象与源对象有同名属性,或多个源对象有同名属性,则后面的属性会覆盖前面的属性。
Object.assign拷贝的属性是有限制的,只拷贝源对象的自身属性(不拷贝继承属性),也不拷贝不可枚举的属性(enumerable: false)。
此方法可以处理数组,但是会把数组当作对象进行处理。
Object.assign只能进行值的复制,如果要复制的值是一个取值函数,那么将求值后再复制。
常见用途
Object.assign方法有很多用处。
(1)为对象添加属性
(2)为对象添加方法
(3)克隆对象
function clone(origin) {
return Object.assign({}, origin);
}
上面代码将原始对象拷贝到一个空对象,就得到了原始对象的克隆。
不过,采用这种方法克隆,只能克隆原始对象自身的值,不能克隆它继承的值。如果想要保持继承链,可以采用下面的代码。
function clone(origin) {
let originProto = Object.getPrototypeOf(origin);
return Object.assign(Object.create(originProto), origin);
}
(4)合并多个对象
将多个对象合并到某个对象
(5)为属性指定默认值
如,把用户提供的参数对象合并到默认值对象中,用户没提供的参数就会使用默认值,而提供的就会覆盖默认值。
ES5 的Object.getOwnPropertyDescriptor()方法会返回某个对象属性的描述对象(descriptor)。ES2017 引入了Object.getOwnPropertyDescriptors()方法,返回指定对象所有自身属性(非继承属性)的描述对象。
该方法的引入目的,主要是为了解决Object.assign()无法正确拷贝get属性和set属性的问题。
Object.getOwnPropertyDescriptors()方法配合Object.defineProperties()方法,就可以实现正确拷贝。
const source = {
set foo(value) {
console.log(value);
}
};
const target2 = {};
Object.defineProperties(target2, Object.getOwnPropertyDescriptors(source));
Object.getOwnPropertyDescriptor(target2, 'foo')
// { get: undefined,
// set: [Function: set foo],
// enumerable: true,
// configurable: true }
JavaScript 语言的对象继承是通过原型链实现的。ES6 提供了更多原型对象的操作方法。
__proto__属性
__proto__属性(前后各两个下划线),用来读取或设置当前对象的prototype对象。目前,所有浏览器(包括 IE11)都部署了这个属性
该属性没有写入 ES6 的正文,而是写入了附录,原因是__proto__前后的双下划线,说明它本质上是一个内部属性,而不是一个正式的对外的 API,只是由于浏览器广泛支持,才被加入了 ES6。标准明确规定,只有浏览器必须部署这个属性,其他运行环境不一定需要部署,而且新的代码最好认为这个属性是不存在的。因此,无论从语义的角度,还是从兼容性的角度,都不要使用这个属性,而是使用下面的Object.setPrototypeOf()(写操作)、Object.getPrototypeOf()(读操作)、Object.create()(生成操作)代替。
实现上,__proto__调用的是Object.prototype.proto
Object.setPrototypeOf()
Object.setPrototypeOf方法的作用与__proto__相同,用来设置一个对象的prototype对象,返回参数对象本身。它是 ES6 正式推荐的设置原型对象的方法。
Object.getPrototypeOf()
该方法与Object.setPrototypeOf方法配套,用于读取一个对象的原型对象。
ES5 引入了Object.keys方法,返回一个数组,成员是参数对象自身的(不含继承的)所有可遍历(enumerable)属性的键名。
ES2017 引入了跟Object.keys配套的Object.values和Object.entries,作为遍历一个对象的补充手段,供for...of循环使用。
Object.values()
Object.values方法返回一个数组,成员是参数对象自身的(不含继承的)所有可遍历(enumerable)属性的键值。
Object.entries()
Object.entries()方法返回一个数组,成员是参数对象自身的(不含继承的)所有可遍历(enumerable)属性的键值对数组。
Object.fromEntries()方法是Object.entries()的逆操作,用于将一个键值对数组转为对象。
该方法的主要目的,是将键值对的数据结构还原为对象,因此特别适合将 Map 结构转为对象。
Windows Presentation Foundation 翻译为Windows表示基础,简称WPF,产生于2007年。在此之前,桌面程序开发多数使用Win Forms等技术。在此之前,Windows Forms等技术使用的都是事件驱动理念,即事件-订阅-事件处理器,可能导致界面逻辑和业务逻辑纠缠在一起,而WPF是将事件驱动变成了数据驱动。
事件驱动,用户每进行一个操作就会激发一个事件,相应的事件处理器就会执行。事件驱动的数据是静态的,被动的,界面控件是主动的,界面逻辑与业务逻辑间的桥梁是事件。
数据驱动相反,数据发生变化时会主动通知界面控件,推动控件展示最新的数据。同时,用户对控件的操作会直接传达数据,因此在数据驱动理念中数据是占据主动地位,控件和控件事件被弱化,控件事件一般只参与界面逻辑而不再染指业务逻辑,使程序复杂度得到有效控制。数据和界面间桥梁是数据关联,通过这个桥梁,数据可以流向界面,再从界面流回数据源
1.引用
WPF应用程序会在引用里添加PresentationCore,PresentationFramework,WindowsBase三大核心程序集。
2.项目结构
App.xaml设置应用程序其实文件与资源
App.xaml.cs是App.xaml的后台文件,继承自System.Window.Application,用于处理整个WPF应用程序的相关
MainWindow.xaml是WPF程序界面和XAML设计文件
MainWindow.xaml.cs是MainWindow.xaml文件的后台代码文件,继承自System.Window.Window
3.项目代码基础
App.xaml中
x:Class="WpfSkyline.App" 是Application后台类
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"是WPF应用程序默认命名空间映射
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"映射可扩展应用程序标记语义XAML的扩展命名空间,通常将其映射为x前缀
StartupUri=“MainWindow.xaml”指定WPF项目运行时的启动窗体。
4.应用程序关闭
只有在应用程序的Shutdown方法被调用时才会停止运行。
ShutDown是隐式或显式发生,可以通过指定ShutdownMode属性值来设置。可选值为OnLastWindowClose(默认),OnMainWindowClose,OnExplicitShutdown
可以直接在App.xaml中修改ShutdownMode ,也可以在App.xaml.cs中在app.Run()方法之前修改。
Vue3的特性:
Vue3.0性能优化:
1.优化diff算法。
Vue2每次更新会对页面虚拟DOM进行全量对比,而Vue3只对比带有patch flag的节点,且可通过flag信息得知要对比的具体内容。
在创建虚拟DOM时会根据DOM中内容是否会发生变化来添加静态标记,DOM中内容会发生变化就会添加标记。
标记Flag是个枚举:
值为1表示动态文本节点
值为2表示动态class
值为4表示动态style
值为8表示动态属性,但不包含类名和样式
值为16表示具有动态key属性,当key改变时,需要进行完整的diff比较
值为32表示带有监听事件的节点
值为64表示一个不会改变子节点顺序的fragment
值为128表示带有key属性的fragment或部分子节点有key
值为256表示子节点没有key的fragment
值为512表示一个节点只会进行非props比较
2.hoistStatic 静态提升
Vue2中无论元素是否参与更新,每次都会重新创建,然后再渲染。
Vue3中对于不参与更新的元素,会做静态提升(将不会更新的元素提升到全局静态变量),只会被创建一次,在渲染时直接复用。
3.cacheHandlers 事件侦听器缓存
默认情况下onClick被视为动态绑定,所以每次都会追踪它的变化
但是因为是同一个函数,所以没有追踪变化,直接缓存起来复用即可。
这种事件初次渲染会给出8这个patch flag,下一次静态标记就会消失。因此不会再进行比较和追踪。
4.ssr渲染
当有大量静态内容时,这些内容会被当做纯字符串推进一个buffer里面。
即使存在动态绑定,会通过模板插值嵌入进去,这样会比通过虚拟DOM渲染快很多。
当静态内容大到一定量级时,会用_createStaticVNode 方法在客户端生成一个static node,这些静态node,会被直接innerHTML,就不需要创建对象,然后根据对象渲染。
vuex存储在内存,localstorage(本地存储)则以文件的方式存储在本地,永久保存。
localStorage只能存储字符串,对于对象可以使用stringify和parse来处理。
vuex是状态管理,是为了解决跨组件之间数据共享问题的,一个组件的数据变化会映射到使用这个数据的其他组件当中。如果刷新页面,之前存储的vuex数据全部都会被初始化掉。
localStorage是H5提供的一个更简单的数据存储方式,之前是用cookie存放数据,但是cookie的数据量太小,所以就用localStorage,它可以有5M的限制,不受刷新页面的控制,长久保存。
对于不变的数据,可以用localStorage来处理,但是当不同组件共用同一个数据,如果其中一个改变了这个数据并希望另一个组件响应变化时,需要用到vuex。简单来说,vuex的用途更体现在组件间的信息传递(状态管理)
vuex和全局变量的区别:
1响应式vuex的状态存储是响应式的,当Vue组件从store中读取状态的时候,若store中的状态发生变化,那么相应的组件也会得到高效更新。
2不能直接改变store不能直接改变store的变化,改变store中状态的唯一途径是commit mutation。方便于跟踪每一个状态的变化。
Vue
关于计算属性和方法:
两者都能使用函数对数据进行修改操作等,但是计算属性是基于它们的响应式依赖进行缓存的。只在相关响应式依赖发生改变时它们才会重新求值。这就意味着只要 message 还没有发生改变,多次访问 reversedMessage 计算属性会立即返回之前的计算结果,而不必再次执行函数。
这也同样意味着下面的计算属性将不再更新,因为 Date.now() 不是响应式依赖:
computed: {
now: function () {
return Date.now()
}
}
因此。对于性能开销比较大的计算属性 ,如果没有缓存,将会使用大量资源。但是对于不希望使用缓存的地方,就使用方法。
介绍不同地图服务前首先介绍下OGC。
OGC的简介:
OGC 全称是开放地理空间信息联盟(Open Geospatial Consortium),是一个非盈利的国际标准组织,它制定了数据和服务的一系列标准,GIS厂商按照这个标准进行开发可保证空间数据的互操作,致力于提供地理信息行业软件和数据及服务的标准化工作。
OGC1999年开始WMT1(Web Map Tested)和WMT2互操作项目。其中著名的GML来自WMT1的成果。
在WMT2中OGC定义了三种地理参考信息模型:Web Map Server(WMS) , Web Feature Server(WFS) ,Web Coverage Server(WCS)
1.Web 地图服务(WMS)
能够根据用户的请求返回相应的地图(包括PNG,GIF,JPEG等栅格形式或者是SVG和WEB CGM等矢量形式)。WMS支持网络协议HTTP,所支持的操作是由URL定义的。
有三个重要操作GetCapabilities,GetMap,GetFeatureinfo。
GetCapabilities返回服务级元数据。
GetMap返回一个地图影像。
GetFeatureinfo返回显示在地图上的某些特殊要素的信息。
还有一些其它操作如DescribeLayer,GetLegendGraphic,GetStyles,SetSytles。
事实上用传统的观点来解释,GetMap获得的就是在桌面程序中画在控件上的里的结果,是数据的表现。
GetFeatureInfo更容易理解,它和几乎所有的桌面程序上都用的Info按钮功能相同,都是用来获得屏幕坐标某处的信息,GetFeatureInfo中的参数是屏幕坐标、当前视图范围等,在一定程度上也方便了客户端的编写。
GetFeatureInfo可以同时返回多个图层中的要素信息,这一点和ArcGIS Desktop等也都是相同的。WMS还包括一些GetLegend之类的返回图例信息的请求,也是完全按照桌面既有的标准定义的。
2.Web 要素服务(WFS)
支持对地理要素的插入,更新,删除,检索和发现服务。该服务根据HTTP客户请求返回GML数据。
其基础接口是:GetCapabilities,DescribeFeatureType,GetFeature
GetCapabilities同上。
DescribeFeatureType返回要素结构,以便客户端进行查询和其他操作。
GetFeature可根据查询要求返回一个符合GML规范的数据文档。GetFeature是最重要的接口。
其它接口如Transaction 它不仅能提供要素读取,同时支持要素在线编辑和事务处理。
WFS对应于常见桌面程序中的条件查询功能,WFS通过OGC Filter构造查询条件,支持基于空间几何关系的查询,基于属性域的查询,当然还包括基于空间关系和属性域的共同查询。
在Web上,WFS的请求不是以SQL实现的,而是通过Filter XML来实现,可扩展性更强。WFS所返回的是查询的结果集,从某种程度上说,区别于WMS的“数据的表现”,WFS的结果集是由完整的Schema定义和约束的结果集,以GML为载体。这个结果集,类似于桌面程序查询结果的数据表。
3.Web地理覆盖服务(WCS)
提供的是包含了地理位置信息或属性的空间栅格图层,而不是静态地图的访问。
根据HTTP客户端要求发送相应数据,包括影像,多光谱影像和其它科学数据.
有二个重要操作GetCapabilities,GetCoverage
GetCapabilities返回一个描述服务和XML文档,从中可获取覆盖的数据集合。
GetCoverage是在GetCapabilities确定查询方案和需要获取的数据之后执行,返回覆盖数据。
还有可选操作DescribeCoverageType。
WCS对应基于栅格数据的功能,与WMS基于矢量数据的特点相对应。
4.Web地理覆盖服务(WMTS)
WMTS,切片地图Web服务(OpenGIS Web Map Tile Service)当前版本是1.0.0。WMTS标准定义了一些操作,这些操作允许用户访问切片地图。WMTS可能是OGC首个支持RESTful访问的服务标准。
WMTS提供了一种采用预定义图块方法发布数字地图服务的标准化解决方案。WMTS弥补了WMS不能提供分块地图的不足。WMS针对提供可定制地图的服务,是一个动态数据或用户定制地图(需结合SLD标准)的理想解决办法。WMTS牺牲了提供定制地图的灵活性,代之以通过提供静态数据(基础地图)来增强伸缩性,这些静态数据的范围框和比例尺被限定在各个图块内。这些固定的图块集使得对WMTS服务的实现可以使用一个仅简单返回已有文件的Web服务器即可,同时使得可以利用一些标准的诸如分布式缓存的网络机制实现伸缩性
5.Web 地图服务(WPS)
另:Web Processing Server(WPS)是新近推出的标准,它的功能其实我们已经耳熟能详了。Processing即ArcView中的GeoProcessing,诸如Union,Intersect等方法。WPS要做的就是暴露基于URL接口来实现客户端通过WebService对此类方法的调用、并返回数据。
备注:
这些规范基本在各大主流GIS平台和开源GIS软件中得到支持。
Intergraph早就推出了WFS服务器和互操作开发包。
ESRI在ArcIms 中开发了支持WMS,WFS等规范的相关部件。
MapInfo8.5也已经增加了能访问WMS和WFS服务,也有读取GML数据的借口功能。
GeoServer,MapServer地图服务器扮演向网络中的客户端提供地图服务的角色。这类地图服务器可以接收统一规范的WMS和WFS请求(request),返回多种格式的数据。这个过程有WMS/WFS规范的严格规定,所以,对客户端来说其地图服务器的实现究竟是什么并不会造成太大影响。这样的规范,为公共的、联合的地图服务创造了可能。
OpenLayers/MapBuilder,uDig,QGIS这些客户端软件分为浏览器和桌面客户端程序两种。以OpenLayers为代表的B/S系统客户端现在已经非常强大,它可以封装WMS请求,在浏览器上实现地图的切片载入功能。另外拖动、缩放都功能也非常完善,可以实现跨浏览器操作。最近的OpenLayers版本还支持了矢量编辑功能,可以通过WFS-t提交。而传统的桌面客户端程序功能则更加强大,支持多种包括WMS和WFS在内的数据源,另外编辑功能、操作性也要比浏览器中的强大。
总结:
WMS:动态地图服务,在ArcGIS中我们经常利用mxd文件发布的服务,就是这种地图服务,如果你的数据会变化,建议发这种服务。这种服务优点是动态,缺点是慢。
WMS-C:可以理解为WMS的升级版,预先缓存瓦片,按需请求,提高了访问的速度。
WMTS:相比WMS,牺牲了提供定制地图的灵活性,代之以通过提供静态数据(基础地图)来增强伸缩性,这些静态数据的范围框和比例尺被限定在各个图块内。
WFS:支持要素的增删改等事务操作,支持空间和属性查询。
WCS:我理解的是WCS主要是面向空间影像数据
WPS:这块我理解的主要是用来发起web端的空间运算处理工作,入裁切、合并等空间运算。
css3媒体查询是响应式方案核心
all 所有媒体(默认值)
screen 彩色屏幕
print 打印预览
projection 手持设备
tv 电视
braille 盲文触觉设备
embossed 盲文打印机
speech “听觉”类似的媒体设备
tty 不适用像素的设备
width (可加max min前缀)
height (可加max min前缀)
device-width (可加max min前缀)
device-pixel-ratio(可加max min前缀,需要加webkit前缀)
orientation portrait竖屏
landscape横屏
only:
防止老旧的浏览器 不支持带媒体属性的查询而应用到给定的样式.
@media only screen and (min-width:800px ){
规则;
规则
}
@media screen and (min-width:800px ){
规则;
规则
}
在老款的浏览器下
@media only ---> 因为没有only这种设备 规则被忽略
@media screen ---> 因为有screen这种设备而且老浏览器会忽略带媒体属性的查询
建议在每次抒写media query的时候带上only
and:
连接媒体属性 、连接媒体类型
对于所有的连接选项都要匹配成功才能应用规则
or(,) : 和and相似
对于所有的连接选项只要匹配成功一个就能应用规则
not:取反
一。一元操作符
(1)递增和递减:
包括前置和后置。如:
var age = 10;
++age;或者--age;
执行前置递增或递减时,变量值是在语句被求值之前改变的(在计算机领域通常被成为副效应)
如:var age = 29;
var ano = --age+2;
则:age为28,ano为30
而后置递增或递减,递增或递减的操作是在包含它们的语句被计算之后再执行的。
如:
var n1 = 2;
var n2 = 20;
var n3 = n1-- + n2 //等于22
var n4 = n1+n2 //等于21
(2)加减和正负:正常使用
(3)位操作符:
(4)布尔操作符
逻辑与或非
与&& 或 || 非!
async是一种声明,说明接下来是异步操作
普通函数会一直执行直到结束,async函数能够“暂停”。
要在需要暂停(异步操作)的地方之前使用await。
async函数返回一个 Promise 对象,可以使用then方法添加回调函数。当函数执行的时候,一旦遇到await就会先返回,等到异步操作完成,再接着执行函数体内后面的语句。函数前面的async关键字,表明该函数内部有异步操作。调用该函数时,会立即返回一个Promise对象。
function timeout(ms) {
return new Promise((resolve) => {
setTimeout(resolve, ms);
});
}
async function asyncPrint(value, ms) {
await timeout(ms);
console.log(value);
}
asyncPrint('hello world', 50);
上面代码指定 50 毫秒以后,输出hello world。
async函数返回一个 Promise 对象。
async函数内部return语句返回的值,会成为then方法回调函数的参数。
async函数内部抛出错误,会导致返回的 Promise 对象变为reject状态。抛出的错误对象会被catch方法回调函数接收到。
async函数返回的 Promise 对象,必须等到内部所有await命令后面的 Promise 对象执行完,才会发生状态改变,除非遇到return语句或者抛出错误。也就是说,只有async函数内部的异步操作执行完,才会执行then方法指定的回调函数。
await命令后面的Promise对象,运行结果可能是rejected,所以最好把await命令放在try...catch代码块中。
根据语法规格,await命令只能出现在 async 函数内部,否则都会报错。
作用:父组件给子组件传值
用法:在子组件中添加props属性,在父组件中引入子组件标签时绑定这个属性,并把值设置为父组件的一个data。在子组件中,props实际上和data中数据一样,可以用各种方法修改它。同时,可以把props属性设置为一个对象,其中可以设置默认值,是否必须,类型等。
示例
子组件:
<p>这是我的名字{{name}}</p>
export default{
props['name']
}
父组件:
<子组件 :name= ' value'> </子组件>
export default{
data(){
return{
value: 'zz'
}
}
}
作用:子组件给父组件传值
用法:在子组件中使用$emit方法。$emit参数有两个:emit事件名称和需要传递的值。然后再父组件的子组件标签中监听那个emit事件,并接收传递过来的值。
示例
子组件:
<button @click = 'set' ></button>
methods:{
set(){
let a = 10
this.$emit('setName', a)
}
}
父组件
<子组件 @set = “hehe = $event”></子组件>
data(){
return{
hehe: 'bs'
}
}
作用:把父组件的方法放到子组件中从而通过方法给子组件传值。相比直接传值不会报错。
用法:在父组件中的methods中设置一个方法,在父组件的子组件标签中绑定一个属性,并把值设置为父组件的这个方法。在子组件中的props中设置这个绑定的那个属性为Function
示例
子组件:
<button @click = ' reset()'></button>
data(){
hei : ' v '
}
props:{
reset: Function
}
父组件:
<子组件 :reset = 'chuan'></子组件>
methods:{
chuan(){
hei = 'ddd'
}
}
因此通过在子组件中的props设置数据和函数可以达到双向通信的效果
作用:实现在同一路由下的组件(可以是兄弟组件,也可以是其它关系)间通信。
用法:在main.js中设置一个全局的Vue实例,或者直接在Vue原型链上添加一个Vue实例。
如Vue.prototype.eventBus= new Vue();
其中的eventBus就是事件总线。
在需要发送数据的组件中: (起点站)
eventBus.$emit('事件名', 要传递的数据)
在需要接收数据的组件中:(终点站)
eventBus.$on('事件名',(data)=>{
对data进行处理
})
因为这个eventBus本身就是个Vue实例,可以在其中的methods中把起点站函数重新封装:
Vue.prototype.eventBus= new Vue({
methods: {
send(data){
this.$emit('click', data)
},
receive(回调函数){
this.$on('click', 回调函数)
}
}
})
此时就可以简化使用eventBus了。
简单来说vuex的功能就是保存多个组件中公用的数据并且是响应式的,即会在组件中改变。各组件也都能访问到。因此可以用vuex进行各组件间通信。官方称之为状态管理。
ES6 允许直接写入变量和函数,作为对象的属性和方法。这时,属性名为变量名, 属性值为变量的值。
除了属性,方法也可以简写。
注意,属性名表达式如果是一个对象,默认情况下会自动将对象转为字符串[object Object],这一点要特别小心
函数的name属性,返回函数名。对象方法也是函数,因此也有name属性。
如果对象的方法使用了取值函数(getter)和存值函数(setter),则name属性不是在该方法上面,而是该方法的属性的描述对象的get和set属性上面,返回值是方法名前加上get和set。
对象的每个属性都有一个描述对象(Descriptor),用来控制该属性的行为。Object.getOwnPropertyDescriptor方法可以获取该属性的描述对象。
描述对象的enumerable属性,称为“可枚举性”,如果该属性为false,就表示某些操作会忽略当前属性。
目前,有四个操作会忽略enumerable为false的属性。
for...in循环:只遍历对象自身的和继承的可枚举的属性。
Object.keys():返回对象自身的所有可枚举的属性的键名。
JSON.stringify():只串行化对象自身的可枚举的属性。
Object.assign(): 忽略enumerable为false的属性,只拷贝对象自身的可枚举的属性。
ES6 规定,所有 Class 的原型的方法都是不可枚举的。
ES6 一共有 5 种方法可以遍历对象的属性。
(1)for...in
for...in循环遍历对象自身的和继承的可枚举属性(不含 Symbol 属性)。
(2)Object.keys(obj)
Object.keys返回一个数组,包括对象自身的(不含继承的)所有可枚举属性(不含 Symbol 属性)的键名。
(3)Object.getOwnPropertyNames(obj)
Object.getOwnPropertyNames返回一个数组,包含对象自身的所有属性(不含 Symbol 属性,但是包括不可枚举属性)的键名。
(4)Object.getOwnPropertySymbols(obj)
Object.getOwnPropertySymbols返回一个数组,包含对象自身的所有 Symbol 属性的键名。
(5)Reflect.ownKeys(obj)
Reflect.ownKeys返回一个数组,包含对象自身的所有键名,不管键名是 Symbol 或字符串,也不管是否可枚举。
以上的 5 种方法遍历对象的键名,都遵守同样的属性遍历的次序规则。
this关键字总是指向函数所在的当前对象,ES6 又新增了另一个类似的关键字super,指向当前对象的原型对象。super关键字表示原型对象时,只能用在对象的方法之中,用在其他地方都会报错。
解构赋值
解构赋值必须是最后一个参数,否则会报错。
解构赋值的拷贝是浅拷贝,即如果一个键的值是复合类型的值(数组、对象、函数)、那么解构赋值拷贝的是这个值的引用,而不是这个值的副本。
扩展运算符
对象的扩展运算符(...)用于取出参数对象的所有可遍历属性,拷贝到当前对象之中。
由于数组是特殊的对象,所以对象的扩展运算符也可以用于数组。
如果扩展运算符后面是一个空对象,则没有任何效果。
如果扩展运算符后面不是对象,则会自动将其转为对象。
npm init 初始化项目,其实就是创建一个package.json文件。
npm install 安装所有项目依赖。
npm help xxx 查看xxx命令的帮助信息。
xxx 搜索xxx 如:npm search jquery。
xxx 搜索并安装xxx(局部)。安装多个依赖可用空格分割,如npm i jquery bootstrap。
xxx -g 搜索并安装xxx(全局)。安装多个同上。
xxx -D 安装并将依赖信息写在package.json中的devDependencies中。
快捷方式 i均可,如npm i jquery。
xxx@版本号 指定需要安装的版本号,若不指定将安装最新的稳定版本。
xxx 卸载xxx。多个依赖可用空格分割。
xxx -D 卸载xxx,并将依赖信息从package.json中的devDependencies中清除。
默认列出局部依赖。
npm list -g 列出已安装的全局依赖。
xxx 局部更新xxx。
xxx -g 全局更新xxx。
默认查看局部安装路径。
-g 查看全局安装路径。
xxx versions 列出xxx的所有版本, 如:npm view jquery versions。
xxx dependencies 列出xxx的所有依赖, 如:npm view gulp dependencies。
--save // 将模块依赖关系写入到package.json文件的dependencies参数中
-dev // 将模块依赖关系写入到package.json文件的devDependencies参数中
-g // 表示全局
@+version // 安装指定版本
Vuex的用途:专门用于状态管理。
因为在Vue中,状态即数据,状态管理实际上也就是数据管理。由于vue组件间数据传递较为困难且兄弟组件没有专门传递数据的方法,并且复杂应用中组件间传值变得更为复杂。此时可以使用vuex在多个组件间进行通信。
state是专门用于存放数据的对象。把需要在不同组件间传递的数据放在state里。
在组件中,使用this.$store.state.数据 来获取数据。
getters和vue中的computed类似,用于监听state里数据的变化。方便用state里存储的数据生成一些可以直接使用的数据。且只有state里的依赖值发生改变后getters里方法的返回值才会发送变化。
在组件中,使用this.$store.getters.处理方法 来获取处理后的数据
getters只是可以利用state里存储的数据生成一些经过处理的数据,但不会影响到state存储数据的本身。而mutations是唯一可以修改state所存储数据的对象。在mutations里定义方法,用来修改state里的数据。
在组件中。使用this.$store.commit(方法名,参数)使用mutations里的方法
类似于mutations,但是不同之处是:
官方不建议直接使用mutations来直接改变state里的数据,而是先提交actions,在actions里提交mutations来修改状态。
在组件中,使用this.$store.dispatch()使用actions里的方法
示例:
mutations:{
add(state){
// 修改state里的count
state.count = state.count + 1;
}
}
actions:{
addFun(context){
// 提交mutations里的add方法
context.commit("add")
}
}
// 在组件中的调用:
this.$store.dispatch("addFun")
包括mapState、mapGetters、mapActions
有时在组件中需要多次调用this.$stroe.state.数据,this.$store.dispatch(),这时可以现在组件中导入辅助函数
import {mapState,mapGetters,mapActions} from "vuex"
Vuex 允许我们将 store 分割成大大小小的对象,每个对象也都拥有自己的 state、getter、mutation、action,这个对象我们把它叫做 module(模块),在模块中还可以继续嵌套子模块、子子模块 ……
比如说某个module专门用于管理用户登录数据,而另一个module用来管理各组件间通信以实现某个业务逻辑。
用法示例:
在modules文件夹下新建两个文件:moduleA.js 和 moduleB.js
// moduleA的示例
export default {
state: {
text: 'moduleA'
},
getters: {},
mutations: {},
actions: {}
}
然后在store.js中,导入moduleA和B
import moduleA from './module/moduleA';
import moduleB from './module/moduleB';
export default new Vuex.Store({
modules: {
moduleA, moduleB,
},
// ...
}
在组件中就可以使用this.$store.state.moduleA.text来访问moduleA里state的数据text。(即需要通过模块名访问不同模块里的数据)
注意问题:
模块内部的 action、mutation 和 getter 默认可是注册在全局命名空间的,这样使得多个模块能够对同一 mutation 或 action 作出响应。
解决方法:通过添加 namespaced: true 的方式使其成为带命名空间的模块。比如在 moduleA.js 中添加 namespaced: true。
如何在模块中访问 store 根节点的数据 state:
可以在模块内部的 getter 和 action 中,通过 rootState 这个参数来获取。
以下是moduleA文件示例:
export default {
getters: {
// 注意:rootState必须是第三个参数
detail(state, getters, rootState) {
return state.text + '-' + rootState.name;
}
},
actions: {
callAction({state, rootState}) {
alert(state.text + '-' + rootState.name);
}
}
}
ES6 允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构(Destructuring)。解构失败时会等于undefined
分为完全解构和不完全解构。
解构时如果等号右边不是可以遍历的结构 就会出错。
对于 Set 结构,也可以使用数组的解构赋值。事实上,只要某种数据结构具有 Iterator 接口,都可以采用数组形式的解构赋值。
默认值
解构赋值允许指定默认值。ES6 内部使用严格相等运算符(===),判断一个位置是否有值。所以,只有当一个数组成员严格等于undefined,默认值才会生效。如果默认值是一个表达式,那么这个表达式是惰性求值的,即只有在用到的时候,才会求值。
默认值可以引用解构赋值的其他变量,但该变量必须已经声明。
对象的解构与数组有一个重要的不同。数组的元素是按次序排列的,变量的取值由它的位置决定;而对象的属性没有次序,变量必须与属性同名,才能取到正确的值。
对象的解构赋值,可以很方便地将现有对象的方法,赋值到某个变量。
默认值
默认值生效的条件是,对象的属性值严格等于undefined。
注意:
(1)如果要将一个已经声明的变量用于解构赋值,必须非常小心.不将大括号写在行首,避免js将其解释为代码块。
(2)解构赋值允许等号左边的模式之中,不放置任何变量名。因此,可以写出非常古怪的赋值表达式。
(3)由于数组本质是特殊的对象,因此可以对数组进行对象属性的解构。
不能使用圆括号的情况:
以下三种解构赋值不得使用圆括号。
(1)变量声明语句
(2)函数参数
(3)赋值语句的模式
可以使用圆括号的情况只有一种:赋值语句的非模式部分,可以使用圆括号。
(1)交换变量的值
let x = 1;
let y = 2;
[x, y] = [y, x];
(2)从函数返回多个值
// 返回一个数组
function example() {
return [1, 2, 3];
}
let [a, b, c] = example();
// 返回一个对象
function example() {
return {
foo: 1,
bar: 2
};
}
let { foo, bar } = example();
(3)函数参数的定义
// 参数是一组有次序的值
function f([x, y, z]) { ... }
f([1, 2, 3]);
// 参数是一组无次序的值
function f({x, y, z}) { ... }
f({z: 3, y: 2, x: 1});
(4)提取 JSON 数据
let jsonData = {
id: 42,
status: "OK",
data: [867, 5309]
};
let { id, status, data: number } = jsonData;
console.log(id, status, number);
// 42, "OK", [867, 5309]
(5)函数参数的默认值
(6)遍历 Map 结构
(7)输入模块的指定方法
const { SourceMapConsumer, SourceNode } = require("source-map");
**容器**
容器的布局方向
-webkit-box-orient:horizontal/vertical
控制主轴是哪一根
horizontal:x轴
vertical :y轴
容器的排列方向
-webkit-box-direction:normal/reverse
控制主轴的方向
normal:从左往右(正方向)
reverse:从右往左(反方向)
富裕空间的管理
只决定富裕空间的位置,不会给项目区分配空间
主轴
-webkit-box-pack
主轴是x轴
start:在右边
end: 在左边
center:在两边
justify:在项目之间
主轴是y轴
start:在下边
end:在上边
center:在两边
justify:在项目之间
侧轴
-webkit-box-algin
侧轴是x轴
start:在右边
end: 在左边
center:在两边
侧轴是y轴
start:在下边
end: 在上边
center:在两边
**项目**
弹性空间管理
-webkit-box-flex:弹性因子(默认值为0)
**容器**
容器的布局方向
容器的排列方向
flex-direction
控制主轴是哪一根,控制主轴的方向
row; 从左往右的x轴
row-reverse;从右往左的x轴
column; 从上往下的y轴
column-reverse;从下往上的y轴
富裕空间的管理
只决定富裕空间的位置,不会给项目区分配空间
主轴
justify-content
flex-start: 在主轴的正方向
flex-end: 在主轴的反方向
center: 在两边
space-between: 在项目之间
space-around: 在项目两边
侧轴
align-items
flex-start: 在侧轴的正方向
flex-end: 在侧轴的反方向
center: 在两边
baseline 基线对齐
stretch 等高布局(项目没有高度)
**项目**
弹性空间管理
flex-grow:弹性因子(默认值为0)
**容器**
flex-wrap:控制的是侧轴的方向
nowrap 不换行
wrap 侧轴方向由上而下 (flex-shrink失效)
wrap-reverse 侧轴方向由下而上 (flex-shrink失效)
align-content:多行/列时侧轴富裕空间的管理(把多行/列看成一个整体)
flex-flow:flex-direction和flex-wrap的简写属性
本质上控制了主轴和侧轴分别是哪一根,以及他们的方向
**项目**
order:控制项目的排列顺序
align-self:项目自身富裕空间的管理
flex-shrink:收缩因子(默认值为1)
flex-basis:伸缩规则计算的基准值(默认拿width或height的值)
flex-basis(默认值为auto)
flex-grow(默认值为0)
可用空间 = (容器大小 - 所有相邻项目flex-basis的总和)
可扩展空间 = (可用空间/所有相邻项目flex-grow的总和)
每项伸缩大小 = (伸缩基准值flex-basis + (可扩展空间 x flex-grow值))
flex-shrink(默认值为1)
--.计算收缩因子与基准值乘的总和
var a = 每一项flex-shrink*flex-basis之和
--.计算收缩因数
收缩因数=(项目的收缩因子*项目基准值)/第一步计算总和
var b = (flex-shrink*flex-basis)/a
--.移除空间的计算
移除空间= 项目收缩因数 x 负溢出的空间
var c = b * 溢出的空间
单行单列
align-items
align-self(优先级高)
多行多列
align-content
Vue.js 的核心是一个允许采用简洁的模板语法来声明式地将数据渲染进 DOM 的系统。简单来说,Vue通过数据驱动页面,而不直接操纵DOM。
在DOM元素中带有前缀v-的属性,会在渲染的DOM上应用特殊的响应行为
如v-bind, v-on事件监听,v-if,v-show,v-model,
每个Vue应用通过Vue函数创建的Vue实例开始(Vue组件也是实例)
数据与方法
当一个 Vue 实例被创建时,它将 data 对象中的所有的属性加入到 Vue 的响应式系统中。当这些属性的值发生改变时,视图将会产生“响应”,即匹配更新为新的值。
Vue 实例还暴露了一些有用的实例属性与方法,它们都有前缀 $,以便与用户定义的属性区分开来。
vm.$data === data // => true
vm.$el === document.getElementById('example') // => true
// $watch 是一个实例方法
vm.$watch('a', function (newValue, oldValue) {
// 这个回调将在 `vm.a` 改变后调用
})
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.