前端的杂谈

JSON语法规则

1:键值对的方式
2:键用双引号引用
3:键值以冒号分割
4:数据以逗号分割

   {
     "name": "Tom",
     "age": 20,
     "isMan": true,
     "list": ["item1", "item2"],
     "obj": {"height": 180, "weight": 90}
   }

对象字面量命名规则

1:键值对的方式
2:键不需要使用双引号引用,但当键包含会导致语法错误的字符时,需加引号
3:键值以冒号分割
4:数据以逗号分割

   let josn = {
     name: "Tom",
     age: 20,
     isMan: true,
     getHeight: function () {},
     "first-name": "Demo",
     list: ["item1", "item2"],
     obj: {"height": 180, "weight": 90}
   }

解构赋值

左右结构尽量一致,不需要可留空处理

数组解构赋值

 let [x, y, [z, i]] = ['this', "is", ['js', 'es6']];
  console.log(x, y, z, i);  //this is js es6

  let [x, y, m, n] = ['this', "is", 'js'];
  console.log(x, y, m, n); //this is js undefined

  let [x, [z, i]] = ['this', "is", ['js', 'es6']];
  console.log(x, z, i); //this i s

  // 留空处理
  let [x, , [z, i]] = ['this', "is", ['js', 'es6']];
  console.log(x, z, i); //this js es6

对象解构赋值

  let {b} = {a: 1, b: 2, c: 3};
  console.log(b); //2

  let person = {
    name: "Tom",
    age: 20,
    list: ["item1", "item2"],
  };
  //isMan可设置默认值
  let {name, age, list: [i1, i2], isMan = true} = person;
  console.log(name, age, i1, i2, isMan);  //Tom 20 item1 item2 true

使用场景

1:交换变量

  let x = 1, y = 2;
  [x, y] = [y, x];
  console.log(x, y); //2 1

2:如果一个函数接收一个对象作为参数,那么,可以使用解构直接把对象的属性绑定到变量中

  age({name: "Tome", age: 20, isMan: true});

  function age({name, age, isMan, height = 180}) {
    console.log(name, age, isMan, height); //Tome 20 true 180
  }

箭头函数规则

1:如果只有一个参数,()括号可以省略
2:如果只有一句return,{}大括号可以省略
3:如果返回对象,必须用()把对象包括起来

注意:箭头函数体中的 this 对象,是定义函数时的对象,而不是使用函数时的对象

   let newArr = [10, 20].map(value => value * 2);
   console.log(newArr[0], newArr[1]); //20 40
 //如果返回对象,可以这样写
  let newArr = [10, 20].map(value => {
    return {
      num: value * 2
    }
  });

  console.log(newArr[0], newArr[1]); //{num: 20} {num: 40}

  //如果返回对象,也可以这样写
  let newArr = [10, 20].map(value => ({num: value * 2}));
  console.log(newArr[0], newArr[1]); //{num: 20} {num: 40}

Object.assign使用

Object.assign(target, …sources)
用于将所有可枚举属性的值从一个或多个源对象复制到目标对象。并返回目标对象

修改原有对象a

  
  let a = {name: 'Tom', age: 20, son: {name: "Jack", age: 5}};
  let b = {age: 25, weight: 90};
  let c = Object.assign(a, b);
  console.log(c); //{name: "Tom", age: 25, son: {name: "Jack", age: 5}, weight: 90}
  console.log(a === c); //true  修改了a这个对象

创建新对象c

  let c = Object.assign({}, a, b);
  console.log(c);//{name: "Tom", age: 25, son: {name: "Jack", age: 5}, weight: 90}
  console.log(c === a); //false  创建了新对象

创建新对象c,并修改原对象a内对象son的值

  let c = Object.assign({}, a, b);
  a.son.age = 3;
  //因为拷贝的是son的引用,所以c对象内son的age也变为了3
  console.log(c);//{name: "Tom", age: 25, son: {name: "Jack", age: 3}, weight: 90}
  console.log(c === a); //false  创建了新对象

注意
通过assign()合并的对象是浅拷贝,假如源对象的属性值是一个对象,那么合并成的这个对象也只是指向了那个对象的引用。深拷贝可以通过:JSON.parse(JSON.stringify(obj))。

map

一对一映射,适合对数组中每个元素做相同的操作

1:对数组map时可传递三个参数,参数1:每个条目、参数2:条目角标、参数3:原始数组
2:必须有return 否则返回undefined
3:map返回一个新数组,原数组不变

传递三个参数

  let arrMap = [1, 3, 5, 7, 9];
  let newArrMap = arrMap.map((item, index, arr) => {
    console.log(value, index, arr);
  });
  console.info(newArrMap); // [undefined, undefined, undefined, undefined, undefined]
  console.log(newArrMap === arrMap); //false

传递两个参数

  let arrMap = [1, 3, 5, 7, 9];
  let newArrMap = arrMap.map((item, index) => item * 2);
  console.info(newArrMap); // [2, 6, 10, 14, 18]
  console.log(newArrMap === arrMap); //false

传递一个参数-不简写

  let arr = [10, 20].map((item) => {
    return item * 2
  });

简写

let arr = [10, 20].map(item => item * 2);

forEach

循环数组

1:对数组forEach时可传递三个参数,参数1:每个条目、参数2:条目角标、参数3:原始数组
2:forEach没有返回值,原数组不变

  let arr = [1, 3, 5, 7, 9];
  let newArr = arr.forEach((item, index, arr) => {
    console.log(item, index, arr);
  });

filter

过滤数组,返回符合条件的新数组

1:对数组filter时可传递三个参数,参数1:每个条目、参数2:条目角标、参数3:原始数组
2:必须通过返回true来过滤返回需要的值,否则不返回(默认返回false)
3:filter返回符合条件的新数组,原数组不变

注意:当条件都不满足时,返回空数组[]、当有条件满足时返回数组带参数

无返回值示例

  let arr = [1, 3, 5, 7, 9];
  let filterArr = arr.filter((item, index, arr) => {
    console.log(item, index, arr);
  });
  console.log(filterArr === arr); //false
  console.log(filterArr); //[] 因为默认返回false 没有满足条件的值,所以返回空数组

有返回值示例

  let arr = [1, 3, 5, 7, 9];
  let filterArr = arr.filter((item, index, arr) => {
    // if (index % 2) return true; //和下边这行效果一样
    return index % 2;
  });

  console.log(filterArr); //[3,7]

find

查找符合条件的值,只要查找到符合条件的就返回符合条件的值

1:对数组find时可传递三个参数,参数1:每个条目、参数2:条目角标、参数3:原始数组
2:必须通过返回true才能停止循环并返回当前值,否则不返回
3:find返回的是数组中的值,原数组不变

注意:当条件都不满足时,返回undefined

  let arr = [1, 3, 5, 7, 9];
  let findArr = arr.find((item, index, arr) => {
    console.log(item);
    if (item > 3) return true
  });
  console.log(findArr); //5

输出结果:

  1
  3
  5
  5

some

用于查找数组中是否有一项满足条件

1:对数组some时可传递三个参数,参数1:每个条目、参数2:条目角标、参数3:原始数组
2:必须通过返回true才能停止循环,并返回true(不返回具体值),否则返回false(默认返回false)
3:some返回的是Boolean值,原数组不变

注意:当条件都不满足时,返回Boolean值false

  let arr = [1, 3, 5, 7, 9];
  let someArr = arr.some((item, index, arr) => {
    console.log(item);
    if (item == 5) {
      return true
    }
  });

  console.log(someArr)

输出结果:

  1
  3
  5
  true

every

用于判断数组中是否每一项都符合条件

1:对数组every时可传递三个参数,参数1:每个条目、参数2:条目角标、参数3:原始数组
2:必须都返回true才能返回true(不返回具体值),否则返回false(默认返回false)停止循环
3:every返回的是Boolean值,原数组不变

  let arr = [1, 3, 5, 7, 9];
  let everyArr = arr.every((value, index, arr) => {
    console.log(value);
    //这里默认返回false,所以只循环一次就停止了
  });
  console.log(everyArr); //false

输出结果:

  1
  false

find、some、every的区别

find:查找到符合条件的值后返回这个值,停止循环
some:查找到符合条件的值后返回true,停止循环
every:每一个条目都符合条件才返回true,只要有条目返回false,则停止循环

fill

填充修改原数组(改变了原始数组)

参数1:将要填充到数组中的值
参数2:可选,填充的起始索引(默认0)
参数3:可选,填充的终止索引(默认数组末端)

  let arr = [1, 3, 5, 7, 9];
  arr.fill(100, 2, 4);
  console.log(arr); //[1, 3, 100, 100, 9]

findIndex

获取指定元素的索引值,没有返回-1

1:对数组findIndex时可传递三个参数,参数1:每个条目、参数2:条目角标、参数3:原始数组
2:必须返回true才能返回当前条目的索引(不返回具体值)并停止循环,否则返回false(默认返回false)
3:findIndex返回的是符合条件的索引值,没有返回-1,原数组不变

  let arr = [1, 3, 5, 7, 9];
  let findIndexArr = arr.findIndex((item, index, arr) => {
    console.log(item);
    if (item == 5) {
      return true;
    } else {
      return false
    }
  });
  console.log(findIndexArr); //2

输出结果:

  1
  3
  5
  2

reduce

arr.reduce(callback(accumulator, currentValue[, currentIndex[, array]])[, initialValue])
reduce接收一个callback回调函数和一个初始值,callback回调函数必需有返回值

callback回调函数接收四个值

  • accumulator:必需 累计器累计回调的返回值
  • currentValue:必需 数组中正在处理的元素
  • currentIndex:可选 数组中正在处理的当前元素的索引。 如果提供了initialValue,则起始索引号为0,否则从索引1起始
  • array 可选 原数组

初始值

  • initialValue:可选 作为第一次调用回调函数时的第一个参数的值。 如果没有提供初始值,则将使用数组中的第一个元素。 在没有初始值的空数组上调用 reduce 将报错

注意

  1. 当数组为空并且没有提供initialValue初始值时,会抛出TypeError Reduce of empty array with no initial value
  2. 当提供initialValue初始值时,回调函数第一次执行时,accumulator取值为initialValue,currentValue取数组中角标为1的值
  3. 当提供initialValue初始值时,如果数组为空,那么此初始值将被返回并且callback不会被执行
  4. 当不提供initialValue值时,回调函数第一次执行时,accumulator取数组中角标为0的值,currentValue取数组中角标为1的值
  5. 当不提供initialValue值时,如果数组中仅一个元素(无论位置如何),那么此唯一值将被返回并且callback不会被执行

建议

  • 提供initialValue初始值,通常更安全

提供默认值

  let arr = [1, 3, 5, 7, 9]
  let num =  arr.reduce((accumulator, currentValue, currentIndex, array)=>{
     return accumulator + currentValue
  }, 0)
  console.log(num) // 25

不提供默认值

  let arr = [1, 3, 5, 7, 9]
  let num =  arr.reduce((accumulator, currentValue, currentIndex, array)=>{
     return accumulator + currentValue
  })
  console.log(num) // 25

数组中只有一个值

  let arr = [];
  arr[10] = 100;
  let num = arr.reduce((accumulator, currentValue, currentIndex, array) => {
      return accumulator + currentValue // 不会执行
    }
  )
  console.log(num); // 100

空数组且不提供initialValue初始值则报错

  let arr = []
  let num = arr.reduce((accumulator, currentValue, currentIndex, array) => {
      return accumulator + currentValue
    }
  )
  console.log(num) // Uncaught TypeError: Reduce of empty array with no initial value

ES6的模块

参考:https://www.runoob.com/w3cnote/es6-module.html

ES6的模块分为导出(export)和导入(import)两个模块

特点

1:ES6模块自动开启严格模式,不管你有没有在模块头部加use strict
2:模块可以导入导出各种类型的变量,如函数、对象、字符串、数组、布尔值、类等
3:每个模块都有自己的上下文,每个模块内声明的变量都是局部变量,不会污染到全局作用域
4:每一个模块只加载一次(单例的),若再去加载同目录下同文件,直接从内存中读取

注意
目前在使用模块的导入导出功能时,需要使用babel转码才能用export和import, 也就是需要把es6转成es5, 建议直接在Vue中使用

export内联导出

模块可以导入导出各种类型的变量,如函数、对象、字符串、数组、布尔值、类等

注意
导出的函数声明与类声明必须要有名称(export default 命令除外)

example.js文件

	export const PI = 3.14;
	export let str = "str";
	export let num = 10;
	
	export function test() {
	  console.log("function:test")
	}
	
	export class MyClass {
	  name = "MyClass"
	}
	
	export let obj = {
	  name: "Jack",
	  age: 25
	};
	export let arr = ["item1", "item2"];
	const people = {name: "Tom"};
	//一个模块只能有一个默认导出
	export default people;

在Vue中通过import导入需要的内容,导入和导出的顺序可以不一致

注意

1:通过export方式导出时,在import时需要加{},而通过export default导出时则不需要
2:不需要使用的变量可以不导入
3:可同时导入通过export和export default导出的内容,若export和export default同时存在则可以用下面两种方式导入
4:可以通过as重新定义导入导出的变量名

vue.js文件

<script>
  import people, {obj, MyClass, arr, test, PI} from './example'; //下边和这个同样效果
  // import {obj, MyClass, arr, test, PI, default as people} from './example';

  export default {
    name: "Demo",
    mounted() {
      console.log(obj.name); //Jack
      console.log(MyClass.name); //MyClass
      console.log(arr[0]); //item1
      test(); //function:test
      console.log(PI); //3.14
      console.log(people.name); //Tom
    }
  }
</script>

export对象导出

建议使用大括号指定所要导出的内容,也就是对象导出

export方式导出

let num = 10;

let obj = {
  name: "Jack",
  age: 25
};
export {num, obj};

在使用导入时(顺序可不一致)

import {obj, num} from './example';

export default方式导出

const obj = {
  name: "Tom",
  run() {
    console.log("run");
  }
};
export default obj;

在使用导入时(不能加花括号{})

import example from './example';

注意:可以通过as重新定义导入导出的变量名

export default命令特点

1:在一个文件或模块中,export、import可以有多个,export default最多只能有一个

export default a;
export default b;  //错误 只能有一个

2:通过export方式导出,在导入时要加{},export default则不需要并且可以使用任意变量接收

export default b;
import xxx from "./xxx.js"; // 不需要加{}, 可使用任意变量接收

3:export default中的default对应的是导出的变量不能是表达式,但export可以直接导出表达式

export default const PI = 3.14; //错误 只能是导出变量,不能是表达式

import命令特点

1:只读属性:不允许在加载模块的脚本里面改写import变量类型为基本类型的变量,也不允许改写接口的引用指向,但可以改写引用指向的属性值

example.js文件

let num = 10;

let obj = {
  name: "Jack",
  age: 25
};
export {num, obj};

vue.js
<script>
  import {obj, num} from './example';
  export default {
    name: "demo",
    mounted() {
      num = 20;  //错误
      obj = {}; //错误
      obj.name = "Jack"; //正确
    }
  }
</script>

2:单例模式:多次重复执行同一句import语句,那么只会执行一次,而不会执行多次。import同一个模块,声明不同变量引用,则会声明对应变量,但只执行一次import

import {a} "./xxx.js";
import {a} "./xxx.js";
//相当于 import {a} "./xxx.js" 了一次

import { a } from "./xxx.js";
import { b } from "./xxx.js";
// 相当于 import { a, b } from "./xxx.js";

3:静态执行特性:import是静态执行,所以不能使用表达式和变量

//错误
import {"f"+"oo"} from "./xxx.js";

//错误
let module = "./xxx.js";
import {foo} from module;

//错误
if(true){
  import {foo} from "./xxx.js";
}else{
  import {foo} from "./xxx.js"
}

splice

向数组中添加或删除元素,然后返回含有被删除元素的数组
注意:这种方法会改变原始数组

语法
array.splice(index,howmany,item1,…,itemX)

参数
index:必需。整数,规定添加/删除项目的位置,使用负数可从数组结尾处规定位置。
howmany:要删除的元素数量。如果设置为 0,则不会删除项目。
如果未设置此参数,则删除从 index 开始到原数组结尾的所有元素。
item1, …, itemX 可选。向数组添加的新元素。

返回值
如果从 array 中删除了元素,则返回的是含有被删除元素的数组

不传参数–原始数组不被修改–这样用没什么意义

  /**
   * 返回一个空数组,并未修改原始数组
   */
   let arr = [1, 3, 5, 7, 9];
   let newArr = arr.splice();
   console.log(arr); //[1, 3, 5, 7, 9]
   console.log(newArr); //[]

传入一个参数–原始数组被修改

  /**
   * 参数1:从哪个角标开始删除之后的所有元素,并返回包含删除元素的数组
   */
   let arr = [1, 3, 5, 7, 9];
   let newArr = arr.splice(2);
   console.log(arr); //[1, 3]
   console.log(newArr); //[5, 7, 9]

传入两个参数–原始数组被修改

  /**
   * 第二个参数传入0就是不删除元素
   * 参数1:从哪个角标开始删除元素
   * 参数2:删除几个元素(传0就是不删除元素)
   * 返回包含删除元素的数组
   */
   let arr = [1, 3, 5, 7, 9];
   let newArr = arr.splice(2, 0);
   console.log(arr); //[1, 3, 5, 7, 9]
   console.log(newArr); //[]
  /**
   * 第二个参数传2就是删除两个元素
   */
   let arr = [1, 3, 5, 7, 9];
   let newArr = arr.splice(2, 2);
   console.log(arr); //[1, 3, 9]
   console.log(newArr); //[5, 7]

只插入元素


/**
 * 只插入元素- 从角标2开始先删除0个元素,并从角标2开始向数组中添加新元素
 * 传入三个参数--原始数组被修改
 * 参数1:从哪个角标开始删除元素
 * 参数2:删除几个元素(传0就是不删除元素)
 * 参数3、4、.....:从参数1的角标开始向数组中添加新元素
 * 返回包含删除元素的数组
 */
 let arr = [1, 3, 5, 7, 9];
 let newArr = arr.splice(2, 0, 10, 20);
 console.log(arr); // [1, 3, 10, 20, 5, 7, 9]
 console.log(newArr); //[]

说明:代表插入元素,从角标2开始先删除0个元素,并用10,20替换那些被删除的元素,即从角标为2元素开始插入10,20两个元素

删除并插入元素

/**
 * 删除并插入元素
 * 传入三个参数--原始数组被修改
 * 参数1:从哪个角标开始删除元素
 * 参数2:删除几个元素(传0就是不删除元素)
 * 参数3、4、.....:从参数1的角标开始向数组中添加新元素
 * 返回包含删除元素的数组
 */
 let arr = [1, 3, 5, 7, 9];
 let newArr = arr.splice(1, 2, 10, 20, 30);
 console.log(arr); // [1, 10, 20, 30, 7,9]
 console.log(newArr); //[3, 5,]

slice

从原数组中返回选定元素的数组
注意:这种方法会不会改变原始数组

语法
array.slice(start,end)

参数
start: 必需。整数,规定从何处开始选取,使用负数可从数组结尾处规定位置
end: 可选。规定从何处结束选取。如果未指定参数,则从start开始一直截取到数组结尾

返回值
返回一个新的数组,包含从start到end(不包含该元素)的array中的元素

  /**
   * 获取新数组,内容从arr的角标3开始一直到结尾的所有元素,
   */
  let arr = [1, 3, 5, 7, 9];
  let newArr = arr.slice(3);
  console.log(arr); // [1, 3, 5, 7, 9]
  console.log(newArr); //[7, 9]
  /**
   * 获取新数组,内容从arr的角标3开始角标4结束(不包含角标4元素)
   */
  let arr = [1, 3, 5, 7, 9];
  let newArr = arr.slice(3, 4);
  console.log(arr); // [1, 3, 5, 7, 9]
  console.log(newArr); //[7]

splice、slice区别

1:splice会修改原数组,slice不会
2:splice可以删除、修改、替换原数组,slice只能截取数组中的值并生成新数组
3:splice可传递多个参数,slice最多只能传递两个参数

判断对象中是否包含某属性

1.1:点运算符
通过 obj.key 或 obj[‘key’] 判断指定的属性在指定 对象和原型链 上是否存在,存在则返回具体值,不存在则返回undefined
可以通过 obj.key !== undefined 判断对象是否包含某属性(记住是全等)
注意:如果某属性值就为undefined,则通过点运算符则无法判断

1.2:in 运算符
通过 “key” in obj 判断指定的属性在指定 对象和原型链 上是否存在,存在则返回true,不存在则返回false
通过in 运算符可以判断某属性值为undefined的情况

1.3:hasOwnProperty() 方法
通过 obj.hasOwnProperty(prop) 方法 判断指定的属性在指定 对象自身身上 是否存在,存在则返回true,不存在则返回false

判断对象是否为空

1.1:通过ES6语法Object.keys
Object.keys() 方法会返回一个由一个给定对象的自身可枚举属性组成的 数组(不包括原型上) ,数组中属性名的排列顺序和使用 for…in 循环遍历该对象时返回的顺序一致,
可通过返回数组的长度来判断对象是否为空

  let obj = {
      name:'liuyz',
      sex:'man',
      age:20
  };
  console.log(Object.keys(obj)); //["name", "sex", "age"]
  console.log(Object.keys(obj).length); //3

1.2:通过 for…in… 遍历属性(包括原型链上)

  function isEmpty(obj) {
      for(let i in obj){
          return true;
      }
      return false;
  }
  console.log(isEmpty(obj)); //true

JS循环遍历对象(包括原型链上)

  for(let i in obj){
      console.log(i + '--' + obj[i]);
  }

JS循环遍历对象(不包括原型链上)

  for (let i in obj) {
      if (obj.hasOwnProperty(i)) {
          console.log(i + "--" + obj[i]);
      }
  }

JS删除对象中某一字段(属性或方法)

  delete obj.sex;
  console.log(obj);

JS删除数组中某一角标

  let arr = ["1", "2", "3"];
  delete arr[1]; //删除数组某一项值,数组长度不变
  console.log(arr);  //["1", empty, "3"]

JS抛出一个异常

 throw new Error('error');

解决div里面img图片下方有空白的问题

# 产生空白的原因

img标签是行内块元素即默认是:display: inline-block,且行内块元素的默认对齐方式是基线对齐即vertical-align: baseline
所以产生空白的原因是因图片底边与容器基线对齐了,留出了基线与底线的空白
在这里插入图片描述
在这里插入图片描述

# 解决空白方法

  <div class="pic-container">
      <img class="pic" src="~images/img1.jpg" alt="">
      <img class="pic" src="~images/img2.jpg" alt="">
  </div>

1.1:把图片父容器设置为flex布局

  .pic-container {
      width: 100%;
      display: flex;
      flex-direction: column;
      .pic {
          width: 100%;
      }
  }

1.2:把图片变成块状元素

  .pic-container {
      .pic {
          display: block; //inline-block不可以
          width: 100%;
      }
  }

1.3:设置图片的vertical-align
修改为vertical-align: middle使其相对容器中部对齐即居中对齐,这样图片就会充满整个容器

  .pic-container{
      .pic{
          vertical-align: middle;
          width: 100%;
      }
  }

1.4:把图片父容器行高置为 0

  .pic-container {
      line-height: 0;
      .pic {
          width: 100%;
      }
  }

1.5:把图片父容器文字大小置为 0

  .pic-container {
      font-size: 0;
      .pic {
          width: 100%;
      }
  }

background-size中cover和contain属性

cover:把背景图片扩展至足够大,以使背景图像完全覆盖背景区域。背景图片的某些部分也许无法显示在背景定位区域中
contain: 把图像扩展至最大尺寸,以使其宽度和高度完全适应内容区域
参考 CSS background-size 参考手册

nth-child(n)

选择器匹配属于其父元素的第 n 个子元素,不论元素的类型(第一个子元素的下标是 1)
如:p:nth-child(2) 匹配父元素的第二个子元素,并且第二个子元素是p标签,若不是则匹配失败
如::nth-child(5) 匹配父元素的第五个子元素,无论类型

1.1:Odd 和 even 是可用于匹配下标是奇数或偶数的子元素的关键词(第一个子元素的下标是 1)
在这里,我们为奇数和偶数 p 元素指定两种不同的背景色:

  p:nth-child(odd) {  /*也可使用类名 如: .class:nth-child(){}*/
      background: #ff0000;

  p:nth-child(even) {
      background: #0000ff;
  }

1.2:使用公式 (an + b)。描述:表示周期的长度,n 是计数器(从 0 开始,子元素下标从 1 开始),b 是偏移值
在这里,我们指定了下标是 3 的倍数的所有 p 元素的背景色

  p:nth-child(3n+0){
      background:#ff0000;
  }

nth-of-type(n)

选择器匹配属于其父元素的 特定类型 的第 n 个子元素
如:p:nth-of-type(2) 匹配父元素内第二个 P 元素,如

 <h1>这是标题</h1>
 <p>第一个段落</p>
 <p>第二个段落</p>  //被选中,因为是特定类型下的第 n 个子元素
 <p>第三个段落</p>

1.1:Odd 和 even 是可用于匹配下标是奇数或偶数的子元素的关键词(第一个子元素的下标是 1)。
在这里,我们为奇数和偶数 p 元素指定两种不同的背景色:

  p:nth-of-type(odd){
      background:#ff0000;
  }
  p:nth-of-type(even){
      background:#0000ff;
  }

1.2:使用公式 (an + b)。描述:表示周期的长度,n 是计数器(从 0 开始),b 是偏移值。

在这里,我们指定了下标是 3 的倍数的所有 p 元素的背景色:

  p:nth-of-type(3n+0){
      background:#ff0000;
  }

参考 CSS 选择器参考手册

nth-child 和 nth-of-type 区别

nth-child:不区分类型,匹配的是其父元素内的第 n 个子元素(子元素下标从1开始)
nth-of-type:区分类型,匹配的是其父元素内 特定类型 的第 n 个子元素(子元素下标从1开始)

this.$route和this.$router区别

this.$route:路由信息对象,包含当前路由的name、params、path、query等属性
this.$router:等同于全局路由实例对象,因为在 Vue 实例内部,可通过 this.$router 访问路由实例,用于路由跳转
如图:
在这里插入图片描述

Vue给对象添加属性

vm.$set( target, propertyName/index, value )
this.$set(obj, 'propertyName', 'lucy')

Vue删除对象属性

vm.$delete( target, propertyName/index )
this.$delete(obj, 'propertyName')

Vue操作数组数据

  this.list.unshift({name: "宙斯"}) //添加到数组头部
  this.list.push({name: "宙斯"}) //添加到数组尾部

  this.list.shift() //删除数组头部一个元素
  this.list.pop() //删除数组尾部一个元素

  this.$set(this.list, 0, {name:"宙斯"}); //修改数组角标为0的数据

发送网络请求时注意事项

1.1:当字段值是undefined时,在请求时如post中不会出现该字段

  id: undefined; //不会出现在请求携带的参数中

1.2:当字段值是""时,在请求时如post中会出现该字段

  id: ""; //在请求携带的中会出现

CSS 盒子模型(Box Model)

CSS盒模型本质上是一个盒子,它包括:边距margin、边框border、填充padding、实际内容content。

1.1:盒模型有两种

  • 标准盒模型:width和height等于实际内容(content)的宽高
  • IE盒模型,width和height等于content+padding+border的总宽高。

1.2:css设置两种盒模型

  • box-sizing: content-box; //标准盒模型
  • box-sizing: border-box; //IE盒模型

绝对定位元素不设置偏移属性

如果绝对元素不设置偏移属性,则他的位置原地不动,但完全脱离文档流,并覆盖默认文档流中的元素

作用:
比如一个悬浮框想在一个列表下方根据状态显示或隐藏,但列表高度不固定,则使用绝对定位但不设置偏移属性最合适。
如果想让悬浮框在列表下方右边显示怎么做?
可以只添加一个属性 right: 0; 则悬浮框就会出现在列表下方右边。

ES6中let、const和var的区别

  • var: 函数作用域、变量会提升、根级变量会挂载到window

  • let: 块级作用域、不会变量提升、根级变量会挂载到window、同一作用域内不能重复定义同名变量、有暂时性死区

  • const: 和let一样,不同的是声明后必须赋值,赋值后不能修改

    暂时性死区

  var a = 1;
  if (true) {
      a = 2; // ReferenceError
      let a;
  }
  • 如果块级作用域中有let或const声明的变量,则该变量就会绑定这个块级作用域,作用域内的该变量不会提升,但它已经存在,只是声明之后才可使用,这被称为暂时性死区。并且作用域内该变量也不受外部变量影响
  • 如果块级作用域内查找不到存在的变量,则还是会向外层作用域查找

暂时性死区 让typeof不再绝对安全

  if (true) {
      console.log(typeof a); // ReferenceError
      let a = 1;
  }

事件捕获、冒泡,事件委托

事件捕获:从document开始触发事件一层一层传递并触发事件,直到当前元素事件触发为止
事件冒泡:从当前元素触发事件并向上级一层一层传递并触发事件,直到document为止
事件委托:基于事件冒泡实现,通过父元素来监听子元素冒泡上来的事件

通过 addEventListener() 的第三个属性设置事件类型,true:表示事件捕获、false:表示事件冒泡,默认为false
阻止事件冒泡:event.stopPropagation()
阻止事件默认行为:event.preventDefault()

数组去重

1:使用数组filter和indexOf方法

  let arr = [1, 2, 3, 2, 4, 5, 3];
  let newArr = arr.filter((item, index, arr) =>{
      return arr.indexOf(item) === index;
  });
  console.log(newArr); //[1, 2, 3, 4, 5]

2:使用ES6的Set (元素唯一特性)

  let arr = [1, 2, 3, 2, 4, 5, 3];
  let set = new Set(arr);
  let newArr = [...set];
  console.log(newArr); //[1, 2, 3, 4, 5]

Set与Array转换

1:Set转Array

  let arr = [1, 2, 3];
  let set = new Set(arr);
  let newArr = [...set];

或者

  let arr = [1, 2, 3];
  let set = new Set(arr);
  let newArr = Array.from(set);

from说明
Array.from() 方法从一个类似数组或可迭代对象创建一个新的,浅拷贝的数组实例
2:Array转Set

  let arr = [1, 2, 3];
  let set = new Set(arr);

图片加载前占位

  <div class="wrapper">
      <img class="img"
           src="http://mp-piao-admincp.qunarzz.com/mp_piao_admin_mp_piao_admin/admin/20192/c64e6f7308f67f0862adb64b9d9fcff0.jpg_750x200_37c4c320.jpg"
           ref="img"
           @load="loadSuccess">
  </div>

  .wrapper {
    height: 0;
    padding-bottom: 26%;
    overflow: hidden;
    background-color: #eee;
    .img {
        width: 100%;
    }
  }

  • 1:各个banner图片宽高比一致
  • 2:给img父元素高度设置为0,通过padding-bottom撑开其父元素

如上方img标签内src的链接图片,它的 宽 x 高= 750 x 200宽高比约等于10 : 2.6
所以img父元素通过 padding-bottom:26% 来占位高度

提示
padding和margin的百分比是 基于其父元素的宽度的百分比的内边距,也就是基于其父元素的内容宽度,不包括父元素的padding、border、margin的宽度。

var a=b=1 和 var a=1,b=1 区别

  function test(ab = 1) {
      var a = b = 1
      let a1 = b1 = 1
      const a2 = b2 = 1
  
      var a3 = 1, b3 = 1
      let a4 = 1, b4 = 1
      const a5 = 1, b5 = 1
  }
  
  test()
  console.log(b, b1, b2) //1 1 1
  console.log(window)
  // console.log(a) //报错 Uncaught ReferenceError: a is not defined
  // console.log(ab) //报错 Uncaught ReferenceError: ab is not defined

window对象
在这里插入图片描述
由打印的window对象图可知,调用test函数后会给window也就是全局添加b、b1、b2三个全局变量,其他变量如:ab(形参)、a、a3、b3等都属于test函数的局部变量,不能在全局访问

Object.freeze冻结

如果确定data中的数据不会发生变化如(对象、数组、Number、Boolean、String),那么可以使用Object.freeze冻结数据,使Vue不对该数据设置响应式监听,以便提高性能
Object.freeze的原理就是把数据上值的这三个属性 configurable、enumerable、writable都设置为false。以便对数据不可配置、不可枚举、不可修改

注意

  1. Object.freeze一般只冻结引用数据,也就是堆内存中的数据
  2. 当冻结Number、Boolean、String时,数据也变成非响应式的,但当重新赋值时,就又会变成响应式

data中的冻结数据

	obj:Object.freeze({
          num:1
        }),
    arr:Object.freeze([1,2,3]),

此时通过下面这种方式都无法修改数据

    this.obj.num = 30;
    this.$set(this.arr, 1, 20)

但可以通过修改obj和arr的引用来修改数

    this.obj = Object.freeze({
          num:40
        }),
    this.arr = Object.freeze([10,20,30])

也可以再变成响应式对象

     this.obj = {
       num: 100,
     }
     this.arr = [100, 200, 300]
    

vueRouter的params、query传参 动态路由匹配 动态路径参数

通过params传递参数

命名路由 userId不会出现在url上

 this.$router.push({ name: 'user', params: { userId: '123' }})

获取传递的参数

 this.$route.params.userId
  • 只能使用name,不能使用path,因为使用path后params会被忽略
  • 参数不会显示在路径上
  • 浏览器强制刷新参数会被清空
    注意:name的值是在router路由里定义的name值,而不是组件中定义的name值

通过query传递参数

带查询参数,变成 /register?plan=private

this.$router.push({name:'register',query:{ plan: 'private' }})

带查询参数,变成 /register?plan=private

  this.$router.push({ path: '/register', query: { plan: 'private' }})

获取参数

 this.$route.query.plan
  • 可以使用name,也可以使用path
  • 参数会显示在路径上
  • 浏览器强制刷新参数不会丢失

动态路由匹配

记住: 参数或查询的改变并不会触发进入/离开的导航守卫
动态路径参数 以冒号开头,如 { path: ‘/user/:id’, component: xxx },使用动态路径参数可以达到动态路由匹配的效果
通过 /:id 的这种动态路由匹配时,当匹配到一个路由时,参数值通过 this.$route.params.id 获取到
当使用路由参数时,例如从 /user/foo 导航到 /user/bar,原来的组件实例会被复用。因为两个路由都渲染同个组件,比起销毁再创建,复用则显得更加高效。不过,这也意味着组件的生命周期钩子不会再被调用
复用组件时,想对路由参数的变化作出响应的话,你可以简单地 watch (监测变化) $route 对象:

  watch: {
    '$route' (to, from) {
      // 对路由变化作出响应...
    }
  }

或者使用 2.2 中引入的 beforeRouteUpdate 导航守卫:

   beforeRouteUpdate (to, from, next) {
    // react to route changes...
    // don't forget to call next() 不要忘记调用next
  }

动态路径参数的跳转方法

如:

{ path: '/user/:userId', component: xxx }

1:命名路由跳转

 this.$router.push({name: 'user',params: { userId: 123, sex:'man' }})  //匹配为/user/123

params中userId必须和上面路径中的 userId(/user/:userId)名一直,userId位置随意,还可以传递其他参数

2:带查询参数跳转

this.$router.push({path: '/user/123',query: { sex: 'man' }}) //匹配为 /user/123?sex=max

path路径格式和路由里定义的一样,:userId匹配123,同时路径上会添加sex=man属性

函数中返回字面量对象

	function test(age){
		return {
			name:"liu"
		}
	}
	let obj1 =	test(10)
	obj1.name = 'y'
	let obj2 = test(20)
	obj2.name = 'z'

	console.log(obj1 == obj2) // false
	console.log(obj1) // {name: "y"}
	console.log(obj2) // {name: "2"}

说明:函数中返回字面量对象时,每一次调用都会创建返回一个新的对象

数组内String转Number

	let arr = ['3', '21', 10, 40, '22','', null, undefined]
	let numberArr = Array.from(arr, n => n - 0)
	console.log(numberArr)
	// 打印结果:	[3, 21, 10, 40, 22, 0, 0, NaN]

数组内Number转String

	let arr = ['3', '21', 10, 40, '22','', null, undefined]
	let stringArr = Array.from(arr, n => n + '')
	console.log(stringArr)
	// 打印结果:	["3", "21", "10", "40", "22", "", "null", "undefined"]

package.json中符合说明

一个完整的版本号组表示为: [主要版本号,次要版本号,补丁版本号]

波浪符号(~):主要版本和次要版本号不变,只会自动更新补丁版本号。如"element-ui": “~2.5.2” ,只会自动更新到2.5.x的最新版本,即2.5.2<=element-ui版本号<2.6.0

插入符号(^):主要版本号不变,会自动更新次要版本号和补丁版本号。如"element-ui": "^2.5.2"只会自动更新到2.x.x的最新版本,即2.5.2<=element-ui版本号<3.0.0

对象深克隆

  function deepClone(obj) {
    //判断深拷贝的是数组还是对象
    var objClone = Array.isArray(obj) ? [] : {};
    //进行深拷贝的不能为空,并且是对象或者是数组
    if (obj && typeof obj === "object") {
      for (key in obj) {
        if (obj.hasOwnProperty(key)) {
          if (obj[key] && typeof obj[key] === "object") {
            objClone[key] = deepClone(obj[key]);
          } else {
            objClone[key] = obj[key];
          }
        }
      }
    }
    return objClone;
 }

多维数组打平

 function flattenMd(arr){
    var result=[]
    function flatten(arr){
        for (var i = 0; i < arr.length; i++) {
            if (Array.isArray(arr[i])) {
                flatten(arr[i]);
            }else{
                result.push(arr[i]);
            }
        }
    }
    flatten(arr);
    return result;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值