初学者跪着学JavaScript Day25 : 宁愿找this也不碰历史

一日客语:中文:太阳 客语:ngidˋ teuˇ(日头)

在学建构函式时很常看到this,建构函式内的this会代表新创健的实例(物件),this到底是什麽呢?

函式呼叫传给函式有哪些?

    1. 引数传到参数
    1. this(隐含式参数)

this又称为函式背景空间(function context),就是函式所在的背景空间

那就会跟函式如何被呼叫有关系

  • 一般函式呼叫:包含函式宣告、函式运算式、立即函式是使用()呼叫,this指向全域
  • 物件的方法呼叫:this指向物件
  • 建构函式呼叫
  • apply、call 呼叫
  • 箭头函式没有自己的this,但在定义时记住this值

会随着呼叫函式不同,他们的this会些许不同


一般函式呼叫:

this会是windows物件,那在严格模式下会是undefined

function pig(){
return this}

function dog(){
"use strict"
return this}

pig()//Window
dog()//undefined

// 当使用立即函式
(function pig(){
return this})() //Window

看看浏览器显示画面:
一般函式:
普通模式(pig())和严格模式(dog())

立即函式:


作为物件methods来呼叫:

animal物件里有一个myPig的property name

他的property vlaue 存放一个函式的reference,记得不用括号

像是这样[Function: pig] 是函数物件

呼叫这函式来看看返回this是什麽吧。

this是myPig

function pig() {
    return this;
}

const animal = {
    myPig: pig,
};

console.log(animal.myPig); //[Function: pig]

//pig function回传是this,this是不是animal物件
console.log(animal.myPig() === animal); //true

使用另一个物件crazyanimal来呼叫pig()
此时这个this 会是crazyanimal

const crazyanimal = {
    myPig: pig,
};

console.log(crazyanimal.myPig() === crazyanimal);//true

结论:在不同物件内存pig function 的reference

某物件.pig()呼叫函式 ,this会是指某物件


作为建构器来呼叫

新物件会被当作this

会像是

let 新物件1={
    say:function () {
        return this; //新物件1
}
let 新物件2={
    say:function () {
        return this;//新物件2
}

function Pig() {
    this.say = function () {
        return this;
    };
}
let pigA = new Pig();
let pigB = new Pig();
console.log(pigA.say()); //Pig { say: [Function (anonymous)] }
console.log(pigA.say() === pigA);
console.log(pigB.say() === pigB);

以为这样就结束了吗???

当建构函式有回传值,那该怎麽办


讨论:new+建构函式

建构函式会以大写开头

1.当回传值:Primitive values (基本型别)
2.当回传值:物件

当回传值:Primitive values (基本型别)

会回传新物件

印出会是Pig { say: [Function (anonymous)]

function Pig() {
    this.say = () => '喉喉喉喉';
    return 1000;
}

let littlePig = new Pig();
console.log(littlePig);//Pig { say: [Function (anonymous)] }

当回传值:物件

会回传return 的物件
印出会是 { }

function Pig() {
    this.say = () => '喉喉喉喉';
    return {};
}

let littlePig = new Pig();
console.log(littlePig);//{}
const myobj = {
    cat1: 'nini',
    cat2: 'niki',
};

function Pig() {
    this.say = () => '喉喉喉喉';
    return myobj;
}

let littlePig = new Pig();
console.log(littlePig);//{ cat1: 'nini', cat2: 'niki' }

Note:
建构器的回传值是某一个物件时,那麽新物件会被丢弃而回传那个物件

那如果回传不是物件则会回传新物件


笔记:哪一个物件会成为函式背景空间(this)

呼叫
一般函式:this会是windows
建构函式:this会是实例物件
物件方法:this会是方法的物件

但我想要自行设定this呢 ???你可以使用apply、call

使用apply 、 call 方法

建立函式 >> 建构函式

所有函式(object)都具备applycall方法
因为一般函式上一层是建构函式Function他的prototype有apply()和call()方法

apply(当作函式背景空间的物件,用来当作呼叫引数的阵列值)
call(当作函式背景空间的物件,用来当作呼叫引数,但不是阵列值)


是呼叫函式的方法

function Pig() {
    console.log('哈罗');
}
Pig.call();//哈罗
Pig.apply();//哈罗

和Pig()一样都是会呼叫函式

使用call、apply时
此时this会是第一个参数的物件

function Pig() {
    console.log(this);
}
Pig();//this会是windows

let obj = {};
Pig.call(obj);//{}  指定的{}
Pig.apply(obj);//{} 指定的{}

可以知道使用call和apply呼叫与一般函式呼叫差异

function person() {
    console.log(this.money);
}

let wendy = { money: 1000000000 };
let ann = { money: 300000000 };

person.call(wendy);//1000000000 ,使用这个this会是wendy
person.call(ann);//300000000,使用这个this会是Ann

apply

函数物件.apply(当作函式背景空间的物件,用来当作呼叫引数的阵列值)

Pig.apply(animal,[10,9,8,7]

call

Function.prototype.call

函数物件.call(当作函式背景空间的物件,用来当作呼叫引数,但不是阵列值)

Pig.call(animal,10,9,8,7)


如下:

let wendy = {
    money: 1000000000,
    sleep: function () {
        console.log(this.money);
    },
};
let ann = { money: 300000000 };

console.log(wendy.sleep()); //印出1000000000
//想指定this为ann时
console.log(wendy.sleep.apply(ann)); //印出300000000


当function 有参数时

function person(value1, value2) {
    console.log('value1:', value1);
    console.log('value2:', value2);
    console.log(this.money);
}

let wendy = {
    money: 1000000000,
};
let ann = { money: 300000000 };
person.call(wendy);

//结果
//value1: undefined
//value2: undefined
//1000000000

可以使用第二个参数为引数

apply是要使用阵列

function person(age, score) {
    console.log('age:', age);
    console.log('score:', score);
    console.log(this.money);
}

let wendy = {
    money: 1000000000,
};
let ann = { money: 300000000 };
person.call(wendy, 10, 1000000);


//结果
//age: 10
//score: 1000000
//1000000000

person.apply(wendy, [10, 1000000]);


//结果
//age: 10
//score: 1000000
//1000000000

箭头函式Arrow Functions

mdn:

箭头函式并不拥有自己的 this 变数;使用的 this 值来自封闭的文本上下文,也就是说,箭头函式遵循常规变量查找规则。因此,如果在当前范围中搜索不到 this 变量时,他们最终会寻找其封闭范围。

this会到(lexical scoping)scope找this,不是以呼叫方式来看

Arrow functions do not bind their own this, instead, they inherit the one from the parent scope, which is called "lexical scoping".

不是使用箭头函式时

如下:

此时this是animal

let animal = {
    myfunction: function () {
        return this;
    },
};

console.log(animal.myfunction() === animal); //true

箭头函式时,this是window

let animal = {
    //此时this是window)
    myfunction: () => this,
};

console.log(animal.myfunction() === window); //true

今日结束~

Day 21:箭头函数 (Arrow Functions) 的 this 和你想的不一样 (1)
Understanding "this" in javascript with arrow functions
忍者开发技巧探秘第二版


<<:  Day 25: 人工智慧在音乐领域的应用 (AI作曲 - 长短期记忆网路 LSTM )

>>:  Day25 React Router useParams

Day26 - 针对 Metasploitable 3 进行渗透测试(7) - 利用 Meterpreter 後渗透

何谓後渗透 当恶意攻击者入侵企业之後,会从第一台入口点开始往内部进行攻击,有些企业会使用 Windo...

文书编辑器_vi

前面提到 我在python上面可以很快的去控制GPIO 可是C呢? 在这Linux的环境下,没有ID...

最大可容忍停机时间 (MTD)

最长可容忍停机时间或 MTD 指定了在组织的生存面临风险之前给定业务流程可能无法运行的最长时间。” ...

[Day 15] 实作 OpenAPI Plugin 产生 API 文件

为什麽我想自己实作 Ktor OpenAPI Generator? 大多数的 Web 框架都有官方或...

33岁转职者的前端笔记-DAY 14 排版技巧小笔记-标签属性元素及定位方法

区块元素(block) 预设为区块元素的标签有:h1~h6,p,div,section,header...