附上学习路径图
JavaScript的数据类型
undefined、Null、Boolean、String、Number、Symbol、BigInt为基础类型;
Object为引用类型,其中包括Array、RegExp、Date、Math、Function这几种常见的类型。
数据类型检测
-
第一种检测方法:typeof
typeof 1 // 'number'
typeof '1' // 'string'
typeof undefined // 'undefined'
typeof true // 'boolean'
typeof Symbol() // 'symbol'
typeof null // 'object'
typeof [] // 'object'
typeof {} // 'object'
typeof console // 'object'
typeof console.log // 'function'
-
第二种检测方法:instanceof
我们 new 一个对象,那么这个新对象就是它原型链继承上面的对象了,通过 instanceof我们能判断这个对象是否是之前那个构造函数生成的对象,这样就基本可以判断出这个新对象的数据类型。
let Car = function() {}
let benz = new Car();
benz instanceof Car; // true
let car = new String('maomin');
car instanceof String; // true
let str = 'haojie';
str instanceof String; // false
-
第三种检测方法:Object.prototype.toString
toString() 是 Object 的原型方法,调用该方法,可以统一返回格式为 “[object Xxx]” 的字符串,其中 Xxx就是对象的类型,第一个首字母要大写。对于 Object 对象,直接调用 toString()就能返回"[object Object]";而对于其他对象,则需要通过call来调用,才能返回正确的类型信息。
Object.prototype.toString({}) // "[object Object]"
Object.prototype.toString.call({}) // 同上结果,加上call也ok
Object.prototype.toString.call(1) // "[object Number]"
Object.prototype.toString.call('1') // "[object String]"
Object.prototype.toString.call(true) // "[object Boolean]"
Object.prototype.toString.call(function(){}) // "[object Function]"
Object.prototype.toString.call(null) //"[object Null]"
Object.prototype.toString.call(undefined) //"[object Undefined]"
Object.prototype.toString.call(/123/g) //"[object RegExp]"
Object.prototype.toString.call(new Date()) //"[object Date]"
Object.prototype.toString.call([]) //"[object Array]"
Object.prototype.toString.call(document) //"[object HTMLDocument]"
Object.prototype.toString.call(window) //"[object Window]"
实现一个数据类型检测方法
function getType(obj){
let type = typeof obj;
if (type !== "object") { // 先进行typeof判断,如果是基础数据类型,直接返回
return type;
}
// 对于typeof返回结果是object的,再进行如下的判断,正则返回结果
return Object.prototype.toString.call(obj).replace(/^\[object (\S+)\]$/, '$1'); // 注意正则中间有个空格
}
/* 代码验证,需要注意大小写,哪些是typeof判断,哪些是toString判断?思考下 */
getType([]) // "Array" typeof []是object,因此toString返回
getType('123') // "string" typeof 直接返回
getType(window) // "Window" toString返回
getType(null) // "Null"首字母大写,typeof null是object,需toString来判断
getType(undefined) // "undefined" typeof 直接返回
getType() // "undefined" typeof 直接返回
getType(function(){}) // "function" typeof能判断,因此首字母小写
getType(/123/g) //"RegExp" toString返回
字符串操作方法:
1. charAt()
charAt()方法可用来获取指定位置的字符串,index为字符串索引值,从0开始到string.leng – 1,若不在这个范围将返回一个空字符串。
let str = 'abcde';
console.log(str.charAt(2)); //返回c
console.log(str.charAt(8)); //返回空字符串
2. charCodeAt()
charCodeAt()方法可返回指定位置的字符的Unicode编码。charCodeAt()方法与charAt()方法类似,都需要传入一个索引值作为参数,区别是前者返回指定位置的字符的编码,而后者返回的是字符子串。
let str = 'abcde';
console.log(str.charCodeAt(0)); //返回97
3. fromCharCode()
fromCharCode()可接受一个或多个Unicode值,然后返回一个字符串。另外该方法是String 的静态方法,字符串中的每个字符都由单独的数字Unicode编码指定。
String.fromCharCode(97, 98, 99, 100, 101) //返回abcde
4. indexOf()
indexOf(searchvalue,fromindex)用来检索指定的字符串值在字符串中首次出现的位置。它可以接收两个参数,searchvalue表示要查找的子字符串,fromindex表示查找的开始位置,省略的话则从开始位置进行检索。
let str = 'abcdeabcde';
console.log(str.indexOf('a')); // 返回0
console.log(str.indexOf('a', 3)); // 返回5
console.log(str.indexOf('bc')); // 返回1
5. lastIndexOf()
lastIndexOf()语法与indexOf()类似,它返回的是一个指定的子字符串值最后出现的位置,其检索顺序是从后向前。
let str = 'abcdeabcde';
console.log(str.lastIndexOf('a')); // 返回5
console.log(str.lastIndexOf('a', 3)); // 返回0 从第索引3的位置往前检索
console.log(str.lastIndexOf('bc')); // 返回6
6. search()
stringObject.search(substr)
stringObject.search(regexp)
search()方法用于检索字符串中指定的子字符串,或检索与正则表达式相匹配的子字符串。它会返回第一个匹配的子字符串的起始位置,如果没有匹配的,则返回-1。
let str = 'abcDEF';
console.log(str.search('c')); //返回2
console.log(str.search('d')); //返回-1
console.log(str.search(/d/i)); //返回3
7. match()
stringObject.match(substr)
stringObject.match(regexp)
match()方法可在字符串内检索指定的值,或找到一个或多个正则表达式的匹配。
如果参数中传入的是子字符串或是没有进行全局匹配的正则表达式,那么match()方法会从开始位置执行一次匹配,如果没有匹配到结果,则返回null。否则则会返回一个数组,该数组的第0个元素存放的是匹配文本,除此之外,返回的数组还含有两个对象属性index和input,分别表示匹配文本的起始字符索引和stringObject 的引用(即原字符串)。
let str = '1a2b3c4d5e';
console.log(str.match('h')); //返回null
console.log(str.match('b')); //返回["b", index: 3, input: "1a2b3c4d5e"]
console.log(str.match(/b/)); //返回["b", index: 3, input: "1a2b3c4d5e"]
如果参数传入的是具有全局匹配的正则表达式,那么match()从开始位置进行多次匹配,直到最后。如果没有匹配到结果,则返回null。否则则会返回一个数组,数组中存放所有符合要求的子字符串,并且没有index和input属性。
let str = '1a2b3c4d5e';
console.log(str.match(/h/g)); //返回null
console.log(str.match(/\d/g)); //返回["1", "2", "3", "4", "5"]
8. substring()
stringObject.substring(start,end)
substring()是最常用到的字符串截取方法,它可以接收两个参数(参数不能为负值),分别是要截取的开始位置和结束位置,它将返回一个新的字符串,其内容是从start处到end-1处的所有字符。若结束参数(end)省略,则表示从start位置一直截取到最后。
let str = 'abcdefg';
console.log(str.substring(1, 4)); //返回bcd
console.log(str.substring(1)); //返回bcdefg
console.log(str.substring(-1)); //返回abcdefg,传入负值时会视为0
9. substring()
stringObject.slice(start,end)
slice()方法与substring()方法非常类似,它传入的两个参数也分别对应着开始位置和结束位置。而区别在于,slice()中的参数可以为负值,如果参数是负数,则该参数规定的是从字符串的尾部开始算起的位置。也就是说,-1 指字符串的最后一个字符。
let str = 'abcdefg';
console.log(str.slice(1, 4)); //返回bcd
console.log(str.slice(-3, -1)); //返回ef
console.log(str.slice(1, -1)); //返回bcdef
console.log(str.slice(-1, -3)); //返回空字符串,若传入的参数有问题,则返回空
10. substr()
stringObject.substr(start,length)
substr()方法可在字符串中抽取从start下标开始的指定数目的字符。其返回值为一个字符串,包含从 stringObject的start(包括start所指的字符)处开始的length个字符。如果没有指定 length,那么返回的字符串包含从start到stringObject的结尾的字符。另外如果start为负数,则表示从字符串尾部开始算起。
var str = 'abcdefg';
console.log(str.substr(1, 3)) //返回bcd
console.log(str.substr(2)) //返回cdefg
console.log(str.substr(-2, 4)) //返回fg,目标长度较大的话,以实际截取的长度为准
11. replace()
stringObject.replace(regexp/substr,replacement)
replace()方法用来进行字符串替换操作,它可以接收两个参数,前者为被替换的子字符串(可以是正则),后者为用来替换的文本。 如果第一个参数传入的是子字符串或是没有进行全局匹配的正则表达式,那么replace()方法将只进行一次替换(即替换最前面的),返回经过一次替换后的结果字符串。
let str = 'abcdeabcde';
console.log(str.replace('a', 'A')); // 返回Abcdeabcde
console.log(str.replace(/a/, 'A')); // 返回Abcdeabcde
如果第一个参数传入的全局匹配的正则表达式,那么replace()将会对符合条件的子字符串进行多次替换,最后返回经过多次替换的结果字符串。
var str = 'abcdeabcdeABCDE';
console.log(str.replace(/a/g, 'A')); //返回AbcdeAbcdeABCDE
console.log(str.replace(/a/gi, '$')); //返回$bcde$bcde$BCDE
12. split()
stringObject.split(separator,howmany)
split()方法用于把一个字符串分割成字符串数组。第一个参数separator表示分割位置(参考符),第二个参数howmany表示返回数组的允许最大长度(一般情况下不设置)。
let str = 'a|b|c|d|e';
console.log(str.split('|')); //返回["a", "b", "c", "d", "e"]
console.log(str.split('|', 3)); //返回["a", "b", "c"]
console.log(str.split('')); //返回["a", "|", "b", "|", "c", "|", "d", "|", "e"]
也可以用正则来进行分割
let str = 'a1b2c3d4e';
console.log(str.split(/\d/)); //返回["a", "b", "c", "d", "e"]
13. toLowerCase()和toUpperCase()
stringObject.toLowerCase() stringObject.toUpperCase()
toLowerCase()方法可以把字符串中的大写字母转换为小写,toUpperCase()方法可以把字符串中的小写字母转换为大写。
let str = 'JavaScript';
console.log(str.toLowerCase()); //返回javascript
console.log(str.toUpperCase()); //返回JAVASCRIPT
数组操作方法:
1. ES6 Array.of()
Array.of() 方法创建一个具有可变数量参数的新数组实例,而不考虑参数的数量或类型。
Array.of() 和 Array 构造函数之间的区别在于处理整数参数:Array.of(7) 创建一个具有单个元素 7 的数组,而 Array(7) 创建一个长度为7的空数组(注意:这是指一个有7个空位(empty)的数组,而不是由7个undefined组成的数组)。
Array.of(7); // [7]
Array.of(1, 2, 3); // [1, 2, 3]
Array(7); // [ , , , , , , ]
Array(1, 2, 3); // [1, 2, 3]
2. ES6 Array.from()
Array.from() 方法从一个类似数组或可迭代对象创建一个新的,浅拷贝的数组实例。
Array.from('foo') // ['f', 'o', 'o']
Array.from([1, 2, 3], x => x + x) // [2, 4, 6]
3. ES6 find()
find() 方法返回数组中满足提供的测试函数的第一个元素的值。否则返回 undefined。
const array1 = [5, 12, 8, 130, 44];
const found = array1.find(element => element > 10);
console.log(found); // expected output: 12
4. ES6 findIndex()
findIndex()方法返回数组中满足提供的测试函数的第一个元素的索引。若没有找到对应元素则返回-1。
const array1 = [5, 12, 8, 130, 44];
const isLargeNumber = (element) => element > 13;
console.log(array1.findIndex(isLargeNumber)); // expected output: 3
5. ES6 fill()
fill() 方法用一个固定值填充一个数组中从起始索引到终止索引内的全部元素。不包括终止索引。
const array1 = [1, 2, 3, 4];
// fill with 0 from position 2 until position 4
console.log(array1.fill(0, 2, 4));
// expected output: [1, 2, 0, 0]
// fill with 5 from position 1
console.log(array1.fill(5, 1));
// expected output: [1, 5, 5, 5]
console.log(array1.fill(6));
// expected output: [6, 6, 6, 6]
6. ES6 includes()
includes() 方法用来判断一个数组是否包含一个指定的值,根据情况,如果包含则返回 true,否则返回false。
const array1 = [1, 2, 3];
console.log(array1.includes(2)); // expected output: true
const pets = ['cat', 'dog', 'bat'];
console.log(pets.includes('cat')); // expected output: true
console.log(pets.includes('at')); // expected output: false
7. concat()
concat() 方法用于连接两个或多个数组。该方法不会改变现有的数组,仅会返回被连接数组的一个副本。
let arr1 = [1, 2, 3];
let arr2 = [4, 5];
let arr3 = arr1.concat(arr2)
console.log(arr1) // [1, 2, 3]
console.log(arr3) // [1, 2, 3 , 4, 5]
8. join()
join() 方法用于把数组中的所有元素放入一个字符串。元素是通过指定的分隔符进行分隔的,默认使用’,'号分割,不改变原数组。
let arr = [2, 3, 4];
console.log(arr.join()); // 2, 3, 4
9. push()
push() 方法可向数组的末尾添加一个或多个元素,并返回新的长度。末尾添加,返回的是长度,会改变原数组。
const animals = ['pigs', 'goats', 'sheep'];
const count = animals.push('cows');
console.log(count);
// expected output: 4
console.log(animals);
// expected output: Array ["pigs", "goats", "sheep", "cows"]
animals.push('chickens', 'cats', 'dogs');
console.log(animals);
// expected output: Array ["pigs", "goats", "sheep", "cows", "chickens", "cats", "dogs"]
10. pop()
pop() 方法用于删除并返回数组的最后一个元素。返回最后一个元素,会改变原数组。
const plants = ['broccoli', 'cauliflower', 'cabbage', 'kale', 'tomato'];
console.log(plants.pop());
// expected output: "tomato"
console.log(plants);
// expected output: Array ["broccoli", "cauliflower", "cabbage", "kale"]
plants.pop();
console.log(plants);
// expected output: Array ["broccoli", "cauliflower", "cabbage"]
11. shift()
shift() 方法用于把数组的第一个元素从其中删除,并返回第一个元素的值。返回第一个元素,改变原数组。
const array1 = [1, 2, 3];
const firstElement = array1.shift();
console.log(array1);
// expected output: Array [2, 3]
console.log(firstElement);
// expected output: 1
12. unshift()
unshift() 方法可向数组的开头添加一个或更多元素,并返回新的长度。返回新长度,改变原数组。
const array1 = [1, 2, 3];
console.log(array1.unshift(4, 5));
// expected output: 5
console.log(array1);
// expected output: Array [4, 5, 1, 2, 3]
13. slice()
返回一个新的数组,包含从 start 到 end (不包括该元素)的 arrayObject 中的元素。返回选定的元素,该方法不会修改原数组。
const animals = ['ant', 'bison', 'camel', 'duck', 'elephant'];
console.log(animals.slice(2));
// expected output: Array ["camel", "duck", "elephant"]
console.log(animals.slice(2, 4));
// expected output: Array ["camel", "duck"]
console.log(animals.slice(1, 5));
// expected output: Array ["bison", "camel", "duck", "elephant"]
14. splice()
splice() 方法可删除从 index 处开始的零个或多个元素,并且用参数列表中声明的一个或多个值来替换那些被删除的元素。如果从 arrayObject 中删除了元素,则返回的是含有被删除的元素的数组。splice() 方法会直接对数组进行修改。
const months = ['Jan', 'March', 'April', 'June'];
months.splice(1, 0, 'Feb');
// inserts at index 1
console.log(months);
// expected output: Array ["Jan", "Feb", "March", "April", "June"]
months.splice(4, 1, 'May');
// replaces 1 element at index 4
console.log(months);
// expected output: Array ["Jan", "Feb", "March", "April", "May"]
15. sort()
按照 Unicode code 位置排序,默认升序
const months = ['March', 'Jan', 'Feb', 'Dec'];
months.sort();
console.log(months);
// expected output: Array ["Dec", "Feb", "Jan", "March"]
const array1 = [1, 30, 4, 21, 100000];
array1.sort();
console.log(array1);
// expected output: Array [1, 100000, 21, 30, 4]
16. reverse()
reverse() 方法用于颠倒数组中元素的顺序。返回的是颠倒后的数组,会改变原数组。
const array1 = ['one', 'two', 'three'];
console.log('array1:', array1);
// expected output: "array1:" Array ["one", "two", "three"]
const reversed = array1.reverse();
console.log('reversed:', reversed);
// expected output: "reversed:" Array ["three", "two", "one"]
// Careful: reverse is destructive -- it changes the original array.
console.log('array1:', array1);
// expected output: "array1:" Array ["three", "two", "one"]
17. every()
对数组的每一项都运行给定的函数,每一项都返回 ture,则返回 true
const isBelowThreshold = (currentValue) => currentValue < 40;
const array1 = [1, 30, 39, 29, 10, 13];
console.log(array1.every(isBelowThreshold));
// expected output: true
18. some()
对数组的每一项都运行给定的函数,任意一项都返回 ture,则返回 true
const array = [1, 2, 3, 4, 5];
// checks whether an element is even
const even = (element) => element % 2 === 0;
console.log(array.some(even));
// expected output: true
19. filter()
对数组的每一项都运行给定的函数,返回 结果为 ture 的项组成的数组
const words = ['spray', 'limit', 'elite', 'exuberant', 'destruction', 'present'];
const result = words.filter(word => word.length > 6);
console.log(result);
// expected output: Array ["exuberant", "destruction", "present"]
20. map()
对数组的每一项都运行给定的函数,返回每次函数调用的结果组成一个新数组
const array1 = [1, 4, 9, 16];
// pass a function to map
const map1 = array1.map(x => x * 2);
console.log(map1);
// expected output: Array [2, 8, 18, 32]
21. forEach()
forEach 数组遍历
const array1 = ['a', 'b', 'c'];
array1.forEach(element => console.log(element));
// expected output: "a"
// expected output: "b"
// expected output: "c"
对象操作方法:
1. 判断对象是否为空
-
使用ES6的Object.keys()方法
let data = {}
let arr = Object.keys(data)
console.log(arr.length) //0
console.log(arr) // []
-
转换成字符串进行比对
let data = {};
let flag = (JSON.stringify(data) == "{}");
-
for in 循环判断
let data = {};
let a = function (){
for(var key in data) {
return false;
}
return true;
}
a(); //true
-
jquery的isEmptyObject方法
var data = {};
var a = $.isEmptyObject(data);
console.log(a); //true
2. 删除对象中某个属性
delete
let a = {a : 1, b: 2};
delete a.b;
console.log(a); //{a: 1}
3. 添加对象属性
var a = {a: 1};
a.b = 2;
console.log(a); // {a: 1,b: 2}
4. 浅拷贝
当一个对象拷贝另一个对象的数据的时候,只要一个对象的数据发生改变另一个对象的数据也会发生改变 因为浅拷贝拷贝的是引用的地址,(所以必须在对象是多层才能拷贝,单层拷贝的是数值,多层说明里面套着对象,所以拷贝的是地址。)
-
方法一(ES6的方法):
var obj = {a:{name:"kaiqin",age:19}};
var obj1 = Object.assign({},obj);
obj1.a.name="wang"
console.log(obj1) // name已经被改变
console.log(obj) //name已经被改变
-
方法二:使用 for in 循环,遍历每一个属性,将他们赋值给新的对象。要求对象必须是多层的状态下才能实现浅拷贝
var obj = { a: {name:"kaiqin",age:19 } } ;
var obj2 = {a:1,b:2,c:3};
//多层
function copy(obj){
var newObj = {};
for(var key in obj){
newObj[key] = obj[key];
}
return newObj;
}
//单层
var obj1 = copy(obj);
obj1.a.name="wang"
console.log(obj1)
console.log(obj)
5. 深拷贝
当一个对象拷贝另一个对象的数据的时候,其中一个对象的数据发生变化不会影响另一个对象的数据 因为深考贝拷贝的是对象的数据而不是地址
-
方法一:对象是单层的情况下
Object.assign()
var obj = {a:1,b:2,c:3}
var obj1 = Object.assign({},obj);
obj1.a = 30;
console.log(obj1,obj)
-
方法二:JSON.parse(JSON.stringify())
用JSON.stringify将对象转成JSON字符串,再用JSON.parse()把字符串解析成对象,一去一来,新的对象产生了,而且对象会开辟新的栈,实现深拷贝。
let arr = [1,2,{name:'kobe'}]
let newArr = JSON.parse(JSON.stringify(arr))
arr[2].name = 'jodan'
console.log(arr)
console.log(newArr)
防抖节流:
防抖:任务频繁触发的情况下,只有任务触发的间隔超过指定间隔的时候,任务才会执行。
具体例子:有个输入框,输入之后会调用接口,获取联想词。但是,因为频繁调用接口不太好,所以我们在代码中使用防抖功能,只有在用户输入完毕的一段时间后,才会调用接口,出现联想词。
function debounce(fn, wait) {
var timeout = null;
return function() {
if(timeout !== null)
clearTimeout(timeout);
timeout = setTimeout(fn, wait);
}
}
// 处理函数
function handle() {
console.log(Math.random());
}
// 滚动事件
window.addEventListener('scroll', debounce(handle, 1000));
节流:指定时间间隔内只会执行一次任务。
例子:
1.懒加载要监听计算滚动条的位置,使用节流按一定时间的频率获取。
2.用户点击提交按钮,假设我们知道接口大致的返回时间的情况下,我们使用节流,只允许一定时间内点击一次。
var throttle = function(func, delay) {
var prev = Date.now();
return function() {
var context = this;
var args = arguments;
var now = Date.now();
if (now - prev >= delay) {
func.apply(context, args);
prev = Date.now();
}
}
}
function handle() {
console.log(Math.random());
}
window.addEventListener('scroll', throttle(handle, 1000));
前端敏捷开发流程
markdown
markdown是一类标记类语言,具有纯文本语法格式。通常用于格式化的自述文件
apipost
用于请求接口,也可用于生成文档。
工作中遇到的坑
- 对高德地图的marker生成时,如果列表中,某个坐标不存在,会造成整个marker生成失败。解决问题的思路就是,生成marker之前,判断坐标是否存在,不存在就跳出执行,进行下一次循环。
try {
list.forEach((marker, i) => {
let longitude = marker.longitude;
let latitude = marker.latitude;
if (!longitude || !latitude) {
throw new Error("LoopTerminates");
}
var amarker = new AMap.Marker({
map: map,
clickable: true,
icon: "healthImg/addressIcon.png",
position: [longitude, latitude],
draggable: true,
});
amarker.setLabel({
content: `<div style="color:blue">${
this.map_index == 1 ? marker.name : marker.businessName
}</div>`,
direction: "bottom",
});
});
} catch (e) {
if (e.message !== "LoopTerminates") throw e;
}
- echarts生成图例的时候,例图不能显示的问题,需要legend中的data和series中的name一一对应。
- flex布局产生的间隙解决方法
flex布局的元素会有默认间隙,解决方法
align-content: flex-start
具体参数如下:
取值情况: flex-start:与交叉轴的起点对齐。 flex-end:与交叉轴的终点对齐。 center:与交叉轴的中点对齐。 stretch(默认值):轴线占满整个交叉轴。 space-between:与交叉轴两端对齐,轴线之间的间隔平均分布。 space-around:每根轴线两侧的间隔都相等。所以,轴线之间的间隔比轴线与边框的间隔大一倍。
legend.data = ["住院养老","居家养老"]
series[0].name = "住院养老"
series[1].name = "居家养老"
css的高阶知识:
1.如何在vue里面全局引用css变量(注意是变量)
一般情况下我们在项目中会使用到scss或者less,这里我选中用scss来进行说明。我们需要下载一个scss依赖。
npm install sass-loader sass --save
然后在vue.config.js进行配置,这里我把文件列出来
const path = require('path')
function resolve(dir) {
return path.join(__dirname, dir)
}
module.exports = {
css: {
loaderOptions: {
scss: {
prependData: `@import "@/style/gobal.scss";` // 这里对应文件目录
}
}
}
这样我们就可以在vue每个组件里面使用@/style/gobal.scss这个目录下面的变量(注意是变量)
2.如何在vue里面全局引用css样式
我们都知道,如果我们不对浏览器进行样式的初始化,我们会发现,我们写的东西在不同浏览器有不同的样式。而这些样式我们不需要在vue组件中使用。我们就需要再全局配置好这些样式即可,方法很简单。 我们直接在style目录下编写样式。
这个文件夹的东西,打包后,会自动加载在index.html里面,所以一些初始化样式我们配置在这里即可。
3.px转rem自动适配
在做移动端项目的时候,我们需要根据不同的设备来调我们项目元素的宽高,如果我们使用px的话,会出现偏差是因为手机的尺寸不一样造成。我们就使用rem百分百来控制。
安装依赖
npm install postcss-plugin-px2rem -D
npm install lib-flexible
vue.config.js 配置插件
module.exports = {
css: {
loaderOptions: {
postcss: {
plugins: [
require('postcss-plugin-px2rem')({
rootValue: 75,
exclude: /(node_module)/,
minPixelValue: 3,
selectorBlackList:['van']
})
]
}
}
}
main.js 配置
import 'lib-flexible/flexible.js'
之后在项目中使用px,会自动转换为rem
this、call、apply、bind详细讲解,带例子说明(必须搞懂)
new 绑定
函数如果作为构造函数使用 new 调用时, this 绑定的是新创建的构造函数的实例。
function Foo() {
console.log(this)
}
var bar = new Foo() // 输出: Foo 实例,this 就是 bar
显式绑定
通过 call、apply、bind 我们可以修改函数绑定的 this,使其成为我们指定的对象。通过这些方法的第一个参数我们可以显式地绑定 this。
function foo(name, price) {
this.name = name
this.price = price
}
function Food(category, name, price) {
foo.call(this, name, price) // call 方式调用
// foo.apply(this, [name, price]) // apply 方式调用
this.category = category
}
new Food('食品', '汉堡', '5块钱')
// 浏览器中输出: {name: "汉堡", price: "5块钱", category: "食品"}
// 这里this的指向变成了构造函数,所以这些属性就都在new Food()上了
call 和 apply 的区别是 call 方法接受的是参数列表,而 apply 方法接受的是一个参数数组。
func.call(thisArg, arg1, arg2, ...) // call 用法
func.apply(thisArg, [arg1, arg2, ...]) // apply 用法
而 bind 方法是设置 this 为给定的值,并返回一个新的函数,且在调用新函数时,将给定参数列表作为原函数的参数序列的前若干项。
func.bind(thisArg[, arg1[, arg2[, ...]]]) // bind 用法
var food = {
name: '汉堡',
price: '5块钱',
getPrice: function(place) {
console.log(place + this.price)
}
}
food.getPrice('KFC ') // 浏览器中输出: "KFC 5块钱"
var getPrice1 = food.getPrice.bind({ name: '鸡腿', price: '7块钱' }, '肯打鸡 ')
getPrice1() // 浏览器中输出: "肯打鸡 7块钱"
隐式绑定
函数是否在某个上下文对象中调用,如果是的话 this 绑定的是那个上下文对象。
var a = 'hello'
var obj = {
a: 'world',
foo: function() {
console.log(this.a)
}
}
obj.foo() // 浏览器中输出: "world"
// obj调用的,this就是全局上下文,this就是这里的obj
var a = 'hello'
var obj = {
a: 'world',
b:{
a:'China',
foo: function() {
console.log(this.a)
}
}
}
obj.b.foo() // 浏览器中输出: "China"
默认绑定
函数独立调用,直接使用不带任何修饰的函数引用进行调用,也是上面几种绑定途径之外的方式。非严格模式下 this 绑定到全局对象(浏览器下是 winodw,node 环境是 global),严格模式下 this 绑定到 undefined (因为严格模式不允许 this 指向全局对象)。
var a = 'hello'
function foo() {
var a = 'world'
console.log(this.a)
console.log(this)
}
foo() // 相当于执行 window.foo()
// 浏览器中输出: "hello"
// 浏览器中输出: Window 对象
var a = 'hello'
var obj = {
a: 'world',
foo: function() {
console.log(this.a)
}
}
function func(fn) {
fn()
}
func(obj.foo)
参数传递实际上也是一种隐式的赋值,只不过这里 obj.foo 方法是被隐式赋值
给了函数 func 的形参 fn,而之前的情景是自己赋值,两种情景实际上类似。
这种场景我们遇到的比较多的是 setTimeout 和 setInterval,如果回调函
数不是箭头函数,那么其中的 this 指向的就是全局对象.
es6中的this
箭头函数的 this 绑定是无法通过 call、apply、bind 被修改的,且因为箭头函数没有构造函数 constructor,所以也不可以使用 new 调用,即不能作为构造函数,否则会报错。
var a = 'hello'
var obj = {
a: 'world',
foo: () => {
console.log(this.a)
}
}
obj.foo() // 浏览器中输出: "hello"
练手项目
- 若依 / RuoYi-Vue gitee.com/y_project/R…
持续更新中,最近更新时间2021年5月26日11:19:03.........................................................................................
微信技术交流群:cbq2393159 群内有免费的前端教程资料,需要的欢迎进群。