函数 html
实现特定功能的 n 条语句封装体。c++
1. 建立一个函数对象面试
var myFunc = new Function(); // typeof myFunc 将会打印 function
var aFunc = new Function("console.log('Hello!');"); console.log(aFunc); // 打印: " function anonymous(){ console.log("Hello!"); } "
function myFunc(){ console.log("Hello myFunc !"); }
// 会 函数声明 提高
var myFunc = function(){ console.log("Hello myFunc ! "); };
// 会 变量声明 提高
var myAdd = function(a,b){ // 传递多个参数使用,隔开 console.log(a+b); };
注意:函数解析器不会检查实参的类型; 多余的参数将不会被使用; 缺乏的参数定义为 undefined数组
2. 函数的返回值 外界须要函数处理的值安全
使用 return 关键字返回指定结果,并结束函数。闭包
不写 return 默认为 return ; 此时的函数返回值为 undefinedapp
3. 函数的参数 当没法肯定 n 个变量的值时, 使用 n 个参数 传递____形参异步
length
属性返回函数预期传入的参数个数,即函数定义之中的参数个数
length
属性就是定义时的参数个数。无论调用时输入了多少个参数,length
属性始终等于 形参个数
function f(a, b){} f.length // 2
function f(a, a) { console.log(a); } f(1, 2) // 2 f(1) // undefined // 这时,若是要得到第一个a的值,可使用arguments对象。 function f(a, a) { console.log(arguments[0]); } f(1) // 1
只有函数调用时,才能动态肯定 this 的指向函数
.call(obj, 12, 13);工具
.apply(obj, [12, 13]);
.bind(obj, 12, 13); 重构建函数
不会当即执行函数,而是会建立一个新函数,新函数的 this 指向 obj,参数也被传递
也不会修改原函数的 this
arguments 实参列表
对象 只有数组的 length 属性,可以经过 index 读写数据
arguments[0]
就是第一个参数,arguments[1]
就是第二个参数,以此类推。这个对象只有在函数体内部,才可使用。
var f = function (one) { console.log(arguments[0]); console.log(arguments[1]); console.log(arguments[2]); } f(1, 2, 3) // 1 // 2 // 3
arguments
对象能够在运行时修改。
var f = function(a, b) { arguments[0] = 3; arguments[1] = 2; return a + b; } f(1, 1) // 5
arguments
对象是一个只读对象,修改它是无效的,但不会报错。
var f = function(a, b) { 'use strict'; // 开启严格模式 arguments[0] = 3; // 无效 arguments[1] = 2; // 无效 return a + b; } f(1, 1) // 2
arguments
对象的 length
属性,能够判断函数调用时到底带几个参数。arguments
很像数组,但它是一个对象。数组专有的方法(好比 slice
和 forEach
),不能在 arguments
对象上直接使用。
arguments
对象使用数组方法,真正的解决方法是将arguments
转为真正的数组。下面是两种经常使用的转换方法:
//slice方法 var args = Array.prototype.slice.call(arguments);
//逐一填入新数组。 var args = []; for (var i = 0; i < arguments.length; i++) { args.push(arguments[i]); }
arguments
.callee
属性,返回它所对应的原函数
var f = function () { console.log(arguments.callee === f); } f() // true // 能够经过arguments.callee,达到调用函数自身的目的。 // 这个属性在严格模式里面是禁用的,所以不建议使用。
undefined
undefined
function f(a, b) { return a; } f( , 1) // 报错 SyntaxError: Unexpected token ,(…) f(undefined, 1) // undefined
var sun = { name:"孙悟空", gender:"男", age:600 }; function sayHello(obj){ document.write("你们好,我是"+obj.name+", "+obj.gender+", "+obj.age+"岁了"); } sayHello(sun);
function haha(someFunc){ someFunc(); } haha(sayHello);
4. 函数的属性和方法
.name 属性,返回函数的名字
function f1() {} f1.name // "f1" var f2 = function () {}; f2.name // "f2" var f3 = function myName() {}; f3.name // 'myName'
.toString()
方法返回一个字符串,内容是函数的源码
function f() { a(); b(); c(); // 这是注释 } f.toString() // function f() { // a(); // b(); // c(); // 这是注释 // }
5. 做用域(scope)
变量存在的范围。
不一样做用域的同名变量不会冲突
function Foo() { getName = function () { alert (1); }; return this; } Foo.getName = function () { alert (2);}; Foo.prototype.getName = function () { alert (3);}; var getName = function () { alert (4);}; function getName() { alert (5);} //请写出如下输出结果: Foo.getName(); getName(); Foo().getName(); getName(); new Foo.getName(); new Foo().getName(); new new Foo().getName();
var getName; window.getName = function () { alert (4);}; function Foo() { // window.Foo getName = function () { alert (1); }; // 覆盖 window.getName return this; }; window.Foo.prototype.getName = function () { alert (3);}; window.Foo.getName = function () { alert (2);}; //请写出如下输出结果: Foo.getName(); // window.Foo.getName() 2 getName(); // window.getName() 4 // this.getName() window.getName() 1 注意是在何时被覆盖的 Foo().getName();
getName(); // window.getName() 1 new Foo.getName(); // window.Foo.getName() 2 // 注意 new 返回的是对象 直接调用返回看return // f.getName() window.f.getName() window.Foo.prototype.getName 3 new Foo().getName();
new new Foo().getName(); // new window.f.getName() 3
6. 闭包 closure
① 嵌套: 做为函数里面的 函数 fn2
② fn2 引用了外部函数的局部变量
③ 外部函数 被调用执行时产生闭包,在 new 的时候也至关于执行了____实质是在 第一个知足以上条件 的函数被解析到是,产生闭包
此时就产生了一个闭包____ fn2.Scopes[0] = fn2.closure————包含了被引用局部变量的一个"对象",存在于嵌套的内部函数中,可使用调试工具查看到。
其中 [[Scopes]] 是由底层 c/c++ 实现
缺点:
因为闭包的存在,未释放,致使占用内存时间变长。易形成内存泄漏
怕的就是出现 很是多个闭包
解决:
能不用闭包就不用闭包
及时释放____让 指向含闭包函数的 变量,指向 null
function Person(name) { var _age; function setAge(n) { _age = n; } function getAge() { return _age; } return { name: name, getAge: getAge, setAge: setAge }; } var p1 = new Person('张三'); p1.setAge(25); // 操做的是 闭包中的 _age p1.getAge() // 访问的是 闭包中的 _age
// 上面代码中,函数的内部变量,经过闭包和,变成了返回对象的私有变量。Person_agegetAgesetAgep1
注意
外层函数每次运行,都会生成一个新的闭包,而这个闭包又会保留外层函数的内部变量,因此内存消耗很大。
所以不能滥用闭包,不然会形成网页的性能问题。
fn2
记住了它诞生的环境 fn1
的内部变量。在本质上,闭包就是将函数内部和函数外部链接起来的一座桥梁。
function f1() { var n = 999; function f2() { console.log(n); } return f2; } var result = f1(); result(); // 999
// 函数的返回值就是函数,因为能够读取的内部变量,因此就能够在外部得到的内部变量了f1f2f2f1f1
f2
,即可以读取其余函数内部变量的函数。
function createIncrementor(start) { return function () { return start++; }; } var inc = createIncrementor(5); // 执行了 外层函数,而后销毁了 函数上下文,即 全部外层函数的变量都销毁了 inc(); // 5 inc(); // 6 inc(); // 7
7. 当即调用的函数表达式(IIFE)
自调用匿名函数
____封装时, 隐藏函数内部具体实现, 防止外部修改函数内的代码
____防止污染外部命名空间
这就叫作“当即调用的函数表达式”(Immediately-Invoked Function Expression),简称 IIFE。
// 写法一 var tmp = newData; processData(tmp); storeData(tmp); // 写法二 更好,由于彻底避免了污染全局变量。 (function(w){ // var tmp = newData; processData(tmp); storeData(tmp); }(window)); // 方便对代码进行压缩, 变量 window 改为 w, 减少代码体积
()
是一种运算符,跟在函数名以后,表示调用该函数。 好比,isNaN()
就表示调用 isNaN
函数。function
出如今行首,为了避免让引擎将其理解成一个表达式。最简单的处理,就是将其放在一个圆括号里面。
8. 回调函数
自定义的,不被本身调用的,达到某种条件后被某对象调用了。
异步加载通知机制:
全部异步代码,不能当即执行
只有等主进程执行完全部代码后,才会执行 异步代码
setTimeout(function(){ console.log("异步代码"); }, 0); console.log("主进程代码");
// 打印:
// 主进程代码
// 异步代码
9. eval
命令
接受一个字符串做为参数,并将这个字符串看成语句执行。
eval('var a = 1;'); a // 1
// Uncaught SyntaxError: Invalid or unexpected token
eval
的参数不是字符串,那么会原样返回。eval
没有本身的做用域,都在当前做用域内执行,所以可能会修改当前做用域的变量的值,形成安全问题。eval
内部声明的变量,不会影响到外部做用域。
eval
依然能够读写当前做用域的变量。
(function f() { 'use strict'; var foo = 1; eval('foo = 2'); console.log(foo); // 2 })()
因此通常不推荐使用。一般状况下,eval
最多见的场合是解析 JSON 数据的字符串,不过正确的作法应该是使用原生的JSON.parse
方法。
eval
的别名调用的形式五花八门,只要不是直接调用,都属于别名调用,由于引擎只能分辨eval()
这一种形式是直接调用。
eval.call(null, '...'); window.eval('...'); (1, eval)('...'); (eval, eval)('...'); // 上面这些形式都是eval的别名调用,做用域都是全局做用域。
内存溢出
须要的内存,大于现有内存
内存泄漏
资源占有一片空间,而不曾释放,致使这片内存没法被使用
及时 obj = null; 来释放内存
在函数中, 未使用 var 关键字定义变量, 致使直接声明了一个全局变量
10. 属性描述符