JS闭包直接调用外层函数和把函数赋值给变量再调用有啥区别?

本文探讨了JavaScript中函数表达式与函数声明的不同之处,包括执行时机、作用域提升及ES6中块级作用域的引入,并给出了具体示例。
    function f1(){
        n = 999;
        return function f2(){
            alert(n);
        }
    }
//    var result=f1();      //这里是调用了一个f1()函数, 但是f1()函数所返回的是一个函数引用
//    result(); // 999      //所以要赋值给result再加个括号() 调用一次方法.

//    f1()();   //以上两行等价于因为return返回的 是一个函数,所以 fn1() 得到一个函数.fn1()() 
        调用该函数

javascript中 ”匿名函数赋值给变量“与“直接命名函数”有什么不同的作用?


数赋值给变量“与“直接命名函数”有什么不同的作用?

两种写法最大的区别是:

var init = function() { }; 是函数表达式,函数在代码执行的到当前行的时候才被执行,init 才被赋值。

function init() {} 是函数的声明,和 var 一样,会被提前到代码最前面定义。

所以,下面的两个例子:

1
2
3
4
foo(); // 在函数声明之后调用 foo,可以正常调用。因为 foo 被提前到最前面定义了。
function foo() {
    return true;
}
1
2
3
4
foo(); // 在函数表达式之前调用函数,报错。因为这时候还没有 foo 这个变量。
var foo = function() {
    return foo;
};

ES5 规定,函数只能在顶级作用域和函数作用域中声明,否则是不合法的。例如:

1
2
3
4
5
6
iftrue ) {
    // 非顶级和函数作用域内定义函数,是错误的,虽然可能浏览器不一定会抛出错误,但是是不规范的。
    function foo() {
        return true;
    }
}

ES6 引入了块级作用域的概念,这种定义方法就被允许了。在块级作用域里面声明的函数,作用域类似于使用 let 声明的变量,在块级作用域之外没有办法被调用。

例如:

1
2
3
4
5
6
{
    function foo() {
        return true;
    }
}
foo(); // 在函数声明的代码块之外调用函数,会抛出错误。

在 JavaScript 中,将对象中的方法赋值变量后再通过该变量调用时,`this` 的指向会发生变化。这种情况下,`this` 不再是指向原始对象,而是默认指向全局对象(如 `window` 或者 `global`),或者是严格模式下的 `undefined`。这是因为直接从对象上调取方法单独调用函数有着不同的 `this` 绑定规则。 让我们来看一些具体的例子帮助理解这一点: ### 示例1:非严格模式下 ```javascript const myObject = { value: 'hello', method: function() { console.log(this.value); } }; // 直接调用myObject.method() myObject.method(); // 输出: hello // 把method赋值给一个变量调用它 const fn = myObject.method; fn(); // 非严格模式下输出: undefined (因为此时this指向window/global, 并不存在value属性) ``` ### 示例2:严格模式下 ```javascript 'use strict'; const anotherObj = { prop: 42, showProp: function() { console.log(this.prop); } }; const funcRef = anotherObj.showProp; funcRef(); // 严格模式下抛出错误TypeError: Cannot read property 'prop' of undefined 因为此时this是undefined ``` 为了避免这种情况发生,并保持原有的上下文,我们可以采用以下几种解决方案: #### 方案一:使用 `.bind()` 方法 `.bind()` 返回一个新的函数,同时设置了新的 `this` 上下文。 ```javascript const boundMethod = myObject.method.bind(myObject); boundMethod(); // 正确地打印出了 "hello" ``` #### 方案二:利用闭包保存对原对象的引用 你可以返回一个匿名函数并在其中访问对外部作用域中定义的对象进行操作。 ```javascript function createBoundFunction(obj) { return function(...args) { obj.method.apply(obj, args); // 显式设定this为目标对象 }; } const customFunc = createBoundFunction(myObject); customFunc(); // 同样能够正确打印 "hello" ``` #### 方案三:箭头函数简化语法糖 ES6 引入了箭头函数,它们不会创建自己的 `this`,相反会捕获外层函数的作用域链里的 `this` 值。因此,在某些简单的情况下,可以直接使用箭头函数来解决问题。 ```javascript const arrowFn = () => myObject.method(); arrowFn(); // 成功显示 "hello", 当然这实际上还是需要依赖于原来的对象结构 ``` 总之,在处理对象内嵌的方法时一定要特别注意如何维护好正确的 `this` 上下文。通常来说,最推荐的做法之一是使用 `.bind()` 来确保一致性以及可预测的行为。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值