闭包,原型,继承

mac2026-08-18  2

闭包

闭包:闭包就是函数嵌套时,将局部变量进化成私有变量的环境,这个环境一般是作用域的嵌套,通俗的来说就是函数里面套函数,将原本要删除的变量,不删除,继续使用。 计算机的垃圾回收机制:不立即删,先放在临时空间内,可以二次或继续使用 特点: 闭包是将函数内部和函数外部连接起来的桥梁 可以读取函数内部的变量 让这些变量的值,始终保存在内存中,不会在调用结束后被系统回收 避免全局变量命名空间的污染 内存消耗很大,不能滥用 闭包会在父函数外部,改变父函数内部变量的值

注:一旦内部函数调用外部函数的局部变量,那么这个时候,这个局部变量就会变成内部函数的私有变量

闭包的应用:

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>
最新回复(0)