js基础知识复习2
第一章 走进 JAVASCRIPT 黑洞
1.传值和传址
基本数据类型复制的是值,
引用数据类型复制的是地址,
/* let a = 1; let b = a; console.log(a,b) //1,1 b = 2; console.log(a,b) //1,2 */ let a = {name:"kangxinzhi"}; let b = a; console.log(a,b) //{name:"kangxinzhi"},{name:"kangxinzhi"} b.name = "kxz" console.log(a,b) //{name:"kxz"},{name:"kxz"}
2.null和undifined详解
基本数据类型空为undifined
引用数据类型空为null
null是个对象
3.环境污染(局部污染外部)
/* name="kxz" function change(){ name="kang" } change(); console.log(name) //"kang" */ //原因:变量未声明,成为全局变量,造成全局污染。解决方案:使用严格模式提示 "use strict" name="kxz" function change(){ name="kang" } change(); console.log(name) //"kxz"
第二章 JavaScript 运算符与流程控制
1.比较运算符注意事项
let a=1; let b="1"; a==b //true存在隐式转换,这里的b转化为数字类型 数字和数字的比较 a===b //false 字符串和数字的比较
2.break,continue和label标签的使用
break停止整个循环
continue停止当前循环走下个循环
testlabel:for(let i=0;i<10;i++){ for(let j=0;j<10;j++){ if(i+j>10){ break testlabel; //跳到最外层testlabel循环 } } }
3.for-in;for-of的使用
for-in用来遍历数组时返回的下标;遍历对象时返回的是对象的key
for-of用来遍历数组时返回的是值;遍历对象时返回的是对象的value(用来处理迭代对象)
let arr = ["apple","banana","orange","melon"]; let msg = {name:"kang",age:"18",sex:"man"}; for(let index in arr){ console.log(i); //0,1,2,3 console.log(arr[i]); //"apple","banana","orange","melon" } for(let value of arr){ console.log(value); //"apple","banana","orange","melon" 数组时迭代对象 } for(let key in msg){ console.log(key); //name,age,sex console.log(msg[key]); //"kang","18","man" } for(let value of msg){ console.log(value); //报错msg不是迭代对象 }
for(let value of "kang"){
console.log(value) //k a n g 字符串也是可迭代对象
}
第三章 JavaScript 值类型使用
1.typeof 能判断基本类型和function
A instanceof Array 判断复杂数据类型,它的原理是判断A的protote是否在Array原型链上
2.模板字面量的使用和字符串转义( /t 制表符 /n换行符)
let year="1998年"; let name="康心志"; console.log(name+"出生于"+year);//康心志出生于1998年 console.log(`${name}出生于${year}`)//康心志出生于1998年
let lessons=[{title:"vue"},{title:"react"},{title:"angular"}]; console.log(`${lessons.map(e=>{e.title})}) // , , console.log(`${lessons.map(e=>{return e.title})})//vue react angular console.log(`${lessons.map(e=>e.title)}`) //vue react angular
3.标签模板实例操作
在模板字面量``前加一个函数,函数的第一个参数是模板中的string,第二个可用扩展元素表示剩余的所有参数它表示的是每个${}的内容
let year="1998年"; let name="康心志"; function tag(strings,...vars){ console.log(strings); console.log(vars) } console.log(tag`${name}出生于${year}`) //["", "出生于", "", raw: Array(3)] //["康心志", "1998年"]
4.字符串的常用方法
toUpperCase()大写 toLowerCase()小写 trim()去除字符串两端空格 charAt()获取某个下标的字符
slice()截取字符串 substring()截取字符串 substr()截取字符串
indexOf()查找某个字符串的坐标,没有就返回-1,第二个参数表示从第几个字符串开始查找 includes()是否存在某个字符返回布尔值,第二个参数表示从第几个字符开始查找 lastIndexOf()从末尾开始查找
startsWidth()字符串是否以某个字符开头 endsWidth()字符串是否以某个字符结尾
replace()字符串替换 repeat()重复输出某个字符串
split()字符串转为数组 数组.join(,)数组转为字符串
let a="KangXinZhi"; a.toUpperCase()//"KANGXINZHI" a.toLowerCase();//"kangxinzhi" " xxx ".trim()//"xxx" a.charAt(5)//i a.slice(1);//angXinZhi a.substring(1);//angXinZhi a.substr(1);//angXinZhi a.slice(1,3);//an a.substring(1,3);//an a.substr(1,3);//ang a.slice(-3,-1);//Zh a.substring(-3,-1);//KangXinZhi a.substr(-3,2);//Zh a.replace("Kang","k")//kXinZhi "*".repeat(3);//"***" a.split("");//["K", "a", "n", "g", "X", "i", "n", "Z", "h", "i"] ["k","x","z"].join(,);//"kxz"
5.类型转换和隐式转换
字符串,对象的toString()方法,转为字符串
字符串 使用运算符+-*/转为数字
字符串或数字 前使用!!转为布尔值
String()转字符串,Boolean()转布尔值,Number()转数字,Object()转对象
boolean只有6种情况为false 其他为true
1、undefined(未定义,找不到值时出现)
2、null(代表空值)
3、false(布尔值的false,字符串"false"布尔值为true)
4、0(数字0,字符串"0"布尔值为true)
5、NaN(无法计算结果时出现,表示"非数值";但是typeof NaN==="number")注意NaN===NaN为false 它是唯一一个不等于自身的
6、""(双引号)或''(单引号) (空字符串,中间有空格时也是true)
注意空数组空对象,负值转的布尔值时都为true
6.Number的一些常用函数
number.toString()数字转为字符串 Number.isInteger(number)判断数字是否是整数 Number.isNaN(number)判断是否是NaN Object.is(number,NaN)判断是否是NaN
parseInt()转为整形 parseFloat()转为浮点数 Number.toFixed(1)保留一位小数
Math.max() Math.min() Math.ceil()取最接近的最大整数 Math.floor()取最接近的最小整数 Math.round()四舍五入 Math.random()随机数
7.Data的一些常用函数
时间戳(TIMESTAMP)指从1970-01-01 00:00:00到现在的毫秒数
new Date() //获取当前时间ISO Date.now() //当前时间戳TIMESTAMP const start=Date.now(); for(let i=0;i<20000000;i++) const end =Date.now(); console.log(end-start) //计算脚本执行时间 console.time("for") for(let i=0;i<20000000;i++) console.timeEnd("for") //计算脚本执行时间
ISO和TIMESTAMP的转换
ISO转TIMESTAMP const date=new Date(); console.log(date*1); console.log(Number(date)); console.log(date.valueOf()); console.log(date.getTime()); TIMESTAMP转ISO const TIMESTAMP=date.valueOf(); console.log(new Date(TIMESTAMP));
日期格式格式化
function dateFormat(date,format="YYYY-MM-DD hh:mm:ss"){ const config = { YYYY : date.getFullYear(), MM : date.getMonth(), DD : date.getDate(), hh : date.getHours(), mm : date.getMinutes(), ss : date.getSeconds() } for(const key in config){ format=format.replace(key,config[key]); } return format; } console.log(dateFormat(date)) //2020-9-21 10:29:14 console.log(dateFormat(date,"YYYY年MM月"))//2020年9月
优秀的日期处理库moment.js
http://momentjs.cn/
//npm install moment --save moment().format('MMMM Do YYYY, h:mm:ss a'); // 十月 21日 2020, 10:31:44 上午 moment().format('dddd'); // 星期三 moment().format("MMM Do YY"); // 10月 21日 20 moment().format('YYYY [escaped] YYYY'); // 2020 escaped 2020 moment().format(); // 2020-10-21T10:31:44+08:00
第四章 JavaScript 数组挖掘
1.数组创建的小细节
用new Array()创建数组时,当只填入一个数字,它表示创建的长度是该数字,其每一项的值是undifined
为了解决这一问题,新版可以用Array.of()来创建,
let arr=new Array(6); arr.length //6 arr[0] //undifined let arr2=Array.of(6); arr2.length //1 arr2[0] //undifined
2.数组的常用方法
push() pop() unshift() shift() fill()填充 copywithin(i,j,k)用于操作当前数组自身,用来把某些个位置的元素复制并覆盖到其他位置上去。
slice(i,j)截取数组从第i截取到第j项,不改变原数组 splice(i,j,k)截取数组从第i截取j个元素,用k替换掉其内容,改变原数组
indexOf()查找某项的下标,没有就返回-1,第二个参数表示从第几项开始查找 includes()是否存在某个项返回布尔值,第二个参数表示从第几项开始查找 lastIndexOf()从末尾开始查找
find(callback)查找数组中第一个符合条件的值 findIndex(callback)查找数组中第一个符合条件的值的索引
sort((a,b)=>{return a-b})数组排序
清空数组的几种方式:
let arr=[1,2,3,4]; arr=[]; arr.length=0; arr.splice(0,arr.length); while(arr.pop()){}; while(arr.shift()){};
//手写find function myfind(arr,callback){ for(let value of arr){ if(callback(value)){return value} } return undefined; }
myfind([1,2,3,4,5],e=>{return e==3}) //3
//手写sort function mysort(arr,callback){ for(let m in arr){ for(let n in arr){ if(callback(arr[m],arr[n])<0) { let t=arr[n]; arr[n]=arr[m]; arr[m]=t; } } } return arr; }
2.数组的遍历
1.forEach((item,index,arr)=>{},{}) 遍历数组,第一参数回调函数(每一项,索引值,原数组),第二个参数this指向的对象,不填的话this指向windows
2.使用迭代器iterator
let arr=["kang","xin","zhi"]; let arrkeys=arr.keys(); arrkeys.next();//{value: 0, done: false} arrkeys.next();//{value: 1, done: false} arrkeys.next();//{value: 2, done: false} arrkeys.next();//{value: undefinew, done: true} let arrvalues=arr.values(); arrvalues.next();//{value: "kang", done: false} arrvalues.next();//{value: "xin", done: false} arrvalues.next();//{value: "zhi", done: false} arrvalues.next();//{value: undefined, done: true} for(let values of arr.values()){ console.log(values)//kang xin zhi } for(let keys of arr.keys()){ console.log(keys )//0 1 2 } for(let [keys,values] of arr.entries()){ console.log(values)//kang xin zhi console.log(keys )//0 1 2 }
3.every()和some()
every()是对数组中每一项运行给定函数,如果该函数所有一项返回true,则返回true。一旦有一项不满足则返回flase
some()是对数组中每一项运行给定函数,如果该函数满足任一项返回true,则返回true
var arr = [ 1, 2, 3, 4, 5, 6 ]; console.log( arr.every( function( item, index, array ){ console.log( 'item=' + item + ',index='+index+',array='+array ); return item > 3; })); //item=1,index=0,array=1,2,3,4,5,6 //false console.log( arr.some( function( item, index, array ){ console.log( 'item=' + item + ',index='+index+',array='+array ); return item > 3; })); //item=1,index=0,array=1,2,3,4,5,6 //item=2,index=1,array=1,2,3,4,5,6 //item=3,index=2,array=1,2,3,4,5,6 //item=4,index=3,array=1,2,3,4,5,6 //true
4.filter过滤器
let arr=[100,55,32,65,84] arr.filter((item,index,value)=>{return item>60})//[100,65,84]
//手写 filter function myfilter(arr,callback){ let newarr=[]; for(let value of arr){ if(callback(value)==true){ newarr.push(value) } } return newarr; } myfilter([100,55,32,65,84],(item,index,value)=>{return item>60}) //[100, 65, 84]
5.map映射数组
对于值类型来说返回一个新的数组
对于引用类型来说会改变原数组的内容(可以不改变)
let arr=[1,2,3,4,5] let arr2=arr.map((value,index,array)=>{return value+1}) console.log(arr)//[1,2,3,4,5] console.log(arr2)//[2,3,4,5,6] let arr3=[{name:"kang",age:18},{name:"xin",age:19},{name:"zhi",age:20}] arr3.map((value)=>{value.sex="man"}) console.log(arr3) //[{name:"kang",age:18,sex:"man"},{name:"xin",age:19,sex:"man"},{name:"zhi",age:20,sex:"man"}] //若想不改变引用类型原数据,可以使用以下方法 let arr4=[{name:"kang",age:18},{name:"xin",age:19},{name:"zhi",age:20}] let arr5=arr4.map((value)=>{return Object.assign({sex:"man"},value) }) let arr6=arr4.map((value)=>{return {name:value.name,age:value.age,sex:"man"}}) //arr4 [{name:"kang",age:18},{name:"xin",age:19},{name:"zhi",age:20}] //arr5 [{name:"kang",age:18,sex:"man"},{name:"xin",age:19,sex:"man"},{name:"zhi",age:20,sex:"man"}] //arr6 [{name:"kang",age:18,sex:"man"},{name:"xin",age:19,sex:"man"},{name:"zhi",age:20,sex:"man"}]
6.reduce
/* reduce比之前见到的遍历函数的回调函数中多了一个pre参数,它表示函数每次遍历的返回值,若不给定其初始值,它第一次就表示数组中第一项,接下来表示每一项遍历的返回值。 若给reduce(callback,n)第二个参数n,则表示pre的初始值是n,接下来表示每一项遍历的返回值。 */ let arr=[1,2,3,4,5]; arr.reduce(function(pre,value,index,array){ console.log(pre,value) }) //1 2 //undefined 3 //undefined 4 //undefined 5 arr.reduce(function(pre,value,index,array){ console.log(pre,value) return "kxz" },0) //0 1 //kxz 2 //kxz 3 //kxz 4 //kxz 5 //判断数组中的最大值 function maxnum(array){ return array.reduce((pre,value)=>{ return pre>value?pre:value; }) } maxnum([99,56,43,41,255]); //255
第五章 好用的 JavaScript Symbol 类型
1.symbol的定义
Symbol用于防止属性名冲突而产生的,比如向第三方对象中添加属性时。
symbol定义的值永远是唯一的
let kxz= Symbol(); let kang = Symbol(); console.log(kxz); //symbol console.log(kxz== kang ); //false //symbol不可以添加属性 kxz.name = "康心志"; console.log(hd.name); //报错
2.symbol描述参数
//可传入字符串用于描述Symbol,方便在控制台分辨Symbol let kxz= Symbol("is name"); let kang = Symbol("这是一个姓"); console.log(kxz); //Symbol(is name) console.log(kang.toString()); //Symbol(这是一个姓) //传入相同参数Symbol也是独立唯一的,因为参数只是描述而已,但使用 Symbol.for则不会 let kxz2= Symbol("kang"); let kxz3 = Symbol("kang"); console.log(kxz2== kxz3); //false //使用description可以获取传入的描述参数 let kxz4= Symbol("kang"); console.log(hd.description); //kang
3.Symbol.for和Symbol.keyFor
//Symbol.for根据描述获取Symbol,如果不存在则新建一个Symbol //使用Symbol.for会在系统中将Symbol登记 //使用Symbol则不会登记 let hd = Symbol.for("后盾人"); let edu = Symbol.for("后盾人"); console.log(hd == edu); //true //Symbol.keyFor 根据使用Symbol.for登记的Symbol返回描述,如果找不到返回undefined 。 let hd = Symbol.for("后盾人"); console.log(Symbol.keyFor(hd)); //后盾人 let edu = Symbol("houdunren"); console.log(Symbol.keyFor(edu)); //undefined
4.对象属性
Symbol 是独一无二的所以可以保证对象属性的唯一。
-
Symbol 声明和访问使用
[]
(变量)形式操作 -
也不能使用
.
语法因为.
语法是操作字符串属性的。
//下面写法是错误的,会将symbol 当成字符串symbol处理 let symbol = Symbol("后盾人"); let obj = { symbol: "hdcms.com" }; console.log(obj); //正确写法是以[] 变量形式声明和访问 let symbol = Symbol("后盾人"); let obj = { [symbol]: "houdunren.com" }; console.log(obj[symbol]); //houdunren.com
5.遍历属性
//Symbol 不能使用 for/in、for/of 遍历操作 let symbol = Symbol("后盾人"); let obj = { name: "hdcms.com", [symbol]: "houdunren.com" }; for (const key in obj) { console.log(key); //name } for (const key of Object.keys(obj)) { console.log(key); //name } //可以使用 Object.getOwnPropertySymbols 获取所有Symbol属性 for (const key of Object.getOwnPropertySymbols(obj)) { console.log(key); } //也可以使用 Reflect.ownKeys(obj) 获取所有属性包括 Symbolfor (const key of Reflect.ownKeys(obj)) { console.log(key); } //如果对象属性不想被遍历,可以使用Symbol保护 const site = Symbol("网站名称"); class User { constructor(name) { this[site] = "后盾人"; this.name = name; } getName() { return `${this[site]}-${this.name}`; } } const hd = new User("向军大叔"); console.log(hd.getName()); for (const key in hd) { console.log(key); }
6.对象
1.查看对象的属性
对象自己的属性:obj.hasOwnProperty(属性)
对象自己和原型上的属性:属性 in obj
设置自己的属性:Object.setPrototypeOf(属性)
对象的合并:Object.assgin({a:1},{b:2}) //{a:1,b:2}
2.浅拷贝,深拷贝
浅拷贝:使用for/in Object.assgin 展开语法
深拷贝:
3.构造函数
定义:通过 new 函数名 来实例化对象的函数叫构造函数。任何的函数都可以作为构造函数存在。之所以有构造函数与普通函数之分,主要从功能上进行区别的,构造函数的主要 功能为 初始化对象,特点是和new 一起使用。new就是在创建对象,从无到有,构造函数就是在为初始化的对象添加属性和方法。构造函数定义时首字母大写(规范)。
对new理解:new 申请内存, 创建对象,当调用new时,后台会隐式执行new Object()创建对象。所以,通过new创建的字符串、数字是引用类型,而是非值类型。
4.面向对象抽象设置
Object.getOwnPropertyDescriptors(对象名); //显示对象的所有权限(value值,writeable是否可写,enumerable是否可遍历,configurable是否可删除)
Object.defineProperty(对象名,属性名,{value:'新值',writeable:false,enumerable:false,configurable:false}) //修改或添加属性及其权限
Object.isExtensible(对象名)// 判断是否能向对象中添加属性
Object.preventExtensions(对象名)//禁止向对象添加属性
Object.seal()//
方法封闭一个对象,阻止添加新属性并将所有现有属性标记为 configurable: false
Object.isSealed
如果对象是密封的则返回 true
,属性都具有 configurable: false
。
Object.freeze
() //冻结对象后不允许添加、删除、修改属性,writable、configurable都标记为false
Object.isFrozen()
方法判断一个对象是否被冻结
5.属性访问器
getter方法用于获得属性值,setter方法用于设置属性,这是JS提供的存取器特性即使用函数来管理属性。
- 用于避免错误的赋值
- 需要动态监测值的改变
- 属性只能在访问器和普通属性任选其一,不能共同存在
getter/setter
向对是地用户的年龄数据使用访问器监控控制
"use strict"; const user = { data: { name: '后盾人', age: null }, set age(value) { if (typeof value != "number" || value > 100 || value < 10) { throw new Error("年龄格式错误"); } this.data.age = value; }, get age() { return `年龄是: ${this.data.age}`; } }; user.age = 99; console.log(user.age);
代理拦截proxy
代理(拦截器)是对象的访问控制,setter/getter
是对单个对象属性的控制,而代理是对整个对象的控制
- 读写属性时代码更简洁
- 对象的多个属性控制统一交给代理完成
- 严格模式下
set
必须返回布尔值
使用方法:
"use strict"; const hd = { name: "后盾人" }; const proxy = new Proxy(hd, { get(obj, property) { return obj[property]; }, set(obj, property, value) { obj[property] = value; return true; } }); proxy.age = 10; console.log(hd);
通过proxy实现双向数据绑定:
<body> <input type="text" v-model="title" /> <input type="text" v-model="title" /> <div v-bind="title"></div> </body> <script> function View() { //设置代理拦截 let proxy = new Proxy( {}, { get(obj, property) {}, set(obj, property, value) { obj[property] = value; document .querySelectorAll( `[v-model="${property}"],[v-bind="${property}"]` ) .forEach(el => { el.innerHTML = value; el.value = value; }); } } ); //初始化绑定元素事件 this.run = function() { const els = document.querySelectorAll("[v-model]"); els.forEach(item => { item.addEventListener("keyup", function() { proxy[this.getAttribute("v-model")] = this.value; }); }); }; } let view = new View().run();