事件委托
利用冒泡的原理,把事件加到父级上,触发执行效果
event.target target.nodeName来判断是哪个标签
优点:
1、减少事件注册,节省内存。比如,
在table上代理所有td的click事件。
在ul上代理所有li的click事件。
2、简化了dom节点更新时,相应事件的更新。比如
不用在新添加的li上绑定click事件。
当删除某个li时,不用移解绑上面的click事件。
缺点:
1、事件委托基于冒泡,对于不冒泡的事件不支持。
2、层级过多,冒泡过程中,可能会被某层阻止掉。
3、理论上委托会导致浏览器频繁调用处理函数,虽然很可能不需要处理。所以建议就近委托,比如在table上代理td,而不是在document上代理td。
4、把所有事件都用代理就可能会出现事件误判。比如,在document中代理了所有button的click事件,另外的人在引用改js时,可能不知道,造成单击button触发了两个click事件。
//例子
<body>
<div id="div1"></div>
</body>
window.onload = function(){
let body = document.querySelector('body');
let div1 = document.getElementById('div1');
body.addEventListener('click',function(){
console.log('打印body')
})
div1.addEventListener('click',function(){
console.log('打印div1')
})
}
文档碎片
document.createDocumentFragment() 一个容器,用于暂时存放创建的dom元素
原型模式的优缺点:
1、优点:可以让所有的对象实例共享它所包含的属性和方法
2、缺点:原型中是所有属性都是共享的,但是实例一般都是要有自己的单独属性的。所以一般很少单独使用原型模式。
prtotype、proto、constructor
◆每一个构造函数,都有一个原型[[prototype]]属性 指向构造函数的原型对象
◆每一实例化对象都有一个隐式原型_proto_ 指向构造函数的原型对象
◆每一个原型对象都有一个默认的constructor属性,指向对象的构造函数
闭包
指的是:能够访问另一个函数作用域的变量的函数
《JavaScript高级编程》书中建议:由于闭包会携带包含它的函数的作用域,因为会比其他函数占用更多内容,过度使用闭包,会导致内存占用过多。
//例如:
function init() {
var name = "Mozilla"; // name 是一个被 init 创建的局部变量
function displayName() { // displayName() 是内部函数,一个闭包
alert(name); // 使用了父函数中声明的变量
}
displayName();
}
init();
js链式作用域(冒泡同理):
子对象会一级一级向上寻找所有父对象的变量,反之不行。
js变量两种作用域:
全局变量、局部变量(函数内):js中函数内部可以读取全局变量,函数外部不能读取函数内部的局部变量。
闭包为什么可以实现在函数外读取到函数内的变量:
原因:init是displayName的父函数,displayName被赋给了一个全局变量,displayName始终存在内存中,displayName的存在依赖init因此init也始终存在内存中,不会在调用结束后,被垃圾回收机制回收。
class es6
super()===A.prototype.constructor.call(this)。
super可以造访继承的父级原型对象、可访问父级的原型方法(针对static静态方法调用)
array数组的增删改查排序
增加:
push() 方法可向数组的末尾添加一个或多个元素
unshift() 方法是向数组头部添加一个或多个元素,使用上同push方法
concat() 连接两个或以上的数组,返回的是一个新数组,不影响原数组
删除:
pop() 方法删除数组最后一个元素,该方法会改变原数组,删除元素并且数组长度-1,返回值是删除的元素的值,如果数组是空数组,则不进行删除,返回值是undefined
shift() 方法删除数组第一个元素,使用上同pop方法
修改:
slice(start,end) 数组的截取函数,start 必需,end 选填 ,均可以为负数,返回的是start到end(不包括end)之间的元素,返回新数组,不影响原来数组 (slice 切开)
splice(index,howmany,item1,.....,itemX) 方法删除或者添加数组,会操作原数组,返回的是含有被删除的元素的数组,index 必需 起始位置,howmany 必需 数量可以为0,即不操作,第三个参数添加到数组 替代数组index的位置
排序:
sort() 对数组进行排序,改变的是原数组元素顺序,默认是按字符编码排序,所以在遇到数字排序时,就需要定义函数
reverse() 颠倒元素顺序,改变原数组
其他:
indexOf() 找出某个元素在数组中的索引,并返回该元素索引。
join() 方法将数组拆分成字符串,返回值字符串,默认分隔符为逗号“,”
toString() 将数组转换成字符串,返回字符串,格式为逗号隔开
Object属性方法
var obj = { 0: "a", 1: "b", 2: "c"}; // 以下示例以此对象为例
//属性:
Object.prototype.writable//:默认为false
Object.prototype.enumerable//:默认为false
Object.prototype.configurable//:默认为false
Object.prototype.constructor//:用于创建一个对象的原型。
//常用方法:
Object.prototype.hasOwnProperty()//:返回一个布尔值,表示某个对象是否含有指定的属性,而且此属性非原型链继承。
Object.prototype.isPrototypeOf()//:返回一个布尔值,表示指定的对象是否在本对象的原型链中。
Object.prototype.propertyIsEnumerable()//:判断指定属性是否可枚举。
Object.prototype.toString()//:返回对象的字符串表示。
Object.prototype.watch()//:给对象的某个属性增加监听。
Object.prototype.unwatch()//:移除对象某个属性的监听。
Object.prototype.valueOf()//:返回指定对象的原始值。
Object.create(proto,[propertiesobject])//:创建一个拥有指定原型和若干个指定属性的对象。
Object.keys(obj) = Object.getOwnPropertyNames(obj).sort()//:返回一个由给定对象的所有可枚举自身属性的属性名组成的数组
//举例:
console.log(Object.getOwnPropertyNames(obj).sort()); //["0", "1", "2"]
Object.keys(obj)//["0", "1", "2"]
Object.values(obj)//:返回一个包含指定对象所有的可枚举属性值的数组,数组中的值顺序和使用for…in循环遍历的顺序一样。
//举例:
Object.values(obj);//["a", "b", "c"]
Object.entries(obj)//:返回一个包含由给定对象所有可枚举属性的属性名和属性值组成的 [属性名,属性值] 键值对的数组,数组中键值对的排列顺序和使用for…in循环遍历该对象时返回的顺序一致。
//举例:
console.log(Object.entries(obj)); // [["0","a"],["1","b"],["2","c"]]
Object.assign(target, …sources)//:参考数组操作方法concat(),把任意多个的源对象自身的可枚举属性拷贝给目标对象,然后返回目标对象。
//举例:
Object.assign(obj,{3:'d'},{4:'e',5:'f'});//{0: "a", 1: "b", 2: "c", 3: "d", 4: "e", 5: "f"}
//不常用的方法:
Object.getPrototypeOf(object)//:返回该对象的原型。
Object.is(value1, value2)//:判断两个值是否是同一个值。
Object.isExtensible(obj)//:判断一个对象是否是可扩展的(是否可以在它上面添加新的属性)。
Object.isFrozen(obj)//:判断一个对象是否被冻结(frozen)。
Object.isSealed(obj)//:判断一个对象是否是密封的(sealed)。密封对象是指那些不可 扩展 的,且所有自身属性都不可配置的(non-configurable)且属性不可删除的对象(其可以是可写的)。
Object.freeze(obj)//:冻结一个对象,冻结指的是不能向这个对象添加新的属性,不能修改其已有属性的值,不能删除已有属性,以及不能修改该对象已有属性的可枚举性、可配置性、可写性。也就是说,这个对象永远是不可变的。该方法返回被冻结的对象。
Object.getOwnPropertyDescriptor(obj, prop)//:返回指定对象上一个自有属性对应的属性描述符。
Object.defineProperties(obj, props)//:在一个对象上添加或修改一个或者多个自有属性,并返回该对象。
Object.defineProperty(obj, prop, descriptor)//:直接在一个对象上定义一个新属性,或者修改一个已经存在的属性, 并返回这个对象。obj:需要定义属性的对象。prop:需定义或修改的属性的名字。descriptor:将被定义或修改的属性的描述符。
Set 和 Map es6
相同点:Set和Map都可以用来生成新的 Map
例:
var a = [['foo', 1],['bar', 2]];
new Map(new Set(a)) === new Map(a) === Map(2) {"foo" => 1, "bar" => 2}
// 当然上例虽然值是相等的但是实际并不相等,这里只是看结果,因为Map 的键实际上是跟内存地址绑定
不同点:
1、Set适合操作数组,Map适合操作对象
2、Map具有set(key, value)和get(key)方法操作数据 Set使用add(value)方法
set 不重复的值的集合 es6
使用:new set()
//数组去重:
1、[...new Set(array)]
2、Array.from(new Set(array))
//字符串去重
[...new Set(string)].join('')
遍历:
方法 同Object :因为Set方法内部为对象形式。
new Set().add('a').add('b').forEach(data=>{console.log(data)}) //a //b
方法 同array :具有数组的特性
for(let data of new Set().add('a').add('b').keys()){console.log(data)} //a //b
map
同Set
Echarts
实现方式 纯 js 实现,MVC 封装,利用canvas绘制图形
特点:重要性和优先级依次递减,设计效果直观、生动,能够交互,可个性化定制。
MVC 架构:
Storage(M):模型层,实现图形数据的CURD(增删改查)管理;
Painter(V): 视图层,实现canvas 元素的生命周期管理,即:视图渲染、更新控制、绘图;
Handler©:控制层,事件交互处理,实现完整的dom事件模拟封装。
Proxy es6
代理拦截
//target参数表示所要拦截的目标对象,handler参数也是一个对象,用来定制拦截行为。
var proxy = new Proxy(target, handler);
js内存分配(垃圾回收机制)
内存生命周期
不管什么程序语言,内存生命周期基本是一致的:
1、分配你所需要的内存
2、使用分配到的内存(读、写)
3、不需要时将其释放\归还 (对象有没有其他对象引用到它)
垃圾回收
- 引用:如果没有引用指向该对象(零引用),对象将被垃圾回收机制回收 标记-清除算法 从根(全局对象)开始
- 将可能被引用的对象用递归的方式进行标记,然后将没有标记到的对象作为垃圾进行回收。
Promise构造函数 es6
语法:
new Promise( function(resolve, reject) {...} /* executor */ );
方法
Promise.all()
Promise.allSettled()
Promise.any()
Promise.prototype.catch()
Promise.prototype.finally()
Promise.prototype.then()
Promise.race()
Promise.reject()
Promise.resolve()
有以下几种状态:
pending: 初始状态,既不是成功,也不是失败状态。
fulfilled: 意味着操作成功完成。
rejected: 意味着操作失败。
Promise + axios +qs 同步操作
关键字说明:
async:放在函数声明之前,使其成为 async function
await:它会暂停代码在该行上,直到 promise 完成
//模拟ajax异步操作1
function ajax1() {
const p = new Promise((resolve, reject) => {
this.$axios({
url: '',
method: 'POST',
data: this.qs.stringify({a:1})
}).then(function (res) {
resolve(res.data)
})
})
return p
}
//模拟ajax异步操作2
function ajax2() {
const p = new Promise((resolve, reject) => {
this.$axios({
url: '',
method: 'POST',
data: this.qs.stringify({a:1})
}).then(function (res) {
resolve(res.data)
})
})
return p
}
//等待两个ajax异步操作执行完了后执行的方法
async function myFunction() {
const x = await ajax1()
console.log(x)
const y = await ajax2()
//等待两个异步ajax请求同时执行完毕后打印出数据
console.log(x, y)
}
Date日期时间戳获取转换
//获取一个时间对象 可以添加时间或者时间戳 例如new Date(1594224000000)
var time = new Date() ;
/*
*方法:
*/
var year = time.getFullYear() // 获取年
var month = time.getMonth(); // 获取月 注:月份从0开始计数 所以这里需要+1得到实际月份
var hour = time.getHours(); // 获取小时
var minute = time.getMinutes(); // 获取分钟
var second = time.getSeconds(); // 获取秒
/*
*将日期格式转换成时间戳:
*/
var time1 = date.getTime();
var time2 = date.valueOf();
var time3 = Date.parse(date);
//三种获取的区别:
time1 、time2:会精确到毫秒,其实这两种方法是有区别的在万为单位的获取中会有差异
time3:只能精确到秒,毫秒将用0来代替
/*
*date的几种参数形式 :
*月份从0~11
*/
//
new date("month dd,yyyy hh:mm:ss");
new date("month dd,yyyy");
new date("yyyy/mm/dd hh:mm:ss");
new date("yyyy/mm/dd");
new date(yyyy,mth,dd,hh,mm,ss);
new date(yyyy,mth,dd);
new date(ms); // (1594224000000)
注:经常我们的日期格式会用“-”链接,也就是“2018-08-08”这种形式,放入以下方法有可能不会报错,但是手机浏览器会报错,避免不必要的麻烦,尽量转换成以下任意一种格式使用。
模块化开发
模块化是一种将系统分离成独立功能部分的方法,可将系统分割成独立的功能部分,严格定义模块接口、模块间具有透明性。
优点:
1、代码重用时,引入js文件的数目可能少了,避免来代码的累赘。
2、代码复用高,开发效率也会提高。
3、方便后期的维护
缺点:
1.系统分层,调用链会很长
2.模块间通信,模块间发送消息会很耗性能
常见的模块化的写法
1、原始写法(封装函数)
这种做法的缺点很明显:"污染"了全局变量,无法保证不与其他模块发生变量名冲突,而且模块成员之间看不出直接关系。
2、对象写法
这样的写法会暴露所有模块成员,内部状态可以被外部改写
3、立即执行函数写法
立即执行函数可以达到不暴露私有成员的目的
解构赋值:es6
重点:
1、等号左边为var 的变量,右边为值得数组,两边通过key值一一赋值。
2、如果左边有属性赋值,就赋值右侧的对象属性。
3、只要等号右边的值不是对象或数组,就先将其转为对象 ,所以undefined和null 无法转换,会报错
简单了解解构赋值(数组的对象都有一个length属性):
以下例子统一变量 :
const str = '123',
value = [4, 5, 6],
obj={a:7,b:8,c:9};
以下例子统一打印方法:
console.log('a='+a,'b='+b,'c='+c);
1、字符串: 变量 = 值
let [a,b,c] = str;
// 解析过程var [a,b,c][0]=str[0],[a,b,c][1]=key[1],[a,b,c][2]=[a,b,c][2];
//结果var a=1,b=2,c=3;
2、数组:数组[0] = 数组[0]
let [a,b,c] = value // 解析过程如上,结果为:var a=4,b=5,c=6;
3、对象:
let {a, b, c} = obj;//解析过程如上,结果为:var a=7,b=8,c=9;
4、函数:这里涉及到解构赋值以及默认值方式,注意函数的结构赋值跟以上三种赋值方式一样,这里提供一个例子:
function add({x, y,z = 0}){
return x + y +z;
}
console.log(add({x : 1, y :2}))//3
5、属性赋值(以上讲的都是变量赋值,如果给变量添加属性,那么就是属性赋值):
let { valueOf: a } = obj; // ƒ valueOf() { [native code] }
说明:上诉valueOf设置之后解析的就是obj的valueOf属性 如果设置其他属性同理。
这里打印出来a的值为 obj.prototype.valueOf
默认值: 所有定义的左侧变量都可以设置默认值 使用方式 ‘key=value’赋值,作用于右侧没有相关赋值操作后,保留默认值,否则更新值。
例如:
let [a = 44,b,c,d = 77] = value
// 解析过程如上,
//结果为:var a=4,b=5,c=6,d=77;
转载:https://blog.csdn.net/qq_27751965/article/details/107681017