场景助手4.1怎么使用_闭包的使用场景_js闭包的应用场景

思维导图

场景助手4.1怎么使用_闭包的使用场景_js闭包的应用场景

this 的指向

再来看一下这句话:执行函数前有’.’点操作符的话,函数体中的this就指向前面的对象,没有就指向window

一、普通函数 this 的热身题热身题 1

var name = '林一一'
function fn(){
    var name = '林二二'
    return this.name
}
fn()    // 林一一
复制代码

执行函数fn()闭包的使用场景,前面没有’.’点操作符吧,那么这里的this就指向window。输出的就是全局下的name = ‘林一一’。

再来看一下这句话:执行函数前有’.’点操作符的话,函数体中的this就指向前面的对象,没有就指向window

热身题 2

var name = '林二二'
var obj = {
    name'林一一',
    fnfunction ({
        return this.name
    }
}
console.log(obj.fn())   // '林一一'
var fo = obj.fn
console.log(fo())       // '林二二'     fo() ==> window.fo()
复制代码

obj.fn()中函数fn()前面有’.’点操作符吧,那么这里的this就指向obj这个对象。再看执行函数fo(),前面没有’.’点操作符吧,那么这里的this就指向window。其实上面的函数fo() ==> window.fo(),所以执行函数fo()前面也是可以看作是有’.’操作符的。

再来看一下这句话:执行函数前有’.’点操作符的话,函数体中的this就指向前面的对象闭包的使用场景,没有就指向window

热身题 3,修改一下热身题 2

var name = '林二二'
var obj = {
    name'林一一',
    fnfunction ({
        var name = '小三'
        return function(){
             return this.name
        }
    }
}
console.log(obj.fn()())   // 林二二
var fo = obj.fn()
console.log(fo())    // 林二二
复制代码

热身3和热身2差不多,obj.fn()()中obj.fn()执行完后有一个函数(这里称为函数A)返回,最后相当于执行函数A(),A()前面没有’.’点操作符吧,那么这里的this就指向window,输出就是林二二了。上面的fo()函数同理。

二、函数没有直接调用者(更新)

函数没有直接调用者this指向全局对象(浏览器中是window,node中是 global),如匿名函数等;严格模式下指向undefined

热身题 1

var name = '林一一';
!(function(){
   console.log(this.name)   // 林一一
})()
复制代码

自执行函数没有直接的调用者输出的name = ‘林一一’。

热身题 2

var name = '林一一'
var obj = {
    name : '二二',
    callbackfunction(){
        console.log(this.name)
    }
}

setTimeout(obj.callback,1000)
/* 输出
*   林一一
*/

复制代码

函数setTimeout,obj.callback(这只是一个引用地址)中并没有直接调用者,this就指向window。所以输出的name就是全局下的林一一。

三、构造函数中的 this

来读一下这句话:构造函数的this指向实例本身

关于构造函数的this为什么指向实例是浏览器指定的,详情看new这个过程发生了什么 面试 | 你不得不懂得 JS 原型和原型链

热身题 1

function Fn(){
    var n = 0
    this.name = '林一一'
    this.age = 18
    this.getName = function(){
        return this.name
    }
}

Fn.prototype.getAge = function(){
    return this.age
}

Fn.x = '林二二'

var f = new Fn()
console.log(f.name)     // 林一一
console.log(f.getName())     // 林一一
console.log(f.getAge())        // 18
console.log(f.n)    // undefined
console.log(f.x)    // undefined
复制代码

上面的Fn经过new后就是一个构造函数,this就指向实例f。所以上面的1,2输出都是林一一。f.getAge()是实例f调用了getAge输出就是 18,问:实例f中并没有属性getAge是怎么输出 18的,f.x输出又为什么是undefined?答:这是原型链的查找机制,属性x不是在原型prototype上的就不是实例的属性,可以读一下这篇文章 面试 | 你不得不懂得 JS 原型和原型链;问:为什么f.n输出的是undefined。因为变量n是构造函数的私有变量和new创建的实例没有关系。

四、箭头函数热身题 1

var name = '林一一'
var obj = {
    name'二二',
    a() => {
        console.log(this.name)
    }
}
obj.a()

/* 输出
*   '林一一'
*/

复制代码

箭头函数的this,找不到非箭头函数的this就直接指向window。

热身题 2

var name = '林一一'
var obj = {
    name'二二',
    fnfunction({
        return () => {
            console.log(this.name)
        }
    }
}
obj.fn()()

/* 输出
*   '二二'
*/

复制代码

很明显箭头函数的this来自函数fn,对象obj调用了函数fn,所以fn的this指向obj,输出结果就是二二。

五、call,apply,bind 改变 this 的指向

提示:所有的函数都是基于Function这个基类来创建的,同样拥有Function原型上面的方法

热身题

var name = '林一一'
var age = 18
function fn(){
   return this.name
}

function p(){
    return {
        agethis.age,
        argarguments
    }
}

let obj = {
    name'二二',
    age18
}

let o = {
    name'三三'
}

fn()    // '林一一'
fn.call(obj)    // '二二'
fn.call(o)  //  '三三'
p.call(obj, 12234567// {age: 18, arg: Arguments(4)}

fn.apply(obj)    // "二二"
p.apply(obj, [12345])    // {age: 18, arg: Arguments(5)}

fn.bind(obj)()  // "二二"
p.bind(obj, 122334)()   // {age: 18, arg: Arguments(3)}
复制代码

以上就是call,apply,bind, 关于this的内容,这里不介绍三者的写法,如果介绍可以写另一篇文章了。对这三者不熟悉的可以找其他资料看看。

思考题1. 笔试题 this 指向问题

var name = '林一一'
var obj = {
    name'林二二',
    showfunction (){
        console.log(this.name)
    },
    waitfunction ({
        var fn = this.show
        fn()
    }
}
obj.wait()  //  林一一
复制代码

obj.wait()中,执行函数wait()前面有’.’点操作符吧,那么这里的this就指向obj这个对象,所以this.show ==> obj.show。再看执行函数fn()前面没有’.’点操作符吧,那么这里的this就指向window,输出就是林一一。

2. 阿里 this 指向和原型面试题(新增)

new 创建函数的过程中发生了什么可以看这篇 面试 | 你不得不懂得 JS 原型和原型链

function Foo({
    Foo.a = function({
        console.log(1)
    }

    this.a = function({
        console.log(2)
    }
}

Foo.prototype.a = function({
    console.log(3)
}

Foo.a = function({
    console.log(4)
}

Foo.a();

let obj = new Foo(); 
obj.a();
Foo.a();
/*
*   4
*   2
*   1
*/

复制代码

Foo.a();中直接调用函数的私有方法a输出结果就是 4。new Foo();过程中函数的私有a被重新赋值,同时原型prototype上的属性a也被重新赋值。所以obj.a();输出结果就是 2,Foo.a();输出结果就是 1。

3. 和闭包有关的 this 指向问题

var n = 2 // -> 4 -> 8
var obj = {
    n3,    // 6
    fn: (function(n){
        n*=2
        this.n+=2    // window 下的 n 变成 4
        var n = 5    // 这一步不会再重新声明,因为已经参数赋值,就不会再声明而是直接赋值 n = 5
        console.log("window.n"window.n)
        return function (m{
            console.log("n:", n, "m", m)    // n:5  m:3  这里的 n 向上查找是 5   // 
            this.n*=2    // fn(3): 2 * 4 =8  //  obj.fn(3): 2 * 3 = 6 
            console.log(m + (++n))    // 3 + (++5) ++n 导致上级作用域的n变成了6    // 3 + (++6)
        } 
    })(n)
}

var fn = obj.fn;
fn(3)    // 9
obj.fn(3)    // 10
console.log(n, obj.n)    // 8 6
/* 输出
* 9
* 10
* 8  6
/
复制代码

这道题就留给大家思考了,上面有我的分析步骤,觉得碍眼的话可以去掉 。你可以在评论区给出你的分析过程。

限时特惠:本站每日持续更新海量设计资源,一年会员只需29.9元,全站资源免费下载
站长微信:ziyuanshu688