闭包
闭包:闭包就是函数嵌套时,将局部变量进化成私有变量的环境,这个环境一般是作用域的嵌套,通俗的来说就是函数里面套函数,将原本要删除的变量,不删除,继续使用。
计算机的垃圾回收机制:不立即删,先放在临时空间内,可以二次或继续使用
特点:
闭包是将函数内部和函数外部连接起来的桥梁
可以读取函数内部的变量
让这些变量的值,始终保存在内存中,不会在调用结束后被系统回收
避免全局变量命名空间的污染
内存消耗很大,不能滥用
闭包会在父函数外部,改变父函数内部变量的值
注:一旦内部函数调用外部函数的局部变量,那么这个时候,这个局部变量就会变成内部函数的私有变量
闭包的应用:
1.循环中的事件,获取计数器的值
var ali = document.querySelectorAll("li");
for(var i=0;i<ali.length;i++){
ali[i].onclick = (function(a){
return function(){
console.log(a);
}
})(i)
}
2.在计时器的回调函数中传参
function fn(str){
return function(){
console.log(str);
}
}
setTimeout(fn("html"), 1000);
利用闭包封装事件委托:
function entrust(achild,cb){
return function(e){
for(var i=0;i<achild.length;i++){
if(achild[i] === e.target){
cb.bind(e.target)(); //改变this指向
}
}
}
}
原型
原型:prototype
隐式原型:proto
实例:new出来的对象
构造函数:构造器,被new的那一方
function Fn(){}
function Fun(){}
Fun.prototype = new Fn();
var f = new Fn();
var f2 = new Fun();
console.log(Fn.prototype.constructor === Fn); //true
console.log(Fn.prototype.constructor === f.__proto__.constructor); //true
console.log(f.__proto__.constructor === Fn); //true
console.log(Fn.prototype.constructor === f.constructor); //true
Fn:构造函数
Fn.prototype:构造函数的原型
Fn.prototype.constructor:是构造函数的原型内的指向当前原型所在构造函数的属性
f:实例,new构造函数出来的对象,这个对象的父级是构造函数的原型
f.proto:实例的父级
**查看实例对象f是否有指针指向构造函数Fn的原型:**两种使用,如果是返回ture,如果不是返回false
**isPrototypeOf()**用于检测两个对象之间似乎否存在这种关系
Fn.prototype.isPrototypeOf(f) // 查看 Fn 的 prototype 对象,是否是 f 原型
instanceof运算符
注意:instanceof运算符右侧为构造函数,并且js中所有原型都来自Object构造函数
console.log(f instanceof Fn) // 查看 f 对象是否是构造函数 Fn 的实例
console.log(f instanceof Object)
继承
只要某个对象使用了另一个对象具有,而自身不具有的功能,就叫继承
构造函数继承:改变this指向继承
只能继承构造函数中this身上的属性和方法,不能继承原型身上的属性和方法
function Parent(n){
this.num = n;
this.show = function(){
console.log(this.num);
}
}
Parent.prototype.init = function(){
console.log("hello");
}
function Child(n){
//在Child中使用Parent中的方法和属性
// P中的this是将来new出来的p;
//强行将P的this指向C的this
Parent.call(this,n);
//Parent.apply(this,[n]);
//Parent.bind(this,n)();
}
var p = new Parent(12);
p.show(); //12
p.init(); //hello
var c = new Child(15);
c.show(); //15
c.init(); //报错
原型对象继承:只能继承原型身上的属性和方法,不能继承构造函数中this的属性和方法
function Parent(n){
this.num = 123;
this.show = function(){
console.log(this.num);
}
}
Parent.prototype.init = function(){
console.log("hello");
}
function Child(n){}
//直接将原型作为一个对象复制(浅拷贝)
//Child.prototype = Parent.prototype
//这里更改会全部都更改,因为对象是浅拷贝的,因此要使用深拷贝,遍历一一对应
//深拷贝
for(var i in Parent.prototype){
Child.prototype[i] = Parent.prototype[i];
}
Child.prototype.init = function(){
console.log("html");
}
var p = new Parent(12);
p.init(); //hello
console.log(p.num); //123
var c = new Child(15);
c.init(); //html
console.log(c.num); //报错
原型链继承:既能继承原型身上的属性和方法,又能继承构造函数中的this的属性和方法,但是不方便传参
function Parent(n){
this.num = n;
}
Parent.prototype.init = function(){
console.log("hello");
}
function Child(n){}
Child.prototype = new Parent(15);
Child.prototype.init = function(){
console.log("html");
}
var p = new Parent(12);
p.init(); //hello
console.log(p.num); //12
var c = new Child();
c.init(); //html
console.log(c.num); //15
混合继承:混合原型继承和构造函数继承,是常用的继承方式之一
function Parent(n){
this.num = n;
this.show = function(){
console.log(this.num);
}
}
Parent.prototype.init = function(){
console.log("hello");
}
function Child(n){
//构造函数继承
Parent.call(this,n);
}
//原型继承
for(var i in Parent.prototype){
Child.prototype[i] = Parent.prototype[i];
}
Child.prototype.init = function(){
console.log("html");
}
var p = new Parent(12);
p.init(); //hello
console.log(p.num); //12
var c = new Child(15);
c.init(); //html
console.log(c.num); //15
ES6继承(class继承),混合继承具有改变this指向的特性,原型链继承,是常用继承方式之一
class Parent{
constructor(n) {
this.num = n;
}
init(){
console.log(this.num);
}
}
class Child extends Parent{
constructor(n){
//类似有call,也可以接收参数
super(n);
}
}
var p = new Parent(123);
p.init();
var c = new Child(321);
c.init();
继承的应用:一个页面有两个元素,都有拖拽,一个有边界限定,一个没有边界限定
注意:
因为利用事件监听绑定和删除事件, 所以得有事件处理函数的名字
因为需要给事件处理函数加名字, 所以要将事件处理函数单独封装
因为单独封装, 所以导致事件处理函数中的this不再指向实例
因为时间处理函数中的this不再指向实例, 所以需要使用bind方法改变this指向
因为bind每次执行会返回新函数, 所以需要提前将要改变this指向的函数使用bind处理好
<style>
.box1{width:100px;height:100px;background: red;position: absolute;left:0;top:0;}
.box2{width:100px;height:100px;background: blue;position: absolute;left:0;top:130px;}
</style>
<body>
<div class="box1"></div>
<div class="box2"></div>
</body>
<script>
class Drag{
constructor(ele){
this.ele = ele;
this.m = this.move.bind(this);
this.u = this.up.bind(this);
this.addEvent();
}
addEvent(){
this.ele.addEventListener("mousedown",this.down(this))
}
down(that){
return function(e){
that.x = e.offsetX;
that.y = e.offsetY;
// console.log(that)
document.addEventListener("mousemove",that.m)
document.addEventListener("mouseup",that.u)
}
}
move(e){
this.ele.style.left = e.clientX - this.x + "px";
this.ele.style.top = e.clientY - this.y + "px";
}
up(){
document.removeEventListener("mousemove",this.m)
document.removeEventListener("mouseup",this.u)
}
}
class SmallDrag extends Drag{
constructor(ele){
super(ele);
}
move(e){
var l = e.clientX - this.x;
var t = e.clientY - this.y;
if(l<0) l=0;
if(t<0) t=0;
if(l > document.documentElement.clientWidth - this.ele.offsetWidth){
l = document.documentElement.clientWidth - this.ele.offsetWidth
}
this.ele.style.left = l + "px";
this.ele.style.top = t + "px";
}
}
var obox1 = document.querySelector(".box1");
var obox2 = document.querySelector(".box2");
new Drag(obox1);
new SmallDrag(obox2);
</script>