<script> /*1.如何区分私有变量和全局变量? 1)在全局做用域下声明(预解释的时候上)的变量是全局变量 2)在“私有做用域中声明的变量”和“函数的形参”都是私有变量 在私有做用域中,咱们代码执行的时候遇到了一个变量,首先咱们须要肯定它是否为私有的变量,若是是私有的变量,那么和外面的没有任何的关系;若是不是私有的,则往当前做用域的上级做用域进行查找,若是上级做用域也没有则继续查找,一直找到window为止 ...(做用域链) 2.当函数执行的时候(直接目的:让函数体中的代码执行),首先会造成一个新的私有的做用域,而后按照以下的步骤执行: 1)若是没有形参,先给形参赋值 2)进行私有做用域中的预解释 3)私有做用域中的代码自上而下执行 ... 4)函数造成一个新的私有的做用域保护了里面的私有变量不受外界干扰(外面修改不了里面的),私有的也修改不了外面的-》闭包 闭包:闭包是一种机制,函数执行的时候造成了一个私有的做用域,保护里面的私有变量不受外界干扰。 //预解释的时候无论你的条件是否成立,都要把带var的进行提早的声明 //window的预解释:var num; -> window.num if(!('num' in window)){ var num = 12; } console.log(num) // undefined 3.执行函数定义的那个function在全局做用域下不进行预解释,当代码执行到这个位置的时候定义和执行一块儿完成了 // 自执行函数:定义和执行一块儿完成了,不进行预解释 (function(num){})(100) ~function(num){}(100 +function(num){}(100) -function(num){}(100) !function(num){}(100) 4.函数体中的return下面的代码虽然不在执行了,可是须要进行预解释;return后面跟着的都是咱们的返回值,因此不进行预解释。 function fn(){ console.log(num); // undefined return function(){ }; var num = 10; } fn(); 5.在预解释的时候,若是名字已经声明过了,不须要从新声明,可是须要从新赋值;在JS中若是变量的名字和函数的名字重复了,也算冲突 预解释:var fn; window.fn; fn = xxxfff000 window.fn = xxxfff000 var fn = 10; function fn(){ console.log('ok'); } //window预解释: //声明+定义 fn = xxxfff11 //声明 var fn;(不须要从新声明) //声明(不重复进行) + 定义 fn = xxxfff222 //->fn=xxxfff222 fn(); function fn(){ console.log(1) } fn(); var fn = 10; fn(); function fn(){ console.log(2) } fn(); //如何查找当前做用域上一级做用域 //看当前函数是在哪一个做用域下定义的,那么它的上级做用域就是谁->和函数在哪执行的没有任何关系 var num = 12; function fn(){ var num = 120; return function(){ console.log(num); }; } var f = fn(); f(); //120 ~function(){ var num = 1200; f() //120 } // 堆内存 // 对象数据类型或者函数数据类型在定义的时候首先会开辟一个堆内存,堆内存有一个引用的地址,若是外面有变量等引用了这个地址,咱们就说这个内存被占用了,就不能销毁了。 咱们要让堆内存释放/销毁,只须要把这个引用它的变量赋值为null。若是当前的堆内存没有任何东西被占用了,那么浏览器会在空闲的时候把它销毁。。。 //销毁: obj = null: //栈内存 1)全局做用域 只有当页面关闭的时候全局做用域才会销毁 2)私有的做用域(只有函数执行会产生私有的做用域) //通常状况下,函数执行会造成一个新的私有做用域,当私有做用域中的代码执行完成后,咱们当前做用域都会主动的进行释放和销毁 //可是仍是存在特殊状况的: //当前私有做用域中的部门内存被做用域之外的东西占用了,那么当前的这个做用域就不能销毁了 //a,函数执行返回了一个引用数据类型的值,而且在函数的外面被一个其余的东西给接收了,这种状况下通常造成的私有做用域都不会销毁。 function fn(){ var num = 100; return function(){ num++; console.log(num); } } var f = fn(); f(); 下述状况属于不当即销毁->fn返回的函数没有被其余的东西占用,可是还须要执行一次呢,因此暂时不销毁,当返回的值执行完成后,浏览器会在空闲的时候把它销毁了。->“不当即销毁” function fn(){ var num = 100; return function(){ num++; console.log(num); } } fn()(); 检测数据类型的四种方式: 1.typeof 用来检测数据类型的运算符 2.instanceof 检测某一个实例是否属于某个类 3.constructor 构造函数 4.Object.prototype.toString.call() 1.for,while 都是同步模式 2.异步: 不会当即执行,须要等必定时间,只有当下面的事情都处理完成了,才会回头处理以前的事情;若是下面的事情并无处理完成,无论以前的事情有没有到时间,都等着。 3.在JS中异步编辑有四种状况: 定时器 事情绑定 Ajax 回调函数 每个浏览器对于定时器的等待时间都有一个最小的值,谷歌5-6ms,IE:10-13ms,若是设置的等待时间小于这个值,不起做用,还须要等到最小时间才执行;0也不是当即执行。 var n = 0; setTimeout(function(){ n++; console.log(n) },0) console.log(n) 咱们定时器设置的等待时间不必定是最后执行时间,若是定时器以后还有其余的事情正在处理中,无论定时器的时间有没有到,都是不会执行定时器的 var n = 0; setTimeout(function(){ n++; console.log(n) //不执行 },0) console.log(n) //1 while(1){ //死循环 n++; } console.log(n); //不执行 数组forEach不支持return,没有返回值 数组map支持return,有返回值,并不影响原来的数组,至关于把原数组克隆一份返回出去 var obj = {name:'hongliang'} var ary = [1,2,3,4,5]; //->forEach方法中的this是ary;匿名回调函数中的this默认是window; ary.forEach(function(item,index){ console.log(this); //window },obj);//->不论是forEach仍是map都支持第二个参数值,第二个参数的意思是把匿名回调函数中的this进行修改 var obj = {name:'hongliang'} var ary = [1,2,3,4,5]; ary.forEach(function(item,index){ console.log(this); //window }.call(obj)) //->给forEach赋值的时候,首先把匿名函数执行,把匿名函数中的this改变成obj,把匿名函数执行的返回结果undefined赋值给forEach(不行); var obj = {name:'hongliang'} var ary = [1,2,3,4,5]; ary.forEach(function(item,index){ console.log(this); //obj }.bind(obj)) //->兼容性(ie8及如下) 咱们在js中主要研究的都是函数中的this; JS中的this表明的是当前行为执行的主体;JS中的context表明的是当前行为执行的环境(区域) this 是谁和函数在哪定义的和在哪执行的都没有任何的关系:如何区分this呢? 1,函数执行,首先看函数名前面是否有".",有的话,"."前面是谁this就是谁;没有的话this就是window 2,自执行函数中的this永远是window 3,给元素的某一个事件绑定方法,当事件执行时,this是绑定的元素 4,全局做用下,自定义执行函数中不预解析 function fn(){ console.log(this); } var obj = {fn:fn}; fn(); //this->window obj.fn(); //this->obj document.getElementById('div1').onclick = fn; //this->#div1 document.getElementById('div1').onclick = function(){ //this->#div1 fn(); //this->window }; function sum(){ //this->window fn(): //this->window } sum(); var oo = { sum:function(){ //this->oo fn() //this->window } } oo.sum(); var num = 20; var obj = { num:30, fn:(function(num){ this.num *= 3; num += 15; var num = 45; return function(){ this.num *= 4; num += 20; console.log(num); } })(num); }; var fn = obj.fn; fn(); //65 obj.fn(); //85 console.log(window.num,obj.num) //240,120 做用域不销毁的三种情形: 1,函数执行返回一个引用类型,被一个变量接收 2,在私有做用域里给元素绑定一个方法 3,fn()(); 1, var count = 0; obtn.onclick = function(){ count++; console.log(count); } 2, ~function(){ var count = 0; obtn.onclick = function(){ count++; console.log(count); } }() obtn.onclick = (function(){ var count = 0; return function(){ count++; console.log(count); } })(); 弊端:有一个不销毁的私有做用域,因此占那么一点内存。 3,利用innerHTML的方式处理:每点击一次都去页面获取最新的值,累加,最后再赋值过去 obtn.onclick = function(){ spanNum.innerHTML++; } 弊端:每一次都把页面中的内容转换为字符串再累加,累加完再从新添加回去,浏览器会从新渲染一下 4,利用自定义属性存储(推荐使用) obtn.count = 0; obtn.onclick = function(){ spanNum.innerHTML = ++this.count; } 全部的编程语言都是面向对象开发的->类的继承、封装、多态 继承:子类继承父类中的属性和方法 多态:当前方法的多种形态->后台语言中:多态包含重载和重写 JS中不存在重载,方法名同样的话,后面的会把前面的覆盖掉。 JS中有一个操做相似重载但不是重载:“咱们能够根据传递的参数不同,实现不一样的功能。 重写:子类重写父类的写法 工厂模式: function createPerson(){ var obj = new Object(); obj.name = 'zhl'; obj.getName = function(){ return this.name; } return obj; } 构造函数模式: function createPerson(){ this.name = 'zhl'; this.getName = function(){ return this.name; } } //构造函数模式中拥有了类和实例的概念,而且实例和实例之间是相互独立开的->实例识别 //基于构造函数模式的原型模式解决了 方法或者属性公有的问题->把实例之间相同的属性和方法提取成公有的属性和方法->类.prototype = fn; *1.每个函数数据类型(普通函数、类)都有一个天生自带的属性:prototype(原型),而且这个属性是一个对象数据类型的值 2.而且在prototype上浏览器天生给它增长了一个属性constructor(构造函数),属性值是当前函数(类)的自己 3.每个对象数据类型(普通对象、实例、prototype...)也天生自带一个属性:__proto__,属性值是当前实例所属类的原型(prototype). 二、Object是JS中全部对象数据类型的基类(最基层的类) 1),f1 instanceof Object ->true 经过__proto__能够向上级查找,无论有多少级,最后总能找到Object. 2),在Object.prototype上没有__proto__这个属性 三、原型链模式 f1.hasOwnProperty("x");//->hasOwnProperty是f1的一个属性 可是咱们发如今f1的私有属性上并无这个方法,那如何处理的呢? 1)经过 对象名.属性名 的方式获取属性值的时候,首先在对象的私有属性上进行查找,若是私有属性中存在这个属性,则获取的是这私有属性的值。 2)若是私有属性上没有,则经过__proto__找到所属类的原型(类的原型上定义的属性和方法都是当前实例公有的属性和方法),原型上存在的话,获取的是公有属性值。 3)若是原型上也没有,则继续经过原型上的__proto__继续向上查找,一直找到Object.prototype为止...若是仍是找不到则是undefined -->这种查找机制就是"原型链模式" 一、 JS中的全部的类都是函数数据类型,它经过new执行变成一个类,可是它自己也是一个普通的函数 JS中全部的实例都是对象数据类型的 二、构造函数中的this指当前new出来的实例对象 function Fn(){ //this->f1 this.x = 100; this.getX = function(){ //this->须要看getX执行的时候才知道 console.log(this.x); } } var f1 = new Fn; f1.getX(); //->方法中的this是f1->100 var ss = f1.getX; ss(); //->方法中的this是window -> undefined; 一、在构造函数模式中 new Fn() 执行,若是Fn不须要传递参数的话,后面的小括号能够省略 二、this的问题:在类中出现的this.xx = xxx中的this 都是当前类的实例,而某一个属性值(方法),方法中的this须要看方法执行的时候,前面是否有"."才知道this是谁。 匿名函数中的 this 是 window; 事件对象: e.pageX = e.pageX || (e.clientX + (document.documentElement.scrollLeft || document.body.scrollLeft)) e.pageY = e.pageY || (e.clientY + (document.documentElement.scrollTop || document.body.scrollTop)) e.preventDefault() // 阻止默认行为 表格排序: function sortTable(n){ var _this = this; //-> 把存储全部行的类数组转化为数组 var ary = [].slice.call(oRows); //->点击当前列,让其它列flag回归到初始值-1;这样就不会乱; for(var k = 0; k<oThs.length; k++){ if(oThs[k] != this){ oThs[k].flag = -1; } } //->给数组进行排序; _this.flag *= -1; ary.sort(function(a,b){ var curInn = a.cells[n].innerHTML; var nextInn = b.cells[n].innerHTML; var curInnNum = parseFloat(a.cells[n].innerHTML); var nextInnNum = parseFloat(b.cells[n].innerHTML); if(isNaN(curInnNum) || isNaN(nextInnNum)){ return (curInn.localeCompare(nextInn)) * _this.flag; }else{ return (curInnNum - nextInnNum) * _this.flag; } }) //-> 按照ary中的最新顺序,把每一行从新添加到tBody中 var frg = document.createDocumentFragment(); for (var i = 0; i < ary.length; i++) { frg.appendChild(ary[i]); }; tBody.appendChild(frg); frg = null; } //点击排序:全部具备class="cursor" 这个样式的列均可以实现点击排序 for(var i = 0; i<oThs.length; i++){ var curTh = oThs[i]; if(curTh.className === "cursor"){ curTh.index = i; curTh.flag = -1; curTh.onclick = function(){ sortTable.call(this,this.index); } } } */ </script>