.基本类型和引用类型
基本类型:Number, String, Null, Undefined, Boolean, Symbol(ES6数据类型)
引用类型:Object、Array、RegExp、Date、Function、单体内置对象(Global、Math)
区别:基本类型,操作和保存在变量的实际的值(保存在栈区);引用类型,值指向内存空间的引用,就是地址,所指向的内存中保存着变量所表示的一个值或一组值,所以操作的是对象的引用(引用存放在栈区,实际对象保存在堆区)。
1.1 类型检测
使用typeof进行基本类型检测,使用instanceof检测对象还是数组
类型结果
Undefined"undefined"
Null"object"
Boolean"boolean"
Number"number"
String"string"
Symbol(ECMAScript 6 新增)"symbol"
函数对象"function"
任何其他对象"object"
检测数组和对象:(Array其实是Object的子类)vara = [];console.log(ainstanceofArray);// trueconsole.log(ainstanceofObject);// truevara = {};console.log(ainstanceofArray);// falseconsole.log(ainstanceofObject);// true
1.2 String操作
String <=> Number:
字符串转数字:parseInt(str, 进制)// 默认十进制, 转化为整数,小数点后默认不保留parseFloat(str)// 转化为浮点数+str// 屌屌的转化方法, 但字符串包含非数字会报错数字转字符串:letstr1 = num.toString();letstr2 =String(num);letstr3 = num +'';
String <=> Array:
字符串转数组letarr = str.split(',')// 一般是空格或者逗号数组转字符串letstr = arr.join('');
模板字符串
`Hello,${变量}`
1.3 常用正则
去逗号letnewStr = str.replace(/,/g,'');去空格(一般输入框输入都要做这个)letnewStr = str.replace(/(^\s*)|(\s*$)/g,'');// 去除左右空格letnewStr = str.replace(/\s+/g,"");// 去除所有空格用户名letuserPattern =/^[a-zA-Z0-9_-]{4,16}$/;// 4到16位(字母,数字,下划线,减号)userPattern.test(str);电话号码letmPattern =/^1[34578]\d{9}$/;附:密码/身份证号/E-mail/URL就不上了,太长了背了没意义,用的时候查就好了
1.4 Array操作
在阿里腾讯头条的笔试机试中,对数组的操作可以说是前端算法的核心,数组操作的基本方法全是必背的重中之重。
1.4.1 Array.from()
将伪数组对象和可迭代对象[见附录]转化为数组:
letarr =Array.from(str/newSet()/newmap());
转化数组后对每项进行操作
letarr =Array.from('123', item =>parseInt(item) +1);// 2, 3, 4
去重(可以说这是最精彩的地方了)
Array.from(newSet(arr));
1.4.2 拷贝数组
使用以下方法能复制数组保存在堆内存中的值,但不能深拷贝数组(数组中的数组或者对象依旧只是复制了引用没有复制到其在堆内存中的值)。[数组和对象的深浅拷贝以及for循环递归实现方式本文不涉及]
letarr2 = [...arr1];letarr2 = arr1.slice();letarr2 = arr1.concat([]);// 此方法不常用
深拷贝(对象也是如此)
letarr2 =JSON.parse(JSON.stringify(arr1));
1.4.3 找出最大最小值
Math.max.apply(null, arr);Math.min.apply(null, arr);// ES6的写法Math.max(...arr);
1.4.4 数组排序
sort()
1.数组排序functioncompare(a, b){returna-b; } arr.sort(compare);2.数组对象排序(开发中常用)functioncompare(property){return(obj1, obj2) =>{returnobj1[property] - obj2[property]; } }letstudents = [{name:"xx",age:20}, {name:"hh",age:19}]; students.sort(compare('age'));
1.4.5 其他方法
push(item)// 末尾添加pop()// 删除末尾shift()// 删除开头unshift()// 开头添加sort()// 排序reverse()// 反转slice(start, end)// 截断拷贝, 接收起始和结束位置两参数并返回相应的数组,不影响原数组splice(index, num)// 切片,取出从index位置开始的num个值,原数组被截取splice(index,0, sth)// 插入sthsplice(index,1, sth)// 替换为sth▲ forEach(item, index,array)// 对每一项执行某些操作▲ filter(item, index,array)// 返回满足条件(true)的项组成的数组▲map(item, index,array)// 返回对每一项执行某些操作组成的数组every(item, index,array)// 如果该函数对每一项都返回true,则返回truesome(item, index,array)// 如果该函数对某一项返回true,则返回truereduce()// 从头到尾逐个遍历,迭代数组中的所有项includes(sth, index);// 检测数组中是否含有sth,index代表开始查找的位置,返回布尔值
另:二分查找
1.4.5 对象数组根据对象某key值去重(日常工作常用)
letarr = [{showId:'C',age:'11'}, {showId:'A',age:'11'},{showId:'B',age:'11'}, {showId:'B',age:'11'},{showId:'B',age:'12'},{showId:'B',age:'13'}];// 根据showId去重到新数组newArrconstnewArr = [];arr.forEach(item=>{// 过滤,如果有重复项就添加到过滤数组,那么长度就不为0就不会推入新数组。// 如果没有重复项长度就为0就推入新数组。newArr.filter(m=>m.showId === item.showId).length ===0&& newArr.push(item);});
1.5 Object操作
1.5.1 创建
创建方式:工厂模式、构造函数模式、原型模式、动态原型模式、寄生构造函数模式、稳妥构造函数模式。
工厂模式
functioncreateObj(key){constobj =newObject(); obj.key = key; obj.sayKey =function(){ 方法 };returnobj;}// 使用:const xuqingfeng = createObj('xuqingfeng');
构造函数(对象属性最好用构造函数) + 原型(对象方法最好用原型),这样的话每个实例都会有自己的一份实例属性的副本,同时又共享着对方法的引用,最大限度地节省了内存:
// 构造函数模式用于定义实例属性functionPerson(name){this.name = name;}// 原型模式用于定义方法和共享的属性Person.prototype = {/* 默认情况下,所有原型对象都会自动获得一个constructor属性,
这个属性是一个指向prototype属性所在函数的指针,
这里的Person.prototype.constructor指向Person */constructor: Person, sayName : function() { 方法 }}
ES6的简写(简直不要太好用, 三大框架很多写法基于此):
属性简写:letkeyVal ='xuqingfeng';constobj = {keyVal};// obj: { keyVal: 'xuqingfeng' }方法简写:constobj = { method() {}};获取对象属性:const{ keyVal } = obj;// React的const { data } = this.props; 就是这么个原理,前提是对象中也有对应属性(key)
1.5.2 继承
继承方式:原型链、借用构造函数、组合继承、原型式继承、寄生式继承、寄生组合式继承。
组合继承
这种方式既通过在原型上定义方法实现了函数复用,又能够保证每个实例都有它自己的属性。
functionA_Obj(name){this.name = name;}A_Obj.prototype.sayName =function(){ A_Obj的方法 };functionB_Obj(name, age){ A_Obj.call(this, name);// 继承属性this.age = age;}B_Obj.prototype =newA_Obj();// 继承A_Obj的所有方法B_Obj.prototype.constructor = B_Obj;// 改变指向非常关键B_Obj.prototype.sayAge =function(){ B_Obj的方法 };
object.create()实现对象继承- 特别地提及下这个方法,它可以直接使用创建一个新对象
// 实现继承 - 方法letextend =(Child, Parent) =>{ Child.prototype =Object.create(Parent.prototype);// 拷贝Parent原型对象Child.prototype.constructor = Child;// 将Child构造函数赋值给Child的原型对象}// 实例constPar =function(){this.name ='xuqingfeng'; }Par.prototype.getName =function(){returnthis.name; }// 继承constCld =function(){ Par.call(this); }extend(Cld, Par);// 使用lettestChild =newCld();console.log(testChild.getName())
1.5.3 拷贝
浅拷贝:
constcopyObj =Object.assign({}, obj);constObj2 = {...Obj1};
浅拷贝并修改key的value或添加key与value:const Obj2 = {...Obj1, ['key']: 'newOrCover'},示例如下
constfirObj = {a:'1',s: {ss:'sss'} };constsecObj = { ...firObj, ['b']:'2'}secObj.a ='777';firObj.a ='666';secObj.s.ss ='secObj-s';firObj.s.ss ='firObj-s';console.log(firObj, secObj);// { a: '666', s: { ss: 'firObj-s' } } { a: '777', s: { ss: 'firObj-s' }, b: '2' }
并集-合并两个对象/数组,后者覆盖前者(深度覆盖),最终形成并集:const Obj3 = Object.assign({}, Obj1, Obj2);,示例如下
constfirObj = {a:'1',b:'b',s: {ss:'fir-s'} };constsecObj = {a:'2',c:'c',s: {ss:'sec-s'} }constnewObj =Object.assign({}, firObj, secObj);console.log(newObj);// { a: '2', b: 'b', s: { ss: 'sec-s' }, c: 'c' }constfirArr = [1,2,3,'a','b'];constsecArr = [1,3,5,7];constnewArr =Object.assign([], firArr, secArr);console.log(newArr);// [ 1, 3, 5, 7, 'b' ]
深拷贝[ for循环递归深拷贝见上面数组,Object.assign合并对象和深拷贝移步MDN]:
letobj2 =JSON.parse(JSON.stringify(obj1));
1.5.4 其他方法
Object.freeze()// 冻结对象:其他代码不能删除或更改任何属性。Object.keys()// 返回一个包含所有给定对象自身可枚举属性名称的数组。Object.values()// 返回给定对象自身可枚举值的数组。Object.entries()// 返回给定对象自身可枚举属性的[key, value]数组Object.defineProperty()// vue数据双向绑定的核心方法,建议上 MDN 一观
1.6 Function操作
1.6.1 参数转化为数组(不知参数个数)
数组原型slice方法
functionfc(){Array.prototype.slice.call(arguments) ;// 这个方法可以将只要具有length属性的对象转成数组}
▲ rest 参数
functionfc(...arr){console.log(arr); }
参数cancat为数组
functionfc(){return[].concat.apply([],arguments); }
1.6.2 检测函数参数是否含有某个值(sth)
[].includes.call(arguments,sth)
1.6.3 函数设置可改的默认参数
functionfunc1(a, b='123123',c={id:1}){console.log(a,b,c)}func1('徐清风','xuqingfeng',44)// 徐清风, xuqingfeng, 44
1.7Math与Date
Math方法:
Math.ceil()// 执行向上舍入Math.floor()// 执行向下舍入Math.round()// 执行标准舍入▲Math.random()// 返回大于等于0小于1的随机数
获取当前时间:
letnow =newDate();console.log(now.toLocaleString());// 2018-8-23 17:48:47console.log([now.getFullYear(), now.getMonth()+1, now.getDate()].join('-'));// 2018-8-23
2.JS编程基本操作
2.1 三元运算 - 用起来超刺激
公式:条件1 ? 真结果1 : ( 条件1.1 ? 真结果1.1 : (条件1.1.1 ? 真结果1.1.1:假结果1.1.1)), 一个常用示例:
node.style.display = (node.style.display ==="block"?"none":"block");
2.2 在做JS判断时的true与false(if判断、与非判断、三元运算判断等)
值为false:false、null、undefined、''(空字符串,空格不代表空)、0、NaN
值为true:true、对象、字符串(包括空格)、任意非0数值(包括Infinity)
2.3 与或非运算
&& :如果第一个值为 true,则 && 后面的值将显示在输出中,否则值为第一个值。
leta =false&&123;// falseletb =' '&&123;// 123, 注意这里是空格不是空
|| :如果第一个值为 false,则 || 后面的值将显示在输出中,否则值为第一个值。
let a =false||123;//123let b =' '||123;//' '
附录:
伪数组对象和可迭代对象:
伪数组对象(拥有一个length属性和若干索引属性的任意对象)
可迭代对象(可以获取对象中的元素,如Map和Set等)
福利-今年春秋招阿里腾讯头条机试(远程视频直接撸代码)题:
1.正则电话号码2.两个超过JS数值范围的数字相加3.一片英文文章重复出现次数最多的单词及其出现次数4.创建一个 Person 类,其包含公有属性 name 和私有属性 age 以及公有方法 setAge; 创建一个 Teacher 类,使其继承 Person ,并包含私有属性 studentCount 和私有方法 setStudentCount5.兼容的事件监听方法6.快排7.拖拽一个方块随机移动8.事件观察者9.promise按序执行三个函数10.封装一个flat方法,将多维数组扁平化为一维数组11.实现一个简易的JQ选择器功能(要求能够获取标签、类、Id)12.实现简易的虚拟DOM(意味着用对象构造DOM),然后生成DOM结构, 只要求属性值(比如class、id等属性能够正常获取和调用), 不要求节点增删查改(这涉及到diff算法)。13.对象数组根据某个属性去重【这个上面有提到】
作者:徐丶清风
链接://www.greatytc.com/p/ca6110ebabb9
来源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。