一.Js高级
1.基本数据类型(值类型) 和 复杂数据类型(引用类型)
怎么判断?
凡是 instanceof Object 返回为true的,都是复杂数据类型。
2. 对象 和 Json
//2.Object 动态设置属性 var o = new Object(); o.id = 1; o["name"] = "james"; //2.1对象字面量表示法 var o1 = { id: 1, name:"哈哈" };
Json 是数据在程序间传输的一种 数据格式(轻量级数据传输格式)
//2.2Json格式字符串 注意:字符串里的属性名和属性值必须有【双引号】扩起来 var strJson = '{"id":"1","name":"哈哈"}'; //2.2.1 使用eval将json字符串转成 obj,注意:加 () var jsonObj = eval("(" + strJson + ")"); alert(jsonObj.name); //2.2.2使用JSON.parse将字符串转成 obj 注意:推荐使用此种方式,可以过滤掉不安全的js代码字符串 var jsonObj = JSON.parse(strJson); alert(jsonObj.id + ":" + jsonObj.name); //2.2.3将对象 转成 json格式字符串 var strJsonNew = JSON.stringify(jsonObj); alert(strJsonNew);
Json传输容量小,简便。
3.数据类型
3.1Function
3.1.1声明式函数 特点:浏览器优先于其它执行js加载此声明式函数 //A(1);//可以在声明式函数 之前 调用此函数! function A(a1) { alert("123"+a1); } //alert(A instanceof Function);//true 3.1.2匿名方法 var Ano = function (a,b) { alert(a);}; //alert(Ano instanceof Function);//true 3.1.3对象方式 注意:最后一个参数永远是方法体代码字符串,前面的参数就是 改方法对象的 形参 var funC = new Function("a","b","alert('123,'+a+','+b);"); funC("hhaa ","吼吼"); //alert(funC instanceof Function);//true 3.2 Undefined 代表未定义,只有一个值:undefined 3.2.1声明但未赋值,默认就是undefined var undef; alert(undef == undefined);//true 3.2.2方法没有return,默认 返回 undefined function testUn() { } var tes = testUn(); alert(tes == undefined);//true 3.3Null 代表空引用 var objN = new Object(); objN = null; //null 和 undefined 都代表"没有",所以js把他们看成相等 alert(null == undefined); //可以用 全等号 区别 alert(null === undefined); 3.4Boolean var boolV = true; alert(boolV == true); alert(boolV == 1);//js中 true==1 false==0 3.5Number 3.5.1包含 整数和浮点数 var numb = 1; //alert(typeof numb); var numF = 1.11; //alert(typeof numF); 3.5.2判断变量是否是 数值 //isNaN 判断不是数值!:如果不是数值返回true,如果是数值返回false alert(isNaN("asdf")); 3.5.3转换 var intN = parseInt("111"); var floatF = parseFloat("111.11"); 3.6string字符串 length:得到长度 split:根据指定分隔符拆分字符串 substr:从下标为第一个参数的地方截取到第二个长度的内容 substring:从下标为第一个参数的地方截取到下标为第二个参数的内容 trim:去除字符串两头的空格 indexOf:找到指定字符或字符串在这个字符串里第一次出现的位置 lastIndexOf:找到指定字符或字符串在这个字符串里最后一次出现的位置 charAt:找到指定下标位置的字符
4.检测数据类型
4.1 typeof:用来检测基本数据类型变量的数据类型,返回值 【变量类型字符串】
语法: typeof num1 / typeof(num1)
另外:是js里的关键字,不是一个方法!但也可以使用 typeof() 语法。
4.1.2检测【基本数据类型】 var s ="hahaha"; //var不是说变量没有类型,而是确定类型的时间推迟到运行这句代码时 alert(typeof s); //string alert(typeof(s));//string alert(typeof 110);//number 4.1.2如果用来判断【引用类型】对象,那么永远都返回Object alert(typeof null);//Object
5.方法的内部属性 arguments
//4.1arguments //方法的实参数组 function testArgument() { //模拟函数重载! if (arguments.length == 1) { alert("哈哈~1"+arguments[0]); } else if (arguments.length == 2) { alert("哈哈~2" + arguments[0] + "," + arguments[1]); } else { alert("哈哈~3"); } } testArgument(); testArgument(1); testArgument(1, 2);
注意:js中方法本身是没有重载的,因为:
1.方法的本质就是一个Function类型的变量,如果出现同名的变量,会覆盖!
但是依靠函数内部属性argument来模拟重载!
补充:动态删除对象属性 var oDel = new Object(); oDel.id = 1; alert(oDel.id);//1 //删除对象的 属性 delete oDel.id; alert(oDel.id);//undefined
6.js没有块级作用域
function testBlock() { if (1 == 1) { var ablock = 1; } alert(ablock);//1 for (var i = 0; i < 10; i++) { } alert(i);//10 try{ var tr="try"; }catch(e){ } alert(tr);//try }
补充:关于自动垃圾回收
1.主要针对 引用类型 对象(针对 堆空间),垃圾回收期会定时检查堆空间里的对象,一旦发现对象没有被任何地方引用的话,就把它删除销毁。
2.引用类型:
如果是局部变量,则方法执行完毕后变量被销毁,但对象要等待垃圾回收期来销毁。
如果是全局变量,也是跟随全局对象存放,它的销毁依赖于 全局对象。
3.值类型:
如果是局部变量,则方法执行完毕后立即被销毁。
如果是全局变量,直接跟随全局对象存放在堆中。它的销毁要看这个全局对象的销毁状态。
补充:全局和局部变量
全局变量:直接跟着全局对象存放在堆中;
局部变量:在执行方法的时候,会在执行当前方法的线程栈和堆中 创建 值类型和引用类型变量。
总结:只有值类型的 局部变量才会存在栈中,全局变量不管是什么类型都存在堆里。
function test() { //局部变量 var num = 1;//方法执行完 即销毁 var objNum = new Object();//方法执行完,变量被销毁,但堆空间里的对象 要等垃圾回收器销毁 } test();//注意:方法里的代码要被调用的时候才会执行,才会生成局部变量 //而全局变量,则直接属于window,只有当窗体被关闭或刷新的时候 才跟随window一起销毁 var temp = 1; var tempObj = new Object();
7.数组
7.1js数组不限制元素类型 var arr = [1, 2, "asdf", new Object()]; alert(arr.length);//4 //7.2数组长度可变 arr.length = 10; alert(arr.length);//10
7.2数组当 栈和队列使用
7.3数组当栈使用 栈(LIFO-LastInFirstOut-后进先出)方法 //第一种:unshift(),shift() //第二种:push(),pop() var arrStack = []; arrStack.unshift("尾巴进来的第1个"); arrStack.unshift("尾巴进来的第2个"); arrStack.unshift("尾巴进来的第3个"); arrStack.unshift("尾巴进来的第4个"); alert(arrStack.length); for (var i = 0; i < 4; i++) { alert(arrStack.shift()); }
7.4数组当队列使用 队列(FIFO-FirstInFirstOut)方法 //第一种:push(),shift() //第一种:unshift(), pop() var arrQue = []; arrQue.unshift("尾巴进来的第1个"); arrQue.unshift("尾巴进来的第2个"); arrQue.unshift("尾巴进来的第3个"); arrQue.unshift("尾巴进来的第4个"); alert(arrQue.length); for (var i = 0; i < 4; i++) { alert(arrQue.pop()); }
7.5反转数组 var arrReverse = [4, 3, 1, 6, 8]; alert(arrReverse); arrReverse.reverse(); alert(arrReverse);
7.5 排序
var arrSortObj = [ { age: 18, name: "I笑傲呗" }, { age: 118, name: "乌龟" }, { age: 218, name: "王八" }, { age: 108, name: "蛤蟆" } ]; for (var i = 0; i < arrSortObj.length; i++) { document.body.innerHTML += arrSortObj[i].name + "," + arrSortObj[i].age + "<br/>"; } arrSortObj.sort(function (x, y) {//方法的参数,有sort方法内部传入(升序),方法的返回值约定:x > y 返回 正数,x=y 返回0,x<y 返回 负数 return x.age - y.age; }); document.body.innerHTML += "排序后:<br/><br/>"; for (var i = 0; i < arrSortObj.length; i++) { document.body.innerHTML += arrSortObj[i].name + "," + arrSortObj[i].age + "<br/>"; }
8.arguments
实参数组对象: 是一个 类(似)数组 对象
内部属性arguments的callee
8.1让我们来看一个函数递归的问题 var facorial = function (num) { if (num <= 1) return 1; else return num * facorial(num - 1);//facorial是一个函数变量,其内部保存了函数的地址,但也可以在外部被修改指向其它的函数地址。从而破坏了递归应用。(很危险) } alert(facorial(5)); //5*4*3*2*1=120 var another = facorial; alert(another(5));//5*4*3*2*1=120 facorial = function () { return 1; } alert(another(5));//5*1=5 alert(facorial(5));//1
【解决方案】: var facorial = function (num) { if (num <= 1) return 1; else return num * arguments.callee(num - 1);//calle保存当前函数的引用,一般递归使用 } alert(facorial(5)); //5*4*3*2*1=120 var another = facorial; alert(another(5));//5*4*3*2*1=120 facorial = function () { return 1; } alert(another(5));//5*4*3*2*1=120 alert(facorial(5));//1
9.函数内部属性this
this引用的是函数据以执行操作的对象,也就是 函数在执行时所处的作用域
通俗:就是哪个对象.出了这个函数,那么函数里的this就代表哪个对象
window.color = "blue"; var o = { color: "red" }; function sayColor() { alert(this.color);//谁.出这个方法,这个this就是谁 } sayColor();//blue o.sayColor = sayColor; o.sayColor();//red
function each(arr,func) { if (arr instanceof Array) { for (var i = 0; i < arr.length; i++) { var item = arr[i]; //通过 函数对象的 call/apply方法 改变函数的作用域(为被调用的函数 里的 this 赋值) //func.call(item, i, item); func.apply(item, [i, item]); } } } var arr = [1, 2, 3, 4, 5]; each(arr, function (index,item) { //alert(index + ":" + item); alert(this); });
这样扩充的最大好处就是对象不需要与方法有任何耦合关系。
10.方法的属性(区别方法内部属性)
10.1length 代表方法的形参个数 //9.1 length 函数的形参 function testLength(name,id,cc) { //arguments.length //alert(arguments.callee.length); } //获取函数testLength形参的个数 //testLength.length //将方法对象传入此方法,会根据 传入方法的形参个数决定传什么值! function invokeFun(func) { //当传进来的方法的形参是2个的时候 if (func.length == 2) { func("哈哈","哇哈哈哈哈~~~"); } else if (func.length == 3) { func(1, 2, 3); } }
10.2方法属性:prototype,让那个所有方法实例共享数据的地方 //9.2方法原型 function Person(name, age) { //相当于 C#里的 类和 构造函数 的"综合体" ,Person : Object this.name = name; this.age = age; //this.sayHi = function () { alert("123123"); }; } //Person.prototype是Person 实例共享数据的地方 Person.prototype.sayHi = function () { alert("123123"); }; /* new 关键字: 0.开辟堆空间 1.创建一个 Person 实例,内部没有任何成员,除了 "继承" 自 Object的成员;就相当于是一个Object实例! 2.调用 同名构造函数,将 实例 设置给了 函数中的 this,从而 可以通过 这个函数 为每个new出来的Person实例 添加相同的属性!!!!! 3.返回 实例 的地址 */ var p1 = new Person("james2", 28); var p2 = new Person("james3", 21); alert(p1.sayHi === p2.sayHi);//true
10.3方法对象的call:动态修改方法里的this var sayColor= function (name,age){ alert(this.color + ":" + name + ":" + age); } var oC = new Object(); //将 方法引用 设置给了 oCol的sayColor属性 oC.sayColor = sayColor; oC.color = "red"; //oC.sayColor("james",18);//red var cNew = new Object(); cNew.color = "yellow"; oC.sayColor(); //方法的call方法,用来动态修改 方法执行时的 this //执行 sayColor的同时,将sayColor方法里的this 修改成 colorNew oC.sayColor.call(colorNew, "james",18);//yellow var color = "green"; //执行 sayColor的同时,将sayColor方法里的this 修改成 window oC.sayColor.call(window, "james", 18); 方法对象的apply:动态修改方法里的this //9.4 apply 改变方法的this,但 实参必须作为一个数组传入 var sayColor = function (name, age) { alert(this.color + ":" + name + ":" + age); } var oC = new Object(); //将 方法引用 设置给了 oCol的sayColor属性 oC.sayColor = sayColor; oC.color = "red"; var cNew = new Object(); cNew.color = "yellow"; //方法的call方法,用来动态修改 方法执行时的 this //执行 sayColor的同时,将sayColor方法里的this 修改成 colorNew oC.sayColor.apply(cNew, ["james", 18]);//第二个参数必须是数组
10.eval执行代码字符串
function aa() { var strCode = "var aeval =1;"; //eval方法里的代码就相当于在eval方法当前所在的作用域中执行 eval(strCode);//相当于在此处 执行代码 var aeval =1; }
window.onload = function () { document.getElementById("btnOk").onclick = function () { var strCode = document.getElementById("txt").value; //eval方法 可以直接调用 浏览器的js引擎,直接执行 传入的 js代码字符串 eval(strCode); }; }; //2.eval 中创建的变量 就是添加到 了 当前 eval所在的执行环境 //2.1全局执行环境下 调用 eval 创建变量,那么这个变量就 添加到了 window下 var str1 = "var i=0;"; eval(str1); //alert(i);//? 0 //2.2在方法中 调用 eval 创建变量,那么这个变量 就添加到了 函数的作用域中(局部变量) function testEval() { eval("var a =123;"); alert(a); } testEval(); var res = eval("1+2+3"); alert(res);//? 6
11.new创建对象
<script type="text/javascript"> //alert(Object instanceof Function); //var res = Object(123); //alert(res); function Person(age,name) { //this是 new关键字 创建的对象 this.age = age; this.name = name; this.sayHi = function () { alert("age=" + this.age + ",name=" + this.name); }; //alert("Person的构造函数!" + this);//此时,this是 new关键字 创建的对象 } var p1 = new Person(12, "刘德华"); //p1.sayHi(); var p2 = new Person(21, "习"); //p2.sayHi(); //通过 call 方法 模拟 new 关键字创建对象 //var p3 = new Object();//1.创建一个对象 //Person.call(p3, 99, "神州");//2.将对象 传给 Person 方法的 this,Person方法为 对象添加 属性 //p3.sayHi(); alert(p1 == p2);//false </script>
<script type="text/javascript"> function Person(age,name) { //this是 new关键字 创建的对象 this.age = age; this.name = name; } //prototype(原型) 相当于是 某个 ”类“ 的 共享成员表(共享变量,共享方法) Person.prototype.sayHi = function () { alert("age=" + this.age + ",name=" + this.name); }; var p1 = new Person(12,"刘德华"); //p1.sayHi(); var p2 = new Person(21, "习"); //p2.sayHi(); alert(p1.sayHi === p2.sayHi);//true 证明:每个Person对象 都使用一个 共同的 sayHi 方法对象 </script>
11.模拟继承
<script type="text/javascript"> function Mother() { } //1.定义"父类" function Father(name, age) { this.name = name; this.age = age; } Father.prototype.sayHi = function () { alert(this.name + "," + this.age); }; //2.定义子类 function Son(name, age,gender) { this.gender = gender; Father.call(this, name, age);//3."继承" "父类" 的成员 } Son.prototype = new Father();//4.继承父类 的 方法 Son.prototype.fungame = function () { };//5.为子类原型添加一个子类特有的方法 //创建父类对象 var f1 = new Father("JamesZou", 29); f1.sayHi(); //创建子类对象 var s1 = new Son("jameszou's son", 1, true); s1.fungame(); </script>
12.闭包
闭包:指有权 访问另一个函数作用域中的变量的 函数 function biBaoCreater() { var date = "2013-01-26"; return function () { alert("今天:" + date); }; } var biBao = biBaoCreater();//变量 biBao 就是一个 闭包 biBao();//闭包 会延长 内部引用到的外部作用域的生命周期