1.js数字只有一种类型java
2.见代码ajax
/** * Created by Administrator on 2017/7/2. */ console.log("charpter2"); console.log(1-0.41); //0.5900000000000001 double不能精确计算 console.log((8).toString(2));//1000 数字转其余进制输出 console.log(parseInt("1001", 2));//9 其余进制转数字
1. - * / % 在计算以前会把参数转化成数字, +能够是数字或者字符串,有字符串就优先字符串, 位运算符 ~ & | ^ << >> >>>会将参数转化成32位整数chrome
2.见代码api
1 console.log("charpter3"); 2 console.log("17" * 3); //51 3 console.log(NaN === NaN);//false 4 console.log(isNaN(NaN));//true 5 console.log(isNaN("haha"));//true 6 console.log(isNaN(""));//false 7 console.log(isNaN(null));//false 8 console.log(isNaN(undefined));//true 9 console.log(null === null);//true 10 console.log(undefined === undefined);//true 11 function isReallyNaN(a) { // 判断参数究竟是不是NaN的最简单方法 12 return a !== a; 13 } 14 console.log("object : " + { 15 toString: function () { 16 return "object" 17 }, valueOf: function () { 18 return 123; 19 } 20 }); //优先选择valueOf做为返回值
3. if || && 会把参数转化成布尔值, js里有7个转化后为假的值: false 0 -0 null undefined NaN ""数组
4.检查参数是否为undefined能够用typeof(x) === "undefined" 或者 x===undefined浏览器
1.js有5个原始值类型:boolean number string null undefined安全
2.原始值也能够调用对应的包装类的方法,可是对原始值设置属性没有什么用处,由于原始值会被隐式封装成1个新的对象,因此实际上是在操做那个新的对象.闭包
3.一些实验并发
1 console.log("charpter4"); 2 console.log(typeof null); //object, null比较特殊,和object同样 3 console.log(typeof undefined);//undefined 4 console.log(typeof NaN);//number 5 console.log(typeof true);//boolean 6 //String类和字符串仍是有区别的 7 console.log(typeof "");//string 8 console.log(typeof new String());//object 9 console.log("123" === "123");//true 10 console.log(new String("123") == new String("123"));//false
1.将字符串转为数字可使用Number()或者+运算符app
2.实验结果:
1 console.log("charpter4"); 2 // == 比较的原则为 3 console.log(null == undefined); //true 1.null,undefined 与 null,undefined比较不转型直接返回true 4 console.log(null == 0); //false 2. null,undefined 与 非null,undefined 比较不转型直接返回false 5 6 // 3.非null,undefined原始类型与Date比较都转为数字,Date比较特殊,优先调用toString而不是valueOf 7 var dateToStringFunction = Date.prototype.toString; 8 Date.prototype.toString = function(){ 9 console.log("Date.toString"); 10 var result = dateToStringFunction.apply(this, arguments); 11 console.log(result);//Sun Jul 02 2017 18:12:42 GMT+0800 (中国标准时间) 12 return result; 13 } 14 var dateValueOfFunction = Date.prototype.valueOf; 15 Date.prototype.valueOf = function(){ 16 console.log("Date.valueOf"); 17 var result = dateValueOfFunction.apply(this, arguments); 18 console.log(result); 19 return result; 20 } 21 console.log(true == new Date()); //false 由于转化成数字 new Data().toString() 结果为NaN 22 //clean 23 Date.prototype.toString = dateToStringFunction; 24 Date.prototype.valueOf = dateValueOfFunction; 25 26 // 4.非null,undefined原始类型与非Date比较都转为数字,优先调用valueOf 27 var objectToStringFunction = Object.prototype.toString; 28 Object.prototype.toString = function(){ 29 console.log("Object.toString"); 30 var result = objectToStringFunction.apply(this, arguments); 31 console.log(result); 32 return result; 33 } 34 var objectValueOfFunction = Object.prototype.valueOf; 35 Object.prototype.valueOf = function(){ 36 console.log("Object.valueOf"); 37 var result = objectValueOfFunction.apply(this, arguments); 38 console.log(result); //Object 39 return result; 40 } 41 console.log(true == new Object()); //false 42 //clean 43 Object.prototype.toString = objectToStringFunction; 44 Object.prototype.valueOf = objectValueOfFunction; 45 46 //5.非null,undefined原始类型与非null,undefined原始类型比较转为数字 47 console.log(true == "1"); //true
3.==会产生隐式类型转化,因此仍是本身强制转化而后使用===比较好理解.
1.js能够自动插入分号.规则是:①分号仅在}以前,一个或多个换行以后和程序输入的结尾被插入,因此一行有多处要插入分号的话是不能省略的.
②分号在随后的输入标记不能解析时插入,这可能会致使程序解析和想的不同.好比
a=b ["r", "g", "b"].foEach(function(key)){ ......... }
会被解释成a = b["b"].forEach(......),由于b["r", "g", "b"]能够被解析(,分隔表达式从左向右执行,返回最后边的表达式的值)
③for不会做为for循环头部被插入,因此若是for头部有多行,要本身插入分号
2.通常仍是本身插入;比较清楚简单,可是有时候js也会自动插入分号.好比return同一行最后.
return {};
等价于return ; {};程序不会报错.其余还有些限制产生式.可是我基本都会自动插入;而且不换行避免.
1.当字符串包含辅助平面的代码点时候,js将每一个代码点表示为2个元素而不是1个.因此特殊字符应该算length=2,好比∮.
可是实际上我本身测试结果长度仍是1.
不知道为何..
console.log(); console.log("charpter8"); //console.log(a); //Uncaught ReferenceError: a is not defined console.log(this.a);//undefined
1.JS给一个未绑定的变量赋值会简单的建立一个新的全局变量并赋值给它,而不是报错.
1.如题
2.在with代码块的内部,变量查找先开始找with对象的属性,和从原型链上继承下来的属性,没有再找外部做用域.
4.with须要搜素对象的原型链,因此运行速度比通常代码块慢.
1.闭包就是可以使用外部做用域定义的变量的函数
2.闭包比建立他们的函数有更长的声明周期
3.一个测试:
1 console.log(); 2 console.log("charpter11"); 3 (function () { 4 function f() { 5 var a = 1; 6 function add1() { 7 a++; 8 console.log(a); 9 } 10 function add2() { 11 a++; 12 console.log(a); 13 } 14 add1(); // 2 15 add2(); // 3 16 } 17 f(); 18 })();
1.JS不支持块级做用域,变量定义的做用域并非离其最近的代码块,而是包含它们的函数.
2.JS没有块级做用域的一个例外是异常.
1.闭包存储的是其外部变量的引用而不是值
2.能够用自执行函数来建立局部做用域
3.JS不支持块级做用域,可是可使用函数做用域代替.
1.命名函数表达式因为会致使不少问题,因此并不值得使用
2.一些实验
console.log(); console.log("charpter14"); // 如下测试说明的个人360极速的chrome内核已经支持es5了. (function () { var constructor = function () { return null; }; var f = function f() { return console.log(constructor());//null }; f(); var f = function () { return console.log(constructor());//null }; f(); })();
1.由于没有块级做用域,因此声明在代码块中的函数其实仍是至关于声明在外部做用域中的.但也不是全部环境都是如此,因此很容易出错.
2.ES5官方指定函数声明只能出如今其余函数或者程序的最外层.
3.可使用var 声明和有条件的赋值语句代替有条件的函数声明.
4.一个实验
1 console.log(); 2 console.log("charpter15"); 3 (function () { 4 function f() { 5 return "global"; 6 } 7 8 function test(x) { 9 var g = f; 10 result = []; 11 if (x) { 12 g = function () { 13 return "local"; 14 } 15 result.push(g()); 16 } 17 result.push(g()); 18 return result; 19 } 20 console.log(test(false)); //["global"] 21 console.log(test(true)); // ["local", "local"] 22 })();
1.绑定eval函数到另一个变量名,经过该变量名调用函数会使代码失去对全部局部做用域的访问能力
2.测试:
1 var a = "global"; 2 console.log(); 3 console.log("charpter17"); 4 //直接调用eval就和普通函数同样,间接调用的话只能访问全局做用域 5 (function () { 6 var a = "outer"; 7 function test(){ 8 var a = "inner"; 9 console.log(eval("a")); //inner 10 } 11 test(); 12 13 function test2(){ 14 var a = "inner"; 15 console.log((0, eval)("a"));//global 16 } 17 test2(); 18 19 function test3(){ 20 var a = "inner"; 21 var f = eval; 22 console.log(f("a"));//global 23 } 24 test3(); 25 26 function test4(){ 27 var a = "inner"; 28 console.log((eval)("a"));//inner 29 } 30 test4(); 31 32 function test5(){ 33 //var a = "inner"; 34 console.log(eval("a")); //outer 35 } 36 test5(); 37 })();
3.尽量间接调用eval函数,隐藏细节,同时也加快执行速度.
1.在方法调用中是由调用表达式自身来肯定this变量的绑定.绑定到this变量的对象被称为调用接收者.
2.一般,经过某个对象调用方法将查找该方法并将该对象做为该方法的接收者
3.一个非方法的函数调用会将全局对象做为接收者.
1.高阶函数式那些将函数做为参数活返回值的函数
2.须要引入高阶函数抽象的信号是出现重复或类似的代码.
1.如题,由于形参指向的是arguments中的元素,修改arguments实际上会修改形参
2.能够经过[].slice[arguments]来复制一份(浅克隆).
3.实验
1 console.log(); 2 console.log("charpter23"); 3 //obj 指向 arguments[0] . method指向 arguments[1] 4 (function () { 5 function callMethod(obj, method) { 6 var shift = [].shift; 7 shift.call(arguments); 8 shift.call(arguments); 9 return obj[method].apply(obj, arguments); 10 } 11 12 var obj = { 13 add : function (x, y) { 14 return x + y; 15 } 16 } 17 18 //callMethod(obj, "add", 17, 25); //Uncaught TypeError: Cannot read property 'apply' of undefined 19 })();
1.在ES5中可使用bind方法为方法绑定一个接收者
2.实验:
1 console.log(); 2 console.log("charpter25"); 3 (function () { 4 function f() { 5 console.log(this); 6 } 7 var f2 = f.bind({}); 8 f();//window 9 f2();//object 10 11 })();
1.将函数与其参数的一个本身绑定的技术成为函数柯里化.
其实并非很懂是啥意思,大概就是说原本参数是随便传入的,如今可能有些参数的值被固定了,剩下的参数随便传,多是把一个很是通用的函数拆成部分业务通用的函数.
2实验:
1 console.log(); 2 console.log("charpter26"); 3 (function () { 4 function f(a, b, c) { 5 console.log(arguments); // ["a", "b", 1, 0, Array[3]] ......value=1 index=0 array=Array[3] 6 return a + b + c; 7 } 8 var a = [1, 2, 3]; 9 var b = a.map(f.bind(null, "a", "b")); //用bind简化函数调用,固定值能够直接写死. 10 console.log(b); //["ab1", "ab2", "ab3"] 11 12 //猜想bind的实现原理 13 function bind2() { 14 var arg0 = arguments; 15 var me = this; 16 return function () { 17 var arg = [].slice.apply(arg0, [1]); 18 arg.push.apply(arg, arguments) //后来发现array有个concat方法直接能够用....args.concat(arguments) 19 return me.apply(arg0[0], arg); 20 } 21 } 22 Function.prototype.bind2 = bind2; 23 //bind2 实验1 24 var b2 = a.map(f.bind2(null, "c", "d")); 25 console.log(b2); //["cd1", "cd2", "cd3"] 26 //bind2 实验2 27 var fun = console.log.bind2(console, "jet: "); 28 fun("hello world!"); //jet: hello world! 29 //bind2 实验3 30 var fun2 = function () { 31 console.log(this); 32 } 33 fun2.bind2(new Date())(); //Sun Jul 09 2017 16:12:55 GMT+0800 (中国标准时间) 34 })();
原本f方法里应该传3个参数a,b,c应该都是可变的,如今经过bind2直接写死了a和b,这样就只能变化c了.可能在部分业务能够减小不少代码.由于a和b的值是固定的.可是我感受这样好不习惯..用bind感受没有直接传函数清楚,可能我用的比较少.
25, 26两节总结下的话就是bind函数能够改变函数中的this.同时能够写死函数的部分参数值(实际上是返回了一个新的函数来实现的).
1.eval函数里面使用的变量有可能会是全局变量也有多是局部变量,要看怎么使用,因此比较容易出问题
2.闭包能够访问外部做用域的局部变量,因此有局部变量确定先找局部变量.
3.传字符串代码的代码很难写,编译期也很难优化.而闭包则很简单.
4.一些测试:
1 console.log(); 2 console.log("charpter27"); 3 var a = "global"; 4 (function () { 5 var a = "outer"; 6 function f(n) { 7 eval(n); 8 } 9 function log() { 10 var a = "inner"; 11 f("console.log(a)"); 12 } 13 log(); //outer 14 15 16 function f2(){ 17 console.log(a); 18 } 19 function log2() { 20 var a = "inner"; 21 f2(); 22 } 23 log2(); //outer 24 })();
1.在对象上获取原型对象能够经过Object.getPrototypeOf方法,或者obj.__proto__
2.js中类的本质是一个构造函数与一个用于在该类实例间共享方法的原型.
3.实验:
1 console.log(); 2 console.log("charpter30"); 3 (function () { 4 var a = {}; 5 console.log(Object.getPrototypeOf(a) === Object.prototype);//true 6 console.log(Object.getPrototypeOf("") === String.prototype);//true 7 8 function f(a,b) { 9 this.a = a; 10 this.b = b; 11 } 12 f.prototype.c = 1; 13 console.log(f.toString === Function.prototype.toString);//true 14 console.log(f.toString === Object.prototype.toString);//false 15 console.log(f.prototype.a);//undefined 构造函数构造出来的对象的属性再也不原型对象上 16 //和java的原理同样,就是建立的时候对象有个指向原型的指针 17 var objF = new f(); 18 console.log(objF.c);//1 19 f.prototype.c = 2; 20 console.log(objF.c);//2 21 f.prototype = {}; 22 console.log(objF.c);//2 23 })();
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/create
1 //Shape - superclass 2 function Shape() { 3 this.x = 0; 4 this.y = 0; 5 } 6 7 Shape.prototype.move = function(x, y) { 8 this.x += x; 9 this.y += y; 10 console.info("Shape moved."); 11 }; 12 13 // Rectangle - subclass 14 function Rectangle() { 15 Shape.call(this); //call super constructor. 16 } 17 18 Rectangle.prototype = Object.create(Shape.prototype); 19 20 var rect = new Rectangle(); 21 22 rect instanceof Rectangle //true. 23 rect instanceof Shape //true. 24 25 rect.move(1, 1); //Outputs, "Shape moved."
Rectangle.prototype.__proto__ === Shape.prototype 为true.因此var a = Object.creatye(X)就是建立了一个对象a它的原型是X.
1 console.log(); 2 console.log("charpter33"); 3 (function () { 4 function f() { 5 return new String("123"); 6 } 7 console.log(new f()); //String {0: "1", 1: "2", 2: "3", length: 3, [[PrimitiveValue]]: "123"} return能够覆盖new返回的对象 8 })();
1.在回调函数中this很难看出来到底指向什么对象.因此要清楚的表达有3种方式:
第一个就是回调函数API多传1个对象,调用方法的时候this绑定到这个对象.因此这个是要看api是怎么写的.
第二个就是用对象指向this,好比在外层var me = this.而后调用me.XXX
第三个使用bindFunction.prototype.bind方法的第一个参数能够绑定方法的this指针.
1.js继承的步骤:
第一,子类的构造函数不中调用Parent.call(this,.....);
第二,Child.prototype = Object.create(Parent.prototype);
1.实验:
1 console.log(); 2 console.log("charpter41"); 3 (function () { 4 function f(x) { 5 this.a = x; 6 } 7 8 f.prototype.a2 = function () { 9 10 } 11 12 function f2(x, y) { 13 f.call(this, x); 14 this.b = y; 15 } 16 17 f2.prototype = Object.create(f.prototype); 18 f2.prototype.b2 = function () { 19 20 } 21 22 var test = new f2(); 23 console.log(test); 24 console.log(test.__proto__ === f2.prototype); // true 25 console.log(f2.prototype.__proto__ === f.prototype); // true 26 console.log(test.hasOwnProperty("b2")); // false 27 console.log(test.hasOwnProperty("b")); // true 28 console.log(test.hasOwnProperty("a")); // true 实例都是定义在对象里的 29 console.log(f2.prototype.hasOwnProperty("b2")); // true 30 })();
1.实验:
1 console.log(); 2 console.log("charpter43"); 3 //利用Object.defineProperty能够添加特殊属性 4 (function () { 5 var o = {}; // 建立一个新对象 6 // Example of an object property added with defineProperty with a data property descriptor 7 Object.defineProperty(o, "a", { 8 value: 37, 9 writable: true, 10 enumerable: false, 11 configurable: true 12 }); 13 14 var o2 = {a: 37}; 15 16 for (var i in o) { 17 console.log(i); //无输出,由于不能枚举a属性 18 } 19 for (var i in o2) { 20 console.log(i); //a 21 } 22 23 console.log({} instanceof Object);//true 24 console.log({}.__proto__ === Object.prototype);//true 25 })();
1.实验:
1 console.log(); 2 console.log("charpter44"); 3 (function () { 4 function f() { 5 6 } 7 f.prototype =null; 8 var a = new f(); 9 console.log(Object.getPrototypeOf(a) === Object.prototype); // true 10 11 var b = Object.create(null); 12 console.log(Object.getPrototypeOf(b) === null); // true 利用Object.create(null);来建立空原型的对象 13 })();
1.实验
1 console.log(); 2 console.log("charpter45"); 3 (function () { 4 var a = {}; 5 console.log("toString" in a); //true 6 7 for (var i in a) { 8 console.log(i); //无输出,不能被遍历的属性用in仍是返回true的 9 } 10 11 })();
for in 循环可能在不一样的js环境中选择不一样的枚举顺序,甚至在同一个js环境中执行也不相同.
1.for...in循环始终枚举全部key,key始终是字符串.
1.循环只有一点优于迭代函数,那就是前者有控制流程,如break,continue.
1.复用数组方法传入的参数不必定就是要数组,也能够是类数组,只要知足条件
①有length属性,0-2^32-1
②有索引,小于length在0-2^32-2.
1.API毫不应该重载于其余类型有重叠的类型,好比区分Array和Object就比较麻烦.
2.当浏览器跨frame通讯的时候,一个frame中的数组不会继承自另外一个frame的Array.prototype
3.实验
console.log(); console.log("charpter58"); (function () { console.log(typeof []); //object console.log(typeof {}); //object console.log([] instanceof Array); //true console.log(Array.isArray([])); //true })();
1.无状态的方法能够返回新的对象支持方法链,好比string的replace,有状态的方法使用返回this来支持方法链
1.js并发的接受事件,但会使用一个事件队列按顺序地处理事件处理程序.
个人理解:
1 console.log(); 2 console.log("charpter61"); 3 (function () { 4 //3 1 2 5 $.ajax({ 6 url: "/a.jsp", 7 success : function (data) { 8 for(var i=0; i< 10000000000; i++){ 9 10 } 11 console.log(1); 12 } 13 }); 14 $.ajax({ 15 url: "/b.jsp", 16 success : function (data) { 17 console.log(2); 18 } 19 }); 20 console.log(3); 21 })();
3,必定是在1和2以前的.可是1,2之间的顺序要看后台运行状况.多是12,也多是21,因此个人理解是ajax是异步执行的,请求收到返回结果之后看哪一个ajax先注册时间处理程序哪一个就先执行.
1.实验
1 console.log(); 2 console.log("charpter62"); 3 (function () { 4 // 3 4 5 1 2 5 $.ajax({ 6 url: "/a.jsp", 7 success: function (data) { 8 for (var i = 0; i < 1000000000; i++) { 9 10 } 11 console.log(1); 12 } 13 }); 14 $.ajax({ 15 url: "/b.jsp", 16 success: function (data) { 17 console.log(2); 18 } 19 }); 20 console.log(3); 21 for (var i = 0; i < 3000000000; i++) { 22 23 } 24 $.ajax({ 25 async: false, 26 url: "/a.jsp", 27 success: function (data) { 28 for (var i = 0; i < 1000000000; i++) { 29 30 } 31 console.log(4); 32 } 33 }); 34 console.log(5); 35 })(); 36 37 (function () { 38 // 5 1 39 $.ajax({ 40 url: "/a.jsp", 41 success: function (data) { 42 console.log(1); 43 } 44 }); 45 for (var i = 0; i < 3000000000; i++) { 46 47 } 48 console.log(5); 49 })(); 50 51 (function () { 52 // 后台哪一个断点先放开就输出哪一个对应的值 53 $.ajax({ 54 url: "/TestServlet", 55 success: function (data) { 56 console.log(1); 57 } 58 }); 59 $.ajax({ 60 url: "/TestServlet2", 61 success: function (data) { 62 console.log(2); 63 } 64 }); 65 console.log(5); 66 })(); 67 68 (function () { 69 // 在打印2以前后台就会收到请求,可是就算返回了仍是先输出2再输出1 70 $.ajax({ 71 url: "/TestServlet", 72 success: function (data) { 73 console.log(1); 74 } 75 }); 76 for (var i = 0; i < 3000000000; i++) { 77 78 } 79 console.log(2); 80 })();
前2个实验:
第一个实验3,4,5,1,2的输出说明了异步操做的回调函数确定是后于主函数执行的.
第二个实验5,1的输出说明了只有等主函数执行完毕才会轮到回调函数的触发.即便以前ajax已经返回结果也不会直接调用回调函数.
第三个实验我在后台打了断点,先放开哪一个断点就执行哪一个回调函数,说明ajax请求是异步的,可是只有等资源返回之后才会注册回调函数给事件队列,并不由于第一个ajax写在第二个ajax上面,它的success就先执行.而是等资源返回之后才会注册success.因此当第二个断点先放开的时候会先注册第二个ajax的success函数到事件队列中.
第四个实验在js打印2以前后台断点就收到请求.因此ajax请求资源是当即的.可是回调函数是资源返回完之后才注册的.
1.异步API直接使用trycatch是不对的,由于结果会马上返回也不会有错误.通常异步API都回传一个处理错误的回调函数来处理出错的状况,或者向回调函数中额外传一个包装了错误的参数,若是这个参数不为null或者其余假值,说明发生了错误.
1.把异步API放到循环中调用只会一次启用N个异步操做,若是想异步操做同步进行,须要递归调用这些异步操做.
2.异步API是不会致使栈溢出的,由于调用会马上返回,当回调函数被压入栈的时候栈确定是空的.
1.若是计算须要很长时间,使用递归和循环都会致使主线程被卡死,能够考虑使用异步的操做好比setTimeout来解决,由于是异步的,在异步过程当中其余事件能够被响应.优化一点的话一次异步过程当中可使用循环计算N次操做而不是单次操做.
1.多个异步操做的回调函数的顺序是不一样的,因此若是要同步全部异步操做的结果再调用回调函数的话可使用计数器,每一个异步操做结束都把计数器数字-1,并判断计数器是否为0.
1.同步的调用异步函数会致使执行顺序被改变,同时异步函数的递归调用是安全的,不会栈溢出,而同步的调用回调函数则不能保证.若是回调函数抛出异常就有可能会中断整个函数执行.
2.可使用setTomeout(fun, 0)来异步调用fun函数.