JavaScript权威指南(第6版) 8.8分
读书笔记 函数
浪花

1. 隐式声明的变量总是被创建为全局变量,即使该变量在一个函数体内使用 2. 在执行一个函数时,函数的参数和局部变量是作为调用对象的属性而存储的 3. 函数才有执行环境,每个执行环境都有一个和它关联一起的作用域链,这个作用域链是一个对象列表或对象链 4. 在js中并非所有的对象都包含或者说有正确的constructor属性,在每个新创建的函数原型上默认会有constructor属性,但我们常常会忽略原型上的constructor属性。例如这里定义了一个对象Range和它的原型,由于新定义的原型对象不含有constructor属性 function Range(){} Range.prototype={} var r = new Range(); alert(r.constructor);//function Object(){} 所以需要在原型中定义一个属性 Range.prototype={constructor:Range} alert(r.constructor);//function Range(){} 5. 在客户端js有一个问题是在多窗口和多框架子页面的Web应用中兼容性不好,每个窗口和框架子页面都具有单独的上下文,每个上下文都包含独有的全局变量和一组构造函数。在两个不同框架页面中创建的两个数组继承自两个相同但相互独立的原型对象,其中一个框架页面中的数组不是另一个框架页面的Array()构造函数的实例,instanceof和constructor得到的结果不正确 6. 定义式函数:function f(){};赋值式函数: var f = function b(){b();};注意这里b是这个函数的局部变量,只有在函数内才能调用b不会被全局作用域访问到,例如 var a = 1, b = function a (x) { x && a (--x); }; alert (a);//结果是1 7. 函数是在实际运行之前,当javascript代码被解析或者被编译时定义的,当javascript解析程序遇到一个函数定义(定义式函数)时,它就解析并存储(无需执行)构成函数主体的语句,然后定义一个和该函数同名的额属性(如果函数定义嵌套在其他函数中,那么就在调用对象中定义这个属性,否则在全局对象中定义这个属性)以保存它。然后把所有var变量创建,默认值是undefined。函数是在编译时定义,变量是在执行时定义。 alert(f(4));//16 var f = 0; function f(param){ return param*param; } alert(f);//0 8. throw new Error('');//页面上提示错误,并不会执行下面的语句 9. var f = function fact(x){return x*fact(x-1)}; 上面的代码定义了一个未命名函数,并把它的引用存储在变量f中,它并没有真正的把对函数的引用存储到名为fact的变量中,而只是允许函数体用这个名字来引用自身,注意是函数体自身中才能引用 10. arguments并非真正的数组,而是一个Arguments对象,当函数具有命名了的参数时,Arguments对象的数组元素是存放函数参数的局部变量的同义词,它们的改变会影响另一个的值,arguments是标识符不是保留字,要避免覆盖。 11. Arguments对象定义了callee属性,用来引用当前正在执行的函数,它可以用来对未命名的函数递归的调用自身 12. 在方法体中,用来调用方法的对象成为关键字this的值 13. 属性prototype:每个函数都有一个prototype属性,它引用的是预定义的原型对象。原型对象在使用new运算符把函数作为构造函数时起作用 14. 定义自己的函数属性,静态属性值 uniqueInteger.counter = 0; function uniqueInteger(){ return uniqueInteger.count++; } 15. apply和call方法:call(object,param),第一个参数表示要调用这个方法的对象,第二个参数表示这个方法的参数,例如要把两个数字传递给函数f(),并将它作为对象o的方法调用,可以使用 var o={}; f.call(o,1,2); 这与下面的代码相似,o.m=f;o.(1,2);delete o.m; apply方法与call方法相似,只不过要传递给函数的参数是由数组指定的. f.apply(o,[1,2]); 第一个参数为空时,默认使用全局对象 16. apply的一个巧妙的用处,可以将一个数组默认的转换为一个参数列表([param1,param2,param3] 转换为 param1,param2,param3) 这个如果让我们用程序来实现将数组的每一个项,来装换为参数的列表,可能都得费一会功夫,借助apply的这点特性,所以就有了以下高效率的方法: var arr=[5,7,9,1]; alert(getMax2(arr)); function getMax2(arr){ return Math.max.apply(null,arr); } 因为Math.max 参数里面不支持Math.max([param1,param2]) 也就是数组,但是它支持Math.max(param1,param2,param3…),所以可以根据刚才apply的那个特点来解决 var max=Math.max.apply(null,array),这样轻易的可以得到一个数组中最大的一项(apply会将一个数组装换为一个参数接一个参数的传递给方法) 这块在调用的时候第一个参数给了一个null,这个是因为没有对象去调用这个方法,我只需要用这个方法帮我运算,得到返回的结果就行,.所以直接传递了一个null过去。 Array.prototype.push 可以实现两个数组合并,同样push方法没有提供push一个数组,但是它提供了push(param1,param,…paramN) 所以同样也可以通过apply来装换一下这个数组,即: vararr1=new Array("1","2","3"); vararr2=new Array("4","5","6"); Array.prototype.push.apply(arr1,arr2); 也可以这样理解,arr1调用了push方法,参数是通过apply将数组装换为参数列表的集合. 17. 函数定义表达式,表达式的值是这个新定义的函数,一个典型的函数定义表达式包含关键字function,跟随其后的是一对圆括号,括号内是一个以逗号分隔的列表,列表包含有0个或多个标识符,然后再跟随一个由花括号包裹的js代码段,例如 var square = function(x){return x*x;} 函数定义表达式同样可以包含函数的名字 18. // 函数语句 function fn(str) { console.log(str); }; // 表达式定义 var fnx=function(str) { console.log(str+ ' from fnx'); }; 两种方式都创建了新的函数对象, 但函数声明语句的函数名是一个变量名, 变量指向函数对象, 和通过var声明变量一样,函数定义语句中的函数被显示地提前到了脚本或函数的顶部, 因此它们在整个脚本和函数内都是可见的,但是使用var 表达式定义函数, 只有变量声明提前了,变量初始化代码仍然在原来的位置, 用函数语句创建的函数, 函数名称和函数体均被提前,所以我们可以在声明它之前就使用它。 代码例子如下: console.log(typeof(fn)); // function fn('abc'); // abc console.log(typeof(fnx)); // undefined if(fnx) fnx('abc'); // will not execute else console.log('fnx is undefined'); // fnx is undefined // 函数语句 function fn(str) { console.log(str); }; // 表达式定义 var fnx=function(str) { console.log(str+ ' from fnx'); }; 19. 有4种方式调用js函数:作为函数、作为方法、作为构造函数、通过它们的call和apply方法间接调用。 20. 如果一个函数是一个对象的属性或者数组中的一个元素,那么它就是一个作为方法的调用 21. 作为函数的调用,函数体内的this在es5下是undefined,在es3下是全局变量 22. 如果函数或者方法调用之前有关键字new,它就构成构造函数调用 23. callee属性指代当前正在执行的函数,caller指代调用当前正在执行的函数的函数

0
《JavaScript权威指南(第6版)》的全部笔记 135篇
豆瓣
免费下载 iOS / Android 版客户端