传值与传地址
// 传值,两个变量指针指向不同对象
let a = 1
let b = a
b = 2
console.log(a,b) // 1 2
// 传址,两个变量指针指向同一对象或数组
let a = {name:'kevin'}
let b = a
b.name = 'jeff'
console.log(a,b) // jeff jeff
严格模式
**use strict ** 只对当前作用域及子作用域有效
严格模式下使用的变量必须定义
break-continue 与 label使用
label:for(let i = 0; i < 10; i++){
if(i == 5){
continue label
}
}
typeof instanceof
let a = []
let b = {}
console.log(typeof a) // object
console.log(typeof b) // object
console.log(a instanceof Array) // true
console.log(a instanceof Object) // false
console.log(b instanceof Object) // true
function User(){}
let c = new User()
console.log(typeof c) // object
console.log(c instanceof User) //true
console.log(c instanceof Object) //true
标签模板实例操作
const info = [
{name:'张三',age:18},
{name:'李四',age:19},
{name:'王五',age:20}
]
function template(){
return `
${info.map(item => showInfo`- 名字:${item.name},年龄:${item.age}
`).join('')}
`
}
function showInfo(strings, ...args){
console.log(strings)
// ["名字:", ",年龄:", " ", raw: Array(3)] * 3
console.log(args)
// ["张三", 18]
// ["李四", 19]
// ["王五", 20]
return strings.map((val,key) => {
return val + (args[key] ? args[key] : "")
}).join("")
}
document.body.innerHTML = template()
Object.is(val1,val2) / NaN
let arr = [1]
console.log(Number(arr)) // 1
let arr2 = [1,2]
console.log(Number(arr2)) // NaN
console.log(2 / 'a') // NaN
console.log(NaN == NaN) // false
console.log(Number.isNaN(2 / 'a')) // true
console.log(Object.is(2 / 'a',NaN)) // true
new Date / Date
const d1 = new Date()
console.log(d1) // Tue Mar 24 2020 17:16:00 GMT+0800 (中国标准时间)
console.log(new Date() * 1) // 1585041382989
console.log(typeof d1) // object
const d2 = Date()
console.log(d2) // Tue Mar 24 2020 17:16:00 GMT+0800 (中国标准时间)
console.log(new Date() * 1) // NaN
console.log(typeof d2) // string
// 获取时间戳
console.log(Date.now()) // 1585041382989
console.log(new Date() * 1)
console.log(new Date().valueOf())
console.log(new Date().getTime())
console.log(Number(new Date()))
// 时间戳转时间
console.log(Date.now()) // Tue Mar 24 2020 17:16:22 GMT+0800 (中国标准时间)
// 计算代码执行时间
console.time("runTime")
// any code
console.timeEnd("runTime") // runTime: 11.8548555567ms
// 自定义时间
const d3 = new Date("1999-9-16 5:15:20")
const d4 = new Date(1999,9,16,5,15,20)
console.log(d3) // Thu Sep 16 1999 05:15:20 GMT+0800 (中国标准时间)
console.log(d4) // Thu Sep 16 1999 05:15:20 GMT+0800 (中国标准时间)
时间格式化函数封装
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
}
let date = new Date()
console.log(dateFormat(date,"YYYY年MM月DD日"))
moment.js 库使用
Array.from
const str = "abcde"
let resArr = str.split(''); // ["a","b","c","d","e"]
console.log(Array.from(str)) // ["a","b","c","d","e"]
const divs = document.querySelectAll('div')
// 转换为数组
Array.from(divs)
// 转换为数组,并进行操作
Array.from(divs,(item)=>{
// item 为循环每个dom对象
})
toggle
dom.classList.toggle("className") // 原生 js 切换类名
数组方法
// fill 填充
let arr = [1,2,3,4,5]
console.log(Array(3).fill('a')) //['a','a','a']
arr.fill('a',2,4) // [1,'a','a',4,5]
// push,unshift(头部添加) 返回值为数组长度
// pop,shift(头部移除) 返回值为该元素
// splice(a,b,c) a:起始位置, b:移除数量, c:替换的数据
// 会改变原数组
let tempArr = arr.splice(0,3)
console.log(tempArr) // [1,2,3]
console.log(arr) // [4,5]
let arr2 = [1,2,3,4,5]
arr2.splice(1,0,'a') // [1,'a',2,3,4,5]
// copyWithin(a,b,c) a:起始替换位置, b:复制起始位置, c:复制结束位置 [b,c)
let arr3 = [1,2,3,4,5]
console.log(arr3.copyWithin(2,1,3)) // [1, 2, 2, 3, 5]
// find(callback) 、 findIndex(callback) -> 返回下标值
let arr4 = [1,2,3,4,5]
let obj = {{name:'zhangsan'},{name:'lisi'},{name:'wangwu'}}
let res = arr.find(item => {return item === 3}) // 3 (值), 没找到返回 undefined
let res2 = obj.find(item => {return item.name === 'lisi'}) // {name:'lisi'} (值)
// sort(callback) callback 返回值为负数(从小到大) 正数(从大到小)
// keys()、values()、entries()
let arr5 = ['a','b','c']
let keys = arr5.keys()
let { value, done } = keys.next() // 0 (下标) false (false表示没迭代完)
console.log(keys.next()) // {value: 1, done: false}
console.log(keys.next()) // {value: 2, done: false}
console.log(keys.next()) // {value: undefined, done: true}
while(({ value, done } = values.next()) && done === false){
console.log(value) // a,b,c
}
// entries 为 keys()、value() 集合
let entries = arr5.entries()
let {done,value:[index,value]} = entries.next()
console.log(index,value) // 0 "a"
for(let [key,value] of arr.entries()){
console.log(key,value) // 0 "a"
}
// every 判断是否全部符合(一个错误, 跳出循环)
// some 任意符合(一个正确, 跳出循环)
let arr6 = [1,2,3,4,5]
let res1 = arr6.every((value,index,arr)=>{
return value > 0
})
let res2 = arr6.some((value,index,arr)=>{
return value < 0
})
console.log(res1) // true
console.log(res2) // false
Symbol(生成一个不会重复的字符串)
let a = Symbol()
let b = Symbol()
console.log(typeof a) // symbol
console.log(a == b) // false
// 注意: Symbol不可以添加属性
// 第一种定义, 如果描述内容一样, 内容地址不一样, 会重复创建
let c = Symbol('我是描述信息')
console.log(c.description) // 我是描述信息
// 第二种定义, 如果描述内容一样, 内容地址一样, 不会重复创建
let d = Symbol.for('test')
let e = Symbol.for('test')
console.log(d == e) // true
console.log(Symbol.keyFor(d)) // test
console.log(Symbol.keyFor(c)) // undefined
let fs = Symbol("描述")
let f = {
name: "kevin",
age: "18",
[fs]: "any"
}
// 循环遍历不到Symbol (遍历不到 fs)
// 只遍历Symbol
for(const key of Object.getOwnPropertSymbols()){
console.log(key) // Symbol(描述)
}
set
方法 / 属性 | 解释 | 返回值 |
---|---|---|
size | set 长度 | 数量 |
has(item) | 是否包含item | boolean |
delete(item) | 删除item | boolean |
values() | 展示全部元素 | SetIterator {item1,item2 ...} |
clear() | 清除所有元素 | undefined |
add(item) | 添加元素 | Set |
let set = new Set()
set.add(1)
set.add(1)
console.log(set) // Set(1) {1}
// new Set(Array)
let a = new Set([1,2,3])
console.log(a) // Set(3) {1,2,3}
// set 转数组
console.log([...a]) // [1,2,3]
console.log(Array.from(a)) // [1,2,3]
// new Set(String)
console.log(new Set("hello")) // Set(5) {"h","e","l","l","o"}
let b = {}
let c = { [b]: 'b' }
console.log(c) // {[object Object]: "b"}
console.log(b.toString()) // [object Object]
console.log(c["[object Object]"]) // b
// Set 遍历 value 与 key 一样
set.forEach((value,key,set)=>{})
for(const value of set){}
// 并集、交集、差集
let d1 = new Set([1,2,3,4,5])
let d2 = new Set([1,3,6,7,4])
// 并集
console.log(new Set([...d1,...d2])) // Set(7) {1,2,3,4,5,6,7}
// 差集
console.log(new Set([...d1].filter(item => !d2.has(item)))) // Set(7) {2,5}
// 交集
console.log(new Set([...d1].filter(item => d2.has(item)))) // Set(7) {1,3,4}
Map
方法 / 属性 | 解释 | 返回值 |
---|---|---|
size | set 长度 | 数量 |
has(key) | 是否包含key | boolean |
delete(key) | 删除key对应的项 | boolean |
values() | 展示全部value | MapIterator {value1,value2...} |
clear() | 清除所有元素 | undefined |
set(key,value) | 添加元素 | Map |
let map = new Map()
// 添加元素1 map.set(key,value)
map.set("name","kevin")
// 添加元素2 new Map([[key,value],[...],...])
let map2 = new Map([[key,value],[key2,value2],...])
// Map 遍历
map.forEach((value,key)=>{})
for(const [key,value] of map.entries()){}
// Map 转换 Array
console.log([...map])
console.log([...map.values()])
this
对象中函数(一层)的this指向该对象
箭头函数中,this指向上层对象的this
普通函数,this指向window
apply、call、bind
call ( this , v1 , v2 , ... )
apply ( this , [ v1, v2, ...] )
call apply 会立即执行
bind 会返回一个新的函数,不会立即执行
bind 可以直接传参数,也可以间接调用新函数时传参数,参数会累积
function A(a,b){
console.log(a,b)
return this.c + a + b
}
console.log(A.call({c:5},1,2)) // a=1, b=2, c=3
let func = A.bind({c:5},1,2)
console.log(func()) // a=1, b=2, c=3
let func = A.bind({c:5},1)
console.log(func(2))// a=1, b=2, c=3
obj/array.hasOwnProperty("key")
判断该key(属性)是否在obj / array 对象( 排除原型链 )中,返回值为boolean
拓展:“key” in obj / array 判断属性key是否在obj / array 中(包含原型链)
Object.setPrototypeOf(对象,对象的原型)
设置对象的原型
let a = {name:"kevin"}
let b = {name:"jeff'"}
Object.setPrototypeOf(a,b)
console.log(a.__proto__) // {name: "jeff'"}
Object.assign(obj1,obj2,...)
将obj2覆盖obj1中的相同项,并返回一个新的对象
let a = {name:'kevin',akey:'a'}
let b = {name:'jeff',age:18}
let c = {ckey:'c'}
let d = Object.assign(a,b,c)
console.log(d) // {name: "jeff", akey: "a", age: 18, ckey: "c"}
JSON
JSON.stringify(a,b,c) 转换成json格式
- a: obj / arr
- b: 要保留的属性 , 格式 ["key1","key2",...] , null表示全部保留
- c: tab键的空格数 number 类型
JSON.parse(json,callback) json 转换成js对象格式
- callback(key,value)
let a = {
name:'kevin',
age:'18',
toJSON:function(){
return {
name:"自定义的JSON格式"
}
}
}
let b = ["name","age"]
console.log(JSON.stringify(a,null,2))
/*
{
"name": "kevin",
"age": "18"
}
*/
console.log(cJSON.stringify(a)) // {"name":"自定义的JSON格式"}
console.log(JSON.stringify(b)) // ["name","age"]
let json = JSON.stringify(a,null,2)
let o = JSON.parse(json,(key,value)=>{
console.log(key,value)
})
对象的深浅拷贝
- Object.assign(obj1,obj2,...) 浅拷贝
- {...obj} 深拷贝
let obj = {
name:'kevin',
user:{
name:'jeff'
},
arr:[]
}
// 浅拷贝
function copy(obj){
let res = {}
for(const key in obj){
res[key] = obj[key] // 出现问题: obj.user 依旧是地址赋值
}
return res
}
// 深拷贝 (浅拷贝 + 递归)
function deepCopy1(obj){
let res = {}
for(const key in obj){
// 出现问题: arr:[] 变成arr:{}
res[key] = typeof obj[key] == 'object'?deepCopy1(obj[key]):obj[key]
}
return res
}
// 深拷贝2 (浅拷贝 + 递归)
function deepCopy2(obj){
// 判断是数组还是对象
let res = obj instanceof Array ? [] : {}
for(const [k,v] of Object.entries(obj)){
res[k] = typeof v == "object" ? deepCopy2(v) : v
}
return res
}
Object.getOwnPropertyDescriptor(obj,key)
功能:查看对象属性的特征
联想: 数组的 length 属性不能遍历
let user = {
name:'kevin',
age:18
}
console.log(JSON.stringify(Object.getOwnPropertyDescriptor(user,name),null,2))
/**
{
"value": "kevin",
"writable": true, // 可修改的
"enumerable": true, // 可遍历的
"configurable": true // 可删除或重新配置特征
}
*/
// 获取所有属性的特征
Object.getOwnPropertyDescriptors(user)
// 修改属性特征
Object.getOwnPropertyDescriptor(user,'name').writable = false // 错误的方式
Object.defineProperty(user,"name",{ // 正确
value: 'jeff', // 修改属性值
writable: false // 修改属性特征
})
// 批量修改
Object.defineProperties(user,{
key1:{
},
key2:{
},
...
})
Object.preventExtensions(obj)
禁止在对象obj中添加属性
Object.isExtensible(obj):判断是否可以修改
Object.seal(obj)
功能:封闭对象,不允许任何操作属性的特征
Object.isSeald(obj):判断对象特征是否封闭
Object.freeze(obj)
功能:冻结对象,只允许遍历
Object.isFrozen(obj):判断是否冻结
// 使用严格模式
"use strict"
const CONFIG = {
url:"http://****"
}
Object.freeze(CONFIG)
CONFIG.url = "any" // 报错
console.log(JSON.stringify(Object.getOwnPropertyDescriptor(CONFIG,url),null,2))
/**
{
"value": "http://****",
"writable": false,
"enumerable": true, // 可遍历
"configurable": false
}
*/
访问器保护数据
const user = {
data:{name: "kevin", age: 18},
// 设置属性访问器
set age(age){
if(typeof age != "number" || age >100 || age < 18){
throw new Error("年龄更改错误")
}
this.data.age = age
},
// 获取属性访问器
get age(){
console.log(this.data.age)
}
}
user.age = 20
console.log(user.age) // 20
// get访问器伪造属性
const user = {
arr:[1,2,3,4,5],
get total(){
return this.arr.reduce((p,n) => p +n,0)
}
}
console.log(user.total) // 15
user.total = 18 // 没有效果(没有set访问器), 严格模式报错
访问器的优先级
访问器的优先级高于普通属性
提示:使用Symbol的唯一性作为对象的属性,外部无法更改内部属性
const user = {
name:'kevin',
get name(){
return '233'
}
}
console.log(name) // "233"
token的读写处理
let Request = {
set token(content){
localStorage.setItem('token',content)
},
get token(){
let token = localStorage.getItem('token')
!token ? return "请登录后操作" : return token
}
}
// 设置token
Request.token = "545453445556566656"
console.log(Request.token) // 545453445556566656
Proxy 代理拦截
// 基本使用
// 对象代理
const user = {name:"kevin"}
const proxy = new Proxy(user,{
set(obj,property,value){
obj[property] = value
return true
},
get(obj,property){
console.log(obj,property) // {name:"kevin"} name
return obj[property] // kevin
}
})
console.log(proxy.name) // kevin
proxy.name = 'jeff'
console.log(proxy.name) // jeff
// 函数代理
function add(a,b){
return a + b
}
let proxy = new Proxy(add,{
apply(func,obj,args){
console.log(func,obj,args)
// func 当前函数对象
// undefined this指向
// (2) [1, 2] 函数参数
console.log(func.apply(this,args)) // 3
}
})
proxy(1,2)
proxy.apply({},[1,2]) // 改变this为{}
Vue数据绑定
输入 123
使用Proxy验证表单组件
instanceof
原型检测
in key in obj // 判断key属性是否在obj 或其原型链上
hasOwnProperty(key) // 判断key属性是否在obj上
function A(){}
function B(){}
let a = new A()
let b = new B()
console.log(a instanceof A) // true
A.prototype = b
console.log(a instanceof B) // true
console.log(b instanceof A) // false
console.log(A.__proto__.constructor.prototype) // B{}
console.log(b.constructor.prototype == b.__proto__) // true
构造方法
function User(name){
this.name = name
}
User.prototype = {
constructor: User,
show(){
console.log(this.name)
},
...
}
let u = new User("kevin")
u.show() // kevin
proto属性访问器
proto设置为普通类型没有效果
proto 中有get set访问属性
const obj = {}
obj.__proto__ = {
show(){
console.log("233")
}
}
obj.show() // 233 (向obj的原型添加show方法)
obj.__proto__ = "233" // 语句无效
// 原理
let obj = {
action:{},
get proto(){
return this.active
},
set proto(obj){
if(obj instanceof Object){
this.action = obj
}
}
}
obj.proto = "abc" // 无效
obj.proto = {a:"abc"} // 有效
//
let obj = Object.create(null) // 没有原型链
obj.__proto__ = "abc" // 成功
原生继承的实现
function extend(sub,sup){
sub.prototype = Object.create(sup.prototype)
Object.defineProperty(sub.prototype,"constructor",{
value:sub,
enumerable:false
})
}
class
class User{
constructor(name){
this.name = name
}
getName(){
return this.name
}
setName(name){
this.name = name
}
}
let u = new User("kevin")
console.log(u.getName()) // kevin
静态方法
static 定义,类名直接调用
class User{
show(){
console.log("prototype show")
}
static show = function(){
console.log("static show")
}
}
User.show() // static show
new User.show() // prototype show
私有属性
class User{
#name = 'kevin'
constructor(age){
this.age = age
}
show(){
return #name
}
set name(name){
this.name = name
}
}
let u = new User(18)
u.#name = "ccc" // 报错,不允许修改私有属性
u.name = "ccc" // 修改私有属性
class 继承
class Fu{
constructor(name){
this.name = name
console.log(name)
}
}
class Zi extends Fu{
constructor(name){
super(name)
}
}
let zi = new Zi("zhangsan") // zhangsan
原型继承
function User(){}
User.prototype.show = function(){
console.log("func show")
}
function People(){}
// 实现继承
Admin.prototype = Object.create(User.prototype)
let p = new People()
p.show() // func show
super 原理
new 子类时,自动调用父类构造方法 constructor
如果子类没有定义constructor,默认constructor调用super
子类如果定义了constructor,就必须调用super
super必须放在子类赋值之前,放置父类属性覆盖子类属性
方法、属性 同名,使用super.func()
let a = {
name:"a",
show(){
console.log("this is a")
console.log(this.name) // a
}
}
let b = {
name:"b",
// 对象继承
__proto__ : a,
show(){
// 执行父级方法
this.__proto__.show.call(this) // this is a a
console.log("this is b")
}
}
b.show()
静态继承原理
function User(){
User.name = "kevin",
User.show = function(){
console.log("User show")
}
}
function P(){}
P.__proto__ = User
P.show() // User show
p.name // kevin
// class
class User{
static name = "kevin"
static show(){
console.log("User show")
}
}
class P extends User{}
console.log(P.name) // kevin
P.show() // User show
动画类
class Animation {
constructor(el) {
this.el = el;
this.timeout = 5;
this.isShow = true;
this.defaultHeight = this.height;
}
hide(callback) {
this.isShow = false;
let id = setInterval(() => {
if (this.height <= 0) {
clearInterval(id);
callback && callback();
return;
}
this.height = this.height - 1;
}, this.timeout);
}
show(callback) {
this.isShow = false;
let id = setInterval(() => {
if (this.height >= this.defaultHeight) {
clearInterval(id);
callback && callback();
return;
}
this.height = this.height + 1;
}, this.timeout);
}
get height() {
return window.getComputedStyle(this.el).height.slice(0, -2) * 1;
}
set height(height) {
this.el.style.height = height + "px";
}
}
class Slide {
constructor(el) {
this.el = document.querySelector(el);
this.links = this.el.querySelectorAll("dt");
this.panels = [...this.el.querySelectorAll("dd")].map(
item => new Panel(item)
);
this.bind();
}
bind() {
this.links.forEach((item, i) => {
item.addEventListener("click", () => {
this.action(i);
});
});
}
action(i) {
Panel.hideAll(Panel.filter(this.panels, i), () => {
this.panels[i].show();
});
}
}
class Panel extends Animation {
static num = 0;
static hideAll(items, callback) {
if (Panel.num > 0) return;
items.forEach(item => {
Panel.num++;
item.hide(() => {
Panel.num--;
});
});
callback && callback();
}
static filter(items, i) {
return items.filter((item, index) => index != i);
}
}
let hd = new Slide(".s1");
// 调用
let dom = document.querySelector('.class')
let a = new Animation(dom)
a.hide(()=>{
console.log("隐藏结束")
})
开发一个模块引擎
let mudule = (function(){
const moduleList = {} // 模块容器
// 模块名,依赖模块,模块动作
function define(name,modules,action){
modules.map((m,i)=>{
modules[i] = moduleList[m]
})
moduleList[name] = action.apply(null,modules)
}
return { define }
})()
// 定义模块 a
mudule.define('a',[],function(){
return {
// 模块功能
max(arr,key){
return arr.sort((a,b)=>b[key]-a[key])[0]
},
min(arr,key){
return arr.sort((a,b)=>a[key]-b[key])[0]
}
}
})
// b 模块依赖 a 模块
module.define('b',['a'],function(a){
let data = [
{name:'js',price:199},
{name:'mysql',price:233}
]
console.log(a.max(data,'price')) // {name:'js',price:199}
})
模块按需加载
import 语法 返回promise ,不必写在最上层
if(true){
import("路径").then(({a,b})=>{
console.log(a,b)
})
}
promise 封装ajax
function ajax(url){
return new Promise((resolve,reject)=>{
let xhr = new XHRHttpRequest()
xhr = open("GET",url)
xhr.send()
xhr.onload = function(){
if(this.status == 200){
resolve(this.response)
}else{
reject(this.status)
}
}
xhr.onerror = function(){
reject(this)
}
})
}
缓存后台数据
function query(name){
const cache = query.cache || (query.cache = new Map())
if(cache.has(name)){
console.log("缓存了")
return Promise.resolve(cache.get(name))
}
// 请求数据
resolve ajax().then()
}