HTML篇
DOM的本质是什么:就是用JS表示的UI元素
DOM和虚拟DOM的区别:
-
DOM是由浏览器中的JS提供功能,所以我们只能人为的使用 浏览器提供的固定的API来操作DOM对象;
-
虚拟DOM:并不是由浏览器提供的,而是我们程序员手动模拟实现的,类似于浏览器中的DOM,但是有着本质的区别;目的是为了实现视图的高效更新
css篇
less和Sass
相同点:
都为css的拓展语言
1、混入(Mixins)——class中的class;
2、参数混入——可以传递参数的class,就像函数一样;
3、嵌套规则——Class中嵌套class,从而减少重复的代码;
4、运算——CSS中用上数学;
5、颜色功能——可以编辑颜色;
6、名字空间(namespace)——分组样式,从而可以被调用;
7、作用域——局部修改样式;
8、JavaScript 赋值——在CSS中使用JavaScript表达式赋值。
不同点:
less是通过Javascript编译,sass是通过ruby编译的,如果没有引入前端工程化,less会消耗客户端性能,sass会消耗服务端性能,但是引入前端工程化的话,gunt,gulp,webpack等,less和sass在打包阶段都会转化成css,所以不会有区别,只是sass是基于ruby,所以每次npm的时候相对慢一点点。
SASS技术的文件的后缀名有两种形式:.sass和.scss。其实两者都是同一种东西,两种均可以可以通过编译生成浏览器能识别的css文件。这两种的区别:
1)扩展名不同;
2)SCSS 的语法书写和CSS 语法书写方式非常类似,.sass文件对代码的排版有着非常严格的要求,而且没有大括号,没有分号;
JavaScript篇
js全局属性/函数
全局属性:
代表正的无穷大的数值。
指示某个值是不是数字值。
指示未定义的值。
全局函数:
解码某个编码的 URI。
解码一个编码的 URI 组件。
把字符串编码为 URI。
把字符串编码为 URI 组件。
对字符串进行编码。
计算 JavaScript 字符串,并把它作为脚本代码来执行。
检查某个值是否为有穷大的数。
检查某个值是否是非数字值。
把对象的值转换为数字。
解析一个字符串并返回一个浮点数。
解析一个字符串并返回一个整数。
把对象的值转换为字符串。
对由 escape() 编码的字符串进行解码。
js数组
可以改变原数组的方法:
Array.copyWithin(target[, start[, end])--浅复制数组的一部分到同一数组中的另一个位置,并返回它,不会改变原数组的长度。
Array.fill(value[, start[, end]])--用一个固定值填充一个数组中从起始索引到终止索引内的全部元素
Array.pop()---删除数组的最后一个元素并返回删除的元素。
Array.push()---向数组的末尾添加一个或更多元素,并返回新的长度。
Array.reverse()---反转数组的元素顺序。
Array.shift()---删除并返回数组的第一个元素。
Array.unshift()---向数组的开头添加一个或更多元素,并返回新的长度。
Array.sort()---对数组的元素进行排序。
Array.splice()---用于插入、删除或替换数组的元素。
不会改变原数组的方法:
Array.concat()---连接两个或更多的数组,并返回结果。
Array.entries()---返回一个新的Array Iterator对象,该对象包含数组中每个索引的键/值对
Array.keys()---返回一个包含数组中每个索引键的Array Iterator对象。
Array.values()---返回一个新的 Array Iterator 对象,该对象包含数组每个索引的值
Array.every()---检测数组元素的每个元素是否都符合条件。
Array.some()---检测数组元素中是否有元素符合指定条件。
Array.filter()---检测数组元素,并返回符合条件所有元素的数组。
Array.find()---返回数组中满足提供的测试函数的第一个元素的值。否则返回 undefined
Array.findIndex()---返回数组中满足提供的测试函数的第一个元素的索引。若没有找到对应元素则返回-1。
Array.flat(Inifity ?) -- 用于数组降维,不传参默认降一个维度,Inifity 降成一维数组,eg:[1,2,[3,4,[5,6]],].flat(Infinity) // [1, 2, 3, 4, 5, 6]
Array.flatMap()---首先使用映射函数映射每个元素,然后将结果压缩成一个新数组。它与 map 连着深度值为1的 flat 几乎相同,但 flatMap 通常在合并成一种方法的效率稍微高一些。
Array.includes()---用来判断一个数组是否包含一个指定的值,根据情况,如果包含则返回 true,否则返回false。Array.indexOf()---搜索数组中的元素,并返回它所在的位置。
Array.lastIndexOf()---返回一个指定的字符串值最后出现的位置,在一个字符串中的指定位置从后向前搜索。Array.join()---把数组的所有元素放入一个字符串。
Array.reduce()---对数组中的每个元素执行一个由您提供的reducer函数(升序执行),将其结果汇总为单个返回值。
Array.reduceRight()---接受一个函数作为累加器(accumulator)和数组的每个值(从右到左)将其减少为单个值。
Array.toLocaleString()---返回一个字符串表示数组中的元素。数组中的元素将使用各自的 toLocaleString 方法转成字符串,这些字符串将使用一个特定语言环境的字符串(例如一个逗号 ",")隔开。
Array.toString()---把数组转换为字符串,并返回结果。
可能会改变 也可能不会改变原数组的方法
Array.forEach()---对数组的每个元素执行一次给定的函数。
Array.map()---通过指定函数处理数组的每个元素,并返回处理后的数组。
会产生新数组的方法
Array.from()--从一个类似数组或可迭代对象创建一个新的,浅拷贝的数组实例。
Array.of()--创建一个具有可变数量参数的新数组实例,而不考虑参数的数量或类型
Array.concat()--用于合并两个或多个数组。此方法不会更改现有数组,而是返回一个新数组。
Array.filter()--创建一个新数组, 其包含通过所提供函数实现的测试的所有元素。
Array.flat()--会按照一个可指定的深度递归遍历数组,并将所有元素与遍历到的子数组中的元素合并为一个新数组返回。
Array.flatMap()--首先使用映射函数映射每个元素,然后将结果压缩成一个新数组
Array.map()--通过指定函数处理数组的每个元素,并返回处理后的数组。
Array.reduce()--对数组中的每个元素执行一个由您提供的reducer函数(升序执行),将其结果汇总为单个返回值。
Array.reduceRight()--接受一个函数作为累加器(accumulator)和数组的每个值(从右到左)将其减少为单个值。
Array.slice()---选取数组的的一部分,并返回一个新数组。
js对象
Object.assign(target, ...sources)--用于将所有可枚举属性的值从一个或多个源对象复制到目标对象。它将返回目标对象。
Object.create()--创建一个新对象,使用现有的对象来提供新创建的对象的__proto__Object.defineProperties(obj, props)--直接在一个对象上定义新的属性或修改现有属性,并返回该对象。
Object.entries()--返回一个给定对象自身可枚举属性的键值对数组,其排列与使用 for...in 循环遍历该对象时返回的顺序一致(区别在于 for-in 循环还会枚举原型链中的属性)
eg:const object1 = {
a: 'somestring',
b: 42
};
for (const [key, value] of Object.entries(object1)) {
console.log(`${key}: ${value}`); // "a: somestring" // "b: 42"
}
Object.fromEntries()--把键值对列表转换为一个对象。
Object.freeze()--可以冻结一个对象。一个被冻结的对象再也不能被修改;冻结了一个对象则不能向这个对象添加新的属性,不能删除已有属性,不能修改该对象已有属性的可枚举性、可配置性、可写性,以及不能修改已有属性的值。此外,冻结一个对象后该对象的原型也不能被修改。freeze() 返回和传入的参数相同的对象
Object.getOwnPropertyDescriptor()--返回指定对象上一个自有属性对应的属性描述符。(自有属性指的是直接赋予该对象的属性,不需要从原型链上进行查找的属性)
Object.getOwnPropertyNames()--返回一个由指定对象的所有自身属性的属性名(包括不可枚举属性但不包括Symbol值作为名称的属性)组成的数组
Object.getOwnPropertySymbols()--返回一个给定对象自身的所有 Symbol 属性的数组。
Object.getPrototypeOf() 方法返回指定对象的原型(内部[[Prototype]]属性的值)
Object.is()--判断两个值是否为同一个值。
//都是 undefined、null、true 或 false、相同长度的字符串且相同字符按相同顺序排列、相同对象(意味着每个对象有同一个引用)、都是数字且都是 +0或者都是 -0或者都是 NaN或都是非零而且非 NaN 且为同一个值
Object.preventExtensions()--让一个对象变的不可扩展,也就是永远不能再添加新的属性。
Object.isExtensible()--判断一个对象是否是可扩展的(是否可以在它上面添加新的属性)。
Object.keys()--会返回一个由一个给定对象的自身可枚举属性组成的数组,数组中属性名的排列顺序和正常循环遍历该对象时返回的顺序一致 。
eg:遍历对象:
var obj = {'0':'a','1':'b','2':'c'};
Object.keys(obj).forEach(function(key){
console.log(key,obj[key]);
});
Object.values()--返回一个给定对象自身的所有可枚举属性值的数组,值的顺序与使用for...in循环的顺序相同 ( 区别在于 for-in 循环枚举原型链中的属性 )。
eg:var obj = { 0: 'a', 1: 'b', 2: 'c' };
console.log(Object.values(obj)); // ['a', 'b', 'c']
js对象属性排序
对象是一个散列结构本身是没有顺序的
var data = {
'a':'000',
'3':'ccc',
'1':'aaa',
'测试':'bbb',
};
Object.keys(data);
//控制台输出:["1", "3", "a", "测试"]
调整属性’a’和’测试’的顺序呢?
var data = {
'测试':'bbb',
'3':'ccc',
'a':'000',
'1':'aaa'
};
Object.keys(data);
//控制台输出:["1", "3", "测试", "a"]
结论:对象的遍历输出并不是按照属性的ASC码升序排序的。
Chrome Opera 的 JavaScript 解析引擎遵循的是新版 ECMA-262 第五版规范。因此,使用 for-in 语句遍历对象属性时遍历书序并非属性构建顺序。而 IE6 IE7 IE8 Firefox Safari 的 JavaScript 解析引擎遵循的是较老的 ECMA-262 第三版规范,属性遍历顺序由属性构建的顺序决定。
Chrome Opera 中使用 for-in 语句遍历对象属性时会遵循一个规律: 它们会先提取所有 key 的 parseFloat 值为非负整数的属性,然后根据数字顺序对属性排序首先遍历出来,然后按照对象定义的顺序遍历余下的所有属性。 其它浏览器则完全按照对象定义的顺序遍历属性。
如果想顺序遍历一组数据,请使用数组并使用 for 语句遍历。 for-in语句无法保证遍历顺序,应尽量避免编写依赖对象属性顺序的代码。如果想按照定义的次序遍历对象属性,请参考 这里 针对各浏览器编写特殊代码。 由于对象的输出是无序的,但是数组却是有序的,所以为了保证顺序,搞成数组再输出。
typeof与instanceof的区别
typeof
typeof 是判断参数是什么类型的实例,返回值为说明运算数类型的字符串。
返回值结果:“number”、“string”、“boolean”、“object”、“function”、“undefined”
若参数为引用类型,始终返回“object”,对于Array、null始终返回“object”,所以用typeof来判断参数类型有很大的局限性
instanceof
instanceof是用来判断一个对象在其原型链中是否存在一个构造函数的prototype属性,判断方法是根据对象的原型链依次向下查询,如果obj2的原型属性存在obj1的原型链上,(obj1 instanceof obj2)值为true
a instanceof b:判断a是否为b的实例,可以用于继承关系中
b是c的父对象,a是c的实例,a instanceof b 与 a instanceof c 结果均为true
JS 在获取当前月的最后一天
var date= new Date();
date.setMonth(date.getMonth() + 1);
let lastDay = date.setDate(0); // 日期设置为0号, 0表示1号的前一天
console.log('最后一天:' + new Date(lastDay).toLocaleString())
js校验重复事件段,并获取重复区间
timeList = {
'DAILYMORE': [{
id: '',
startTime: '',
endTime: '',
repeatValid: false,
}],
'WEEKLYMORE': [{
id: '',
startTime: '',
endTime: '',
repeatValid: false,
}],
'MONTHMORE': [{
id: '',
startTime: '',
endTime: '',
repeatValid: false,
}],
};
checkTimeList(type, element?) {
if (this.timeList[type].length > 1) {
let begin = [], over = [], repArr = [];
this.timeList[type].forEach(item => {
if (item.startTime && item.endTime) {
begin.push(item.startTime);
over.push(item.endTime);
}
});
begin = begin.sort();
over = over.sort();
over.forEach((item, i) => {
if (item > begin[i + 1]) {
repArr.push(item);
}
});
if (element) {
element['repeatValid'] = this.timeList[type].some((ele, i) => {
return repArr.includes(ele.endTime);
});
} else {
this.timeList[type].map((ele, i) => {
ele['repeatValid'] = repArr.includes(ele.endTime);
});
}
} else {
this.timeList[type][0] ? this.timeList[type][0]['repeatValid'] = false : '';
}
}
JS函数柯里化
柯里化(Currying)是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数且返回结果的新函数的技术。
函数柯里化的主要作用和特点就是参数复用、提前返回和延迟执行。
function curry(fn, args) { var length = fn.length; var args = args || []; return function(){ newArgs = args.concat(Array.prototype.slice.call(arguments)); if (newArgs.length < length) { return curry.call(this,fn,newArgs); }else{ return fn.apply(this,newArgs); } }}function multiFn(a, b, c) { return a * b * c;}var multi = curry(multiFn);multi(2)(3)(4);multi(2,3,4);multi(2)(3,4);multi(2,3)(4);//es6const curry = (fn, arr = []) => (...args) => ( arg => arg.length === fn.length ? fn(...arg) : curry(fn, arg))([...arr, ...args])let curryTest=curry((a,b,c,d)=>a+b+c+d)curryTest(1,2,3)(4) //返回10curryTest(1,2)(4)(3) //返回10curryTest(1,2)(3,4) //返回10
Flash提供了ExternalInterface接口与JavaScript通信,ExternalInterface有两个方法,call和addCallback:
-
ExternalInterface.addCallback("在js里可调用的flash方法名",flash内方法) //在flash中通过这个方法公开 在js中可调用的flash内的方法;
-
ExternalInterface.call("js方法",传给js的参数) //在flash里调用js里的方法
js设计模式
1.单例模式
单例模式即一个类只能构造出唯一实例,单例模式的意义在于共享、唯一
class SingletonLogin {
constructor(name,password){
this.name = name
this.password = password
}
static getInstance(name,password){
//判断对象是否已经被创建,若创建则返回旧对象
if(!this.instance)this.instance = new SingletonLogin(name,password)
return this.instance
}
}
let obj1 = SingletonLogin.getInstance('CXK','123')
let obj2 = SingletonLogin.getInstance('CXK','321')
console.log(obj1===obj2) // true
console.log(obj1) // {name:CXK,password:123}
console.log(obj2) // 输出的依然是{name:CXK,password:123}
2.观察者模式
//普通观察者模式
class Publisher{
constructor(){
this.observers=[]; //这里存放所有订阅者
this.statement=""; //将来要发布的消息
}
//添加订阅者
addob(ob){
if(this.observers.indexOf(ob)==-1){
this.observers.push(ob);
}
}
//移除订阅者
removeob(ob){
let idx =this.observers.indexOf(ob);
if(idx!=-1){
this.observers.splice(idx,1);
}
}
//发布消息
notice(){
this.observers.forEach((cur,idx)=>{
cur.update(this.statement);
});
}
}
//订阅者
class Subscribe{
constructor(){}
update(data){
console.log(data);
}
}
let ob1 = new Subscribe();
let ob2 = new Subscribe();
let ob3 = {
update(data){
alert('hello'+data);
}
}
let pb = new Publisher();
pb.addob(ob1);
pb.addob(ob2);
pb.addob(ob3);
pb.statement = "hello,everyone";
pb.notice();
//观察者模式升级版
class Publisher{
constructor(){
//根据观察者订阅的主题分别存放观察者
this.observers ={
any:[],
}
}
//添加观察者,带类型,默认any类型
addob(fn,type="any"){
if(!this.observers[type]){
this.observers[type]=[];
}
if(this.observers[type].indexOf(fn)==-1){
this.observers[type].push(fn);
}
}
//默认any类型
removeob(fn,type="any"){
if(!this.observers[type]){
if(this.observers[type]){
let idx= this.observers[type].indexOf(fn);
if(idx!=-1){
this.observers[type].splice(idx, 1);
}
}
}
}
//要发布的内容和所属类型
notice(statement,type="any"){
if(this.observers[type]){
this.observers[type].forEach(cur=>{
cur(statement);
});
}
}
}
class Channel extends Publisher{
constructor(){
super();
}
//发布各类型消息
film(){
this.notice("movie");
}
tv(){
this.notice("tv");
}
}
//两个订阅者
var per1={
callBack(data){
console.log("收到tv:"+data);
}
}
var per2={
callBack(data){
console.log("收到movie:"+data);
}
}
//实例一个发布者
let channel = new Channel();
channel.addob(per1.callBack,"tv");
channel.addob(per2.callBack); //默认any类型
channel.film(); //只发布film类型
channel.tv(); //只发布TV类型
ES6篇
Set 实例的属性和方法
set结构: {1,2,3,4,5} Object size:5
Set 结构的实例有以下属性。
-
Set.prototype.constructor:构造函数,默认就是Set函数。 -
Set.prototype.size:返回Set实例的成员总数。
Set 实例的方法分为两大类:操作方法(用于操作数据)和遍历方法(用于遍历成员)。下面先介绍四个操作方法。
-
add(value):添加某个值,返回 Set 结构本身。 -
delete(value):删除某个值,返回一个布尔值,表示删除是否成功。 -
has(value):返回一个布尔值,表示该值是否为Set的成员。 -
clear():清除所有成员,没有返回值。 -
keys():返回键名的遍历器 -
values():返回键值的遍历器 -
entries():返回键值对的遍历器 -
forEach():使用回调函数遍历每个成员let set = new Set([1, 2]); set.forEach(function(value, key, ownerSet) { console.log(key + " " + value); console.log(ownerSet === set); }); // 输出 1 1 true 2 2 true
Map 类型是键值对的有序列表,而键和值都可以是任意类型。
let map = new Map();
map.set("title", "Understanding ES6");
map.set("year", 2016);
console.log(map.get("title"));
// "Understanding ES6"
console.log(map.get("year"));
// 2016
-
has(key) :判断指定的键是否存在于 Map 中;
-
delete(key) :移除 Map 中的键以及对应的值;
-
clear() :移除 Map 中所有的键与值。
let map = new Map([ ["name", "Nicholas"], ["age", 25]]); map.forEach(function(value, key, ownerMap) {
console.log(key + " " + value);
console.log(ownerMap === map); }); //打印:name Nicholastrueage 25true
async 和 await 和Promise
async 为异步函数, 是Generator 函数,await 只能出现在 async 函数中
async 函数返回的是一个 Promise 对象;await 可以用于等待一个 async 函数的返回值
async function test() { ///Promise对象
const v1 = await getSomething(); ///相当于resolve(data || undefined)
const v2 = await testAsync();
console.log(v1, v2);
}
test().then(res=>{
});
async/await 的优势在于处理 then 链
//三个步骤函数
function step1(n) {
console.log(`step1 with ${n}`);
return takeLongTime(n);
}
function step2(n) {
console.log(`step2 with ${n}`);
return takeLongTime(n);
}
function step3(n) {
console.log(`step3 with ${n}`);
return takeLongTime(n);
}
//Promise 方式来实现这三个步骤的处理
function doIt() {
console.time("doIt");
const time1 = 300;
step1(time1)
.then(time2 => step2(time2))
.then(time3 => step3(time3))
.then(result => {
console.log(`result is ${result}`);
console.timeEnd("doIt");
});
}
doIt();
// async/await 实现
async function doIt() {
console.time("doIt");
const time1 = 300;
const time2 = await step1(time1);
const time3 = await step2(time2);
const result = await step3(time3);
console.log(`result is ${result}`);
console.timeEnd("doIt");
}
doIt();
promise链式操作
Promise的精髓是“状态”,用维护状态、传递状态的方式来使得回调函数能够及时调用,它比传递callback函数要简单、灵活的多。所以使用Promise的正确场景是这样的
runAsync1()
.then(function(data){
console.log(data);
return runAsync2();
})
.then(function(data){
console.log(data);
return runAsync3();
})
.then(function(data){
console.log(data);
});
promise构造函数是同步执行的,then方法是异步执行的
Typescript篇
TypeScript
JavaScript
JavaScript 的超集用于解决大型项目的代码复杂性
一种脚本语言,用于创建动态网页
可以在编译期间发现并纠正错误
作为一种解释型语言,只能在运行时发现错误
强类型,支持静态和动态类型
弱类型,没有静态类型选项
最终被编译成 JavaScript 代码,使浏览器可以理解
可以直接在浏览器中使用
支持模块、泛型和接口
不支持模块,泛型或接口
社区的支持仍在增长,而且还不是很大
大量的社区支持以及大量文档和解决问题的支持
安装:npm install -g typescript验证版本:tsc -v编译:tsc helloworld.ts
基础类型
Boolean 类型:let isDone: boolean = false;
Number 类型:let count: number = 10;
String 类型:let name: string = "semliker";
Symbol 类型:
const sym = Symbol();
let obj = {
[sym]: "semlinker",
};
console.log(obj[sym]); // semlinker
Array 类型:
let list: number[] = [1, 2, 3];
let list: Array<number> = [1, 2, 3]; // Array<number>泛型语法
Enum 类型:
enum Direction {
NORTH,
SOUTH,
EAST,
WEST,
} //默认情况下,NORTH 的初始值为 0,其余的成员会从 1 开始自动增长
let dirName = Direction[0]; // NORTH
let dirVal = Direction["NORTH"]; // 0
enum Color {Red = 1, Green, Blue}
let colorName: string = Color[2];
console.log(colorName); //Green
Any 类型:
let notSure: any = 666;
notSure = "semlinker";
notSure = false;
Unknown 类型:unknown 类型只能被赋值给 any 类型和 unknown 类型本身
let value: unknown;
let value1: unknown = value; // OK
let value2: any = value; // OK
let value3: boolean = value; // Error
let value4: number = value; // Error
let value5: string = value; // Error
let value6: object = value; // Error
let value7: any[] = value; // Error
let value8: Function = value; // Error
Tuple 类型:数组一般由同种类型的值组成,但有时我们需要在单个变量中存储不同类型的值,这时候我们就可以使用元组
let tupleType: [string, boolean];
tupleType = ["semlinker", true];
Void 类型:
let unusable: void = undefined;
// 声明函数返回值为void
function warnUser(): void {
console.log("This is my warning message");
}
Null 和 Undefined 类型:
let u: undefined = undefined;
let n: null = null;
object, Object 和 {} 类型:
interface ObjectConstructor {
create(o: object | null): any;
}
Object.create(null);
const obj = {};
Never 类型:never 类型表示的是那些永不存在的值的类型
// 返回never的函数必须存在无法达到的终点
function error(message: string): never {
throw new Error(message);
}
函数:
TypeScript
JavaScript
含有类型
无类型
箭头函数
箭头函数(ES2015)
函数类型
无函数类型
必填和可选参数
所有参数都是可选的
默认参数
默认参数
剩余参数
剩余参数
函数重载
无函数重载
1、函数定义
// 函数声明写法
function maxA(x: number, y: number): number {
return x > y? x : y;
}
// 函数表达式写法
let maxB = function(x: number, y: number): number {
return x > y? x : y;
}
2、可选参数
function max(x: number, y?: number): number {
}
3.默认参数
function max(x: number, y = 4): number {
return x > y? x: y;
}
let result1 = max(2); // 正常
let result2 = max(2, 4); // 正常
let result3 = max(2, undefined); // 正常
4.剩余参数
function sum(x:number, ...restOfNumber:number[]): number {
}
5.函数重载
function css(config: {});
function css(config: string, value: string);
泛型:允许同一个函数接受不同类型参数的一种模板
设计泛型的关键目的是在成员之间提供有意义的约束,这些成员可以是:类的实例成员、类的方法、函数参数和函数返回值。
function identity <T, U>(value: T, message: U) : T {
console.log(message);
return value;
}
console.log(identity<Number, string>(68, "Semlinker"));
//泛型约束
interface Lengthwise {
length: number;
}
function loggingIdentity<T extends Lengthwise>(arg: T): T {
console.log(arg.length); // Now we know it has a .length property, so no more error
return arg;
}
装饰器
一个表达式,该表达式被执行后,返回一个函数,函数的入参分别为 target、name 和 descriptor,执行该函数后,可能返回 descriptor 对象,用于配置 target 对象
类装饰器
function Greeter(greeting: string) {
return function (target: Function) {
target.prototype.greet = function (): void {
console.log(greeting);
};
};
}
@Greeter("Hello TS!")
class Greeting {
constructor() {
// 内部实现
}
}
let myGreeting = new Greeting();
(myGreeting as any).greet(); // console output: 'Hello TS!';
网络篇--http
一、HTTP最常见的请求头如下:
l Accept:浏览器可接受的MIME类型;
l Accept-Charset:浏览器可接受的字符集;
l Accept-Encoding:浏览器能够进行解码的数据编码方式,比如gzip。Servlet能够向支持gzip的浏览器返回经gzip编码的HTML页面。许多情形下这可以减少5到10倍的下载时间;
l Accept-Language:浏览器所希望的语言种类,当服务器能够提供一种以上的语言版本时要用到;
l Authorization:授权信息,通常出现在对服务器发送的WWW-Authenticate头的应答中;
l Connection:表示是否需要持久连接。如果Servlet看到这里的值为“Keep-Alive”,或者看到请求使用的是HTTP 1.1(HTTP 1.1默认进行持久连接),它就可以利用持久连接的优点,当页面包含多个元素时(例如Applet,图片),显著地减少下载所需要的时间。要实现这一点,Servlet需要在应答中发送一个Content-Length头,最简单的实现方法是:先把内容写入ByteArrayOutputStream,然后在正式写出内容之前计算它的大小;
l Content-Length:表示请求消息正文的长度;
l Cookie:这是最重要的请求头信息之一;
l From:请求发送者的email地址,由一些特殊的Web客户程序使用,浏览器不会用到它;
l Host:初始URL中的主机和端口;
l If-Modified-Since:只有当所请求的内容在指定的日期之后又经过修改才返回它,否则返回304“Not Modified”应答;
l Pragma:指定“no-cache”值表示服务器必须返回一个刷新后的文档,即使它是代理服务器而且已经有了页面的本地拷贝;
l Referer:包含一个URL,用户从该URL代表的页面出发访问当前请求的页面。
l User-Agent:浏览器类型,如果Servlet返回的内容与浏览器类型有关则该值非常有用;
l UA-Pixels,UA-Color,UA-OS,UA-CPU:由某些版本的IE浏览器所发送的非标准的请求头,表示屏幕大小、颜色深度、操作系统和CPU类型。
二、响应头
HTTP最常见的响应头如下所示:
l Allow:服务器支持哪些请求方法(如GET、POST等);
l Content-Encoding:文档的编码(Encode)方法。只有在解码之后才可以得到Content-Type头指定的内容类型。利用gzip压缩文档能够显著地减少HTML文档的下载时间。Java的GZIPOutputStream可以很方便地进行gzip压缩,但只有Unix上的Netscape和Windows上的IE 4、IE 5才支持它。因此,Servlet应该通过查看Accept-Encoding头(即request.getHeader("Accept-Encoding"))检查浏览器是否支持gzip,为支持gzip的浏览器返回经gzip压缩的HTML页面,为其他浏览器返回普通页面;
l Content-Length:表示内容长度。只有当浏览器使用持久HTTP连接时才需要这个数据。如果你想要利用持久连接的优势,可以把输出文档写入ByteArrayOutputStram,完成后查看其大小,然后把该值放入Content-Length头,最后通过byteArrayStream.writeTo(response.getOutputStream()发送内容;
l Content-Type: 表示后面的文档属于什么MIME类型。Servlet默认为text/plain,但通常需要显式地指定为text/html。由于经常要设置Content-Type,因此HttpServletResponse提供了一个专用的方法setContentTyep。 可在web.xml文件中配置扩展名和MIME类型的对应关系;
l Date:当前的GMT时间。你可以用setDateHeader来设置这个头以避免转换时间格式的麻烦;
l Expires:指明应该在什么时候认为文档已经过期,从而不再缓存它。
l Last-Modified:文档的最后改动时间。客户可以通过If-Modified-Since请求头提供一个日期,该请求将被视为一个条件GET,只有改动时间迟于指定时间的文档才会返回,否则返回一个304(Not Modified)状态。Last-Modified也可用setDateHeader方法来设置;
l Location:表示客户应当到哪里去提取文档。Location通常不是直接设置的,而是通过HttpServletResponse的sendRedirect方法,该方法同时设置状态代码为302;
l Refresh:表示浏览器应该在多少时间之后刷新文档,以秒计。除了刷新当前文档之外,你还可以通过setHeader("Refresh", "5; URL=http://host/path")让浏览器读取指定的页面。注意这种功能通常是通过设置HTML页面HEAD区的实现,这是因为,自动刷新或重定向对于那些不能使用CGI或Servlet的HTML编写者十分重要。但是,对于Servlet来说,直接设置Refresh头更加方便。注意Refresh的意义是“N秒之后刷新本页面或访问指定页面”,而不是“每隔N秒刷新本页面或访问指定页面”。因此,连续刷新要求每次都发送一个Refresh头,而发送204状态代码则可以阻止浏览器继续刷新,不管是使用Refresh头还是<META HTTP-EQUIV="Refresh" ...>。注意Refresh头不属于HTTP 1.1正式规范的一部分,而是一个扩展,但Netscape和IE都支持它。
三、实体头
实体头用坐实体内容的元信息,描述了实体内容的属性,包括实体信息类型,长度,压缩方法,最后一次修改时间,数据有效性等。
l Allow:GET,POST
l Content-Encoding:文档的编码(Encode)方法,例如:gzip,见“2.5 响应头”;
l Content-Language:内容的语言类型,例如:zh-cn;
l Content-Length:表示内容长度,eg:80,可参考“2.5响应头”;
l Content-Location:表示客户应当到哪里去提取文档,例如:www.dfdf.org/dfdf.html,可参考“2.5响应头”;
l Content-MD5:MD5 实体的一种MD5摘要,用作校验和。发送方和接受方都计算MD5摘要,接受方将其计算的值与此头标中传递的值进行比较。Eg1:Content-MD5: <base64 of 128 MD5 digest>。Eg2:dfdfdfdfdfdfdff==;
l Content-Range:随部分实体一同发送;标明被插入字节的低位与高位字节偏移,也标明此实体的总长度。Eg1:Content-Range: 1001-2000/5000,eg2:bytes 2543-4532/7898
l Content-Type:标明发送或者接收的实体的MIME类型。Eg:text/html; charset=GB2312 主类型/子类型;
l Expires:为0证明不缓存;
l Last-Modified:WEB 服务器认为对象的最后修改时间,比如文件的最后修改时间,动态页面的最后产生时间等等。例如:Last-Modified:Tue, 06 May 2008 02:42:43 GMT.
四、扩展头
在HTTP消息中,也可以使用一些再HTTP1.1正式规范里没有定义的头字段,这些头字段统称为自定义的HTTP头或者扩展头,他们通常被当作是一种实体头处理。
现在流行的浏览器实际上都支持Cookie,Set-Cookie,Refresh和Content-Disposition等几个常用的扩展头字段。
l Refresh:1;url=www.dfdf.org //过1秒跳转到指定位置;
l Content-Disposition:头字段,可参考“2.5响应头”;
l Content-Type:WEB 服务器告诉浏览器自己响应的对象的类型。
eg1:Content-Type:application/xml ;
eg2:applicaiton/octet-stream;
跨域
同源策略限制以下几种行为
1.) Cookie、LocalStorage 和 IndexDB 无法读取
2.) DOM 和 Js对象无法获得
3.) AJAX 请求不能发送
解决方案
1、 通过jsonp跨域
2、 document.domain + iframe跨域
3、 location.hash + iframe
4、 window.name + iframe跨域
5、 postMessage跨域
6、 跨域资源共享(CORS)
7、 nginx代理跨域
8、 nodejs中间件代理跨域
9、 WebSocket协议跨域
from跟踪数值状态
at():获取数组中指定 index 处的 AbstractControl。
push():在数组的末尾插入一个新的 AbstractControl。
insert():在数组中的指定 index 处插入一个新的 AbstractControl。insert(index: number, control: AbstractControl): void
removeAt():移除位于数组中的指定 index 处的控件。removeAt(index: number): void
setValue():设置此 FormArray 的值。它接受一个与控件结构相匹配的数组
patchValue():修补此 FormArray 的值。它接受一个与该控件的结构相匹配的数组,并尽量把它们的值匹配到组中正确的控件上。patchValue(value: any[], options: { onlySelf?: boolean; emitEvent?: boolean; } = {}): void
reset():重置这个 FormArray,把它的各级子控件都标记为 pristine 和 untouched,并把它们的值都设置为 null。
getRawValue():这个 FormArray 的聚合值,包括所有已禁用的控件。
clear():移除表单里边的所有控件
Chrome浏览器不支持字体小于12px的解决办法
transform:scale()
-webkit-transform:scale(0.833);
/*这个数字0.833,是缩放比例,可以根据你自己的情况不同而不同。*/
Chrome禁用自动填充
<input type="password" matInput autocomplete="new-password" formControlName="password">
autocomplete="new-username"
autocomplete="new-password"
特性
Cookie
localStorage
sessionStorage
数据的生命期
可设置失效时间,默认是关闭浏览器后失效
除非被清除,否则永久保存
仅在当前会话下有效,关闭页面或浏览器后被清除
存放数据大小
4K左右
一般为5MB
一般为5MB
与服务器端通信
每次都会携带在HTTP头中,如果使用cookie保存过多数据会带来性能问题
仅在客户端(即浏览器)中保存,不参与和服务器的通信
仅在客户端(即浏览器)中保存,不参与和服务器的通信
易用性
需要程序员自己封装,源生的Cookie接口不友好
源生接口可以接受,亦可再次封装来对Object和Array有更好的支持
源生接口可以接受,亦可再次封装来对Object和Array有更好的支持
require与import的区别
-
require支持 动态导入,import不支持,正在提案 (babel 下可支持) -
require是 同步 导入,import属于 异步 导入 -
require是 值拷贝,导出值变化不会影响导入值;import指向 内存地址,导入值会随导出值而变化
Web Worker 使用教程
www.ruanyifeng.com/blog/2018/0…
vue
V-model的原理是什么?
Vue的双向数据绑定是由数据劫持结合发布者订阅者实现的。 数据劫持是通过Object.defineProperty()来劫持对象数据的setter和getter操作。 在数据变动时作你想做的事
原理 通过Observer来监听自己的model数据变化,通过Compile来解析编译模板指令,最终利用Watcher搭起Observer和Compile之间的通信桥梁,达到数据变化->视图更新 在初始化vue实例时,遍历data这个对象,给每一个键值对利用Object.definedProperty对data的键值对新增get和set方法,利用了事件监听DOM的机制,让视图去改变数据
vuex的流程
页面通过mapAction异步提交事件到action。action通过commit把对应参数同步提交到mutation。 mutation会修改state中对于的值。 最后通过getter把对应值跑出去,在页面的计算属性中 通过mapGetter来动态获取state中的值
vuex有哪几种状态和属性
state中保存着共有数据,数据是响应式的 getter可以对state进行计算操作,主要用来过滤一些数据,可以在多组件之间复用 mutations定义的方法动态修改state中的数据,通过commit提交方法,方法必须是同步的 actions将mutations里面处理数据的方法变成异步的,就是异步操作数据,通store.dispatch来分发actions,把异步的方法写在actions中,通过commit提交mutations,进行修改数据。 modules:模块化vuex
Angular
1.RouteReuseStrategy路由复用策略
只能依赖注入到根模块,进行路由配置后,可存储对应组件
shouldDetach 是否允许复用路由
store 当路由离开时会触发,存储路由
shouldAttach 是否允许还原路由
retrieve 获取存储路由
shouldReuseRoute 进入路由触发,是否同一路由时复用路由
//reuse-stategy.ts
import { ActivatedRouteSnapshot, RouteReuseStrategy, DetachedRouteHandle, Router, NavigationEnd } from '@angular/router';
export class CustomReuseStrategy implements RouteReuseStrategy {
public static handlers: { [key: string]: DetachedRouteHandle } = {};
subscribe;
currentUrl;
public static shouldStore = false;
constructor(
) {
}
/** 删除缓存路由快照的方法 */
public static deleteRouteSnapshot(path: string) {
for (const key in CustomReuseStrategy.handlers) {
if (new RegExp(path, 'g').test(key)) {
delete CustomReuseStrategy.handlers[key];
}
}
CustomReuseStrategy.shouldStore = false;
}
/**
* @description: 是否允许复用路由
* @param {type}
* @return:
*/
public shouldDetach(route: ActivatedRouteSnapshot): boolean {
if (!!route.data && !!route.data.reusePath) {
return true;
}
return false;
}
/**
* @description: 当路由离开时会触发,存储路由
* @param {type}
* @return:
*/
public store(route: ActivatedRouteSnapshot, handle: DetachedRouteHandle): void {
if (CustomReuseStrategy.shouldStore) {
CustomReuseStrategy.handlers[route.data.reusePath] = handle;
}
}
/**
* @description: 是否允许还原路由
* @param {type}
* @return:
*/
public shouldAttach(route: ActivatedRouteSnapshot): boolean {
if (!!route.data.reusePath && !!CustomReuseStrategy.handlers[route.data.reusePath]) {
return true;
}
return false;
}
/**
* @description: 获取存储路由
* @param {type}
* @return:
*/
public retrieve(route: ActivatedRouteSnapshot): DetachedRouteHandle {
if (!!route.data && !!route.data.reusePath) {
return CustomReuseStrategy.handlers[route.data.reusePath];
}
return null;
}
/**
* @description: 进入路由触发,是否同一路由时复用路由
* @param {type}
* @return:
*/
public shouldReuseRoute(future: ActivatedRouteSnapshot, curr: ActivatedRouteSnapshot): boolean {
if (future.data && curr.data && future.data.reusePath && curr.data.reusePath) {
return future.data.reusePath === curr.data.reusePath;
}
return false;
}
}
//app.module.ts
import { RouteReuseStrategy, RouterModule } from '@angular/router';
import { CustomReuseStrategy } from './';
providers: [
{provide: RouteReuseStrategy, useClass: CustomReuseStrategy}
],
//路由配置--根/子路由都可
{
path: '', component: TaskListComponent,
data: { reusePath: 'task/list' } //进行路由存储配置
},
//.ts
storerouter(){
CustomReuseStrategy.shouldStore = true; //允许路由存储
}
material UI
1.配置
npm install --save @angular/material @angular/cdk
npm install --save @angular/animations
npm install --save hammerjs
// main.ts
import 'hammerjs';
// style.css
@import "~@angular/material/prebuilt-themes/indigo-pink.css";
/*如果需要md-icon需要引入*/
@import '~https://fonts.googleapis.com/icon?family=Material+Icons';
2.关于选择多个MatAutocompleteTrigger
html
<mat-form-field class="input">
<label matPrefix>类别:</label>
<input matInput formControlName="category" #autoInput [matAutocomplete]="auto" (input)="cateInput($event, 1)"
(click)="openAuto($event, 1)">
<mat-autocomplete #auto="matAutocomplete" (optionSelected)="selectCate($event, 1)">
<mat-option *ngFor="let key of objectKeys(list)" [value]="list[key]">
{{list[key]}}
</mat-option>
</mat-autocomplete>
</mat-form-field>
<mat-form-field class="input">
<label matPrefix>组名:</label>
<input matInput formControlName="groupName" #groupInput [matAutocomplete]="group"
(input)="cateInput($event, 0)" (click)="openAuto($event, 0)">
<mat-autocomplete #group="matAutocomplete" (optionSelected)="selectCate($event, 0)">
<mat-option *ngFor="let key of objectKeys(list)" [value]="key">
{{key}}
</mat-option>
</mat-autocomplete>
</mat-form-field>
TS:
@ViewChild('autoInput', { read: MatAutocompleteTrigger }) auto: MatAutocompleteTrigger;
@ViewChild('groupInput', { read: MatAutocompleteTrigger }) group: MatAutocompleteTrigger;
this.auto.openPanel();
this.group.openPanel();
React
1.setState为异步
constructor() {
super();
this.state = {
count: 1
};
}
//异步
this.setState({count: this.state.count+1}) // 2,3,4,5
console.log(this.state.count); //1,2,3,4
//改为同步
//1)
this.setState({count: this.state.count+1},()=>{
console.log(this.state.count); //2,3,4,5
})
//2)
async increment(){
await this.setStateAsync({count: this.state.count + 1})
console.log(this.state.count); //2,3,4,5
}
setStateAsync(state){
return new Promise(()=>{
this.setState(state, resolve);
});
}