读起来使你有新认识或可以使你离更确切的定义更近时的文章不应该被忽略。
this
this既不指向函数自身,也不指向函数的词法作用域(ES6中箭头函数采用词法作用域)。
this实际上是函数被调用时才发生绑定。
this指向什么取决于如何调用函数,谁调用的this,this就指向谁。

1、默认绑定
当独立函数被调用时,不管是否在调用栈中,this都指向全局对象(浏览器中为window)。
默认绑定不适用于严格模式。

<script>
var a = 2;
function foo() {
console.log(a); // 也可以this.a,这里this只window,this.a = 2;
}
function bar() {
var a = 5;
foo();
}
bar(); // 2
</script>

2.1、隐式绑定

当函数引用有上下文对象时,隐式绑定规则会把函数调用中的this绑定这个上下文对象。
对象属性引用链中只有最后一层在调用位置中起作用。
要求:对象内部必须包含一个指向函数的属性,该对象可通过这个属性间接引用函数。

<script>
function foo() {
console.log(this.a)
} var obj2 = {
a: 42,
foo: foo
}; var obj1 = {
a: 2,
obj2: obj2
}; obj1.obj2.foo(); // 42
</script>
2.2、隐式丢失
<script>
function foo() {
console.log(this.a);
}
var obj = {
a: 2,
foo: foo
};
var bar = obj.foo; // 这里bar将引用foo函数本身,所以不带有函数对象上下文。
var a = "oops, global"; // a 是全局对象属性
bar(); // "oops, global"
</script>
2.3、回调函数的情况下(参数传递时的隐式赋值)
<script>
function foo() {
console.log(this.a);
}
function doFoo(fn) {
// 参数传递时fn = obj.foo,fn引用foo函数本身,同样不带有函数对象上下文
fn();
} var obj = {
a: 2,
foo: foo
}; debugger
var a = "oops, global";
doFoo(obj.foo); // "oops, global"
</script>

3、显示绑定

采用call()和apply(),通过传入一个对象(若为基本类型,会被封装函数转为对象——装箱),将this绑定到该对象。

基本类型(String|Boolean|undefined|null|Number)

引用类型(Object,里面包括Function|Array|Date)

<script>
function foo() {
console.log(this.a);
} var obj = {
a: 2
}; // 硬绑定后bar,无论怎么调用,都不会影响foo函数的this绑定。
var bar = function () {
foo.call(obj);
}; var a = "oops, global";
bar(); // 2
setTimeout(bar, 100); // 2
bar.call(window); // 2 // var obj = {a: 2}换成 var obj = "str"时,函数foo中的this为String,打印出来三个undefined(String对象中没有属性)
</script>

硬绑定典型应用——包裹函数

<script>
function foo(something) {
console.log(this.a, something);
return this.a + something;
} var obj = {
a: 2
}; var bar = function () {
return foo.apply(obj, arguments); // 将obj对象硬编码进去
}; var b = bar(3); // 2, 3 注:arguments可以是bar函数传进来的参数,也可以直接某一具体数组,如[5],这时打印出2, 5
console.log(b); // 5 如果arguments为[5],则输出7
</script>
<script>
function foo(something) {
console.log(this.a, something);
return this.a + something;
} function bind(fn, obj) {
return function () {
return fn.apply(obj, arguments); // 利用参数将obj传入
};
} var obj = {
a: 2
}; debugger;
var bar = bind(foo, obj); // bind(foo, obj)会返回一个包裹函数
var b = bar(3); // 2 3
console.log(b); // 5
</script>

上述包裹函数,想要包裹其他函数,只能一个一个重复写,硬编码的方式导致不能被重用,当某种功能需要多次重复使用时,将其抽象出来,成为函数。

4、new 绑定

任何函数都可能被用作构造函数,当函数被new操作符“构造调用”时,会执行以下操作:

1、创建一个新对象(若该函数不是JS内置的,则创建一个新的Object对象);

2、将this绑定到这个对象;

3、执行构造函数中的代码(为这个新对象添加属性);

4、若函数没有返回其他对象,则自动返回这个新对象;若函数有return返回的是非对象,则还是自动返回这个新对象,即覆盖那个非对象。

<script>
function foo(a) {
this.a = a;
}
var bar = new foo(2); // bar 即为foo 这里的foo指的是一个新创建的对象,this也指向它,this.a 即是为该对象添加属性。这里我想告诉自己的是这里的foo对象并不能看做console.log(foo)的foo
console.log(foo); // ƒ foo(a) {this.a = a;} foo是个函数对象
console.log(typeof foo); // function
console.log(typeof bar); // object
console.log(foo instanceof Function); // true
console.log(bar instanceof Function); // false
console.log(bar instanceof Object); // true
console.log(bar.a); // 2
console.log(new foo(4).constructor ); // f foo(a) {this.a = a} 返回的是个函数foo啊
console.log("------------------------------------"); /*
var bar = new foo(2);
这里其实是将new foo(2)创建的对象赋值给bar,创建的新对象为foo【new foo(2)和bar的constructor都为foo】。
函数构造后,函数内的this指向指着函数名,也就是bar其实指的是foo对象,
当console.log(bar == foo)是false的, 因为这里的话bar是对象,而foo则是指function foo(a) {this.a = a;}
*/ </script>
<script>
function returnObj(c) {
this.c = c;
return {d: "Hei~"};
} var obj = new returnObj(1); // 构造函数有返回值后,this指向返回的对象【{d: "Hei~"}】,不是returnObj了,this.c是作为returnObj的属性。
console.log(bar.c); // undefined
console.log(obj instanceof Object); // true
console.log(obj.constructor); // ƒ Object() { [native code] }
console.log(new returnObj(2).c); // undefined
console.log(new returnObj(4).d); // Hei~
</script>
这部分内容记录来来自于《你不知道的JS
<script>
var fun = {
'foo': 'foo1',
'bar': 'bar1'
}; var o = Object.create(fun);
console.log(o.foo); // foo1
console.log(o.hasOwnProperty("foo")); // false
console.log(o.__proto__.foo); // foo1
</script> <script>
function NothingSpecial() {
console.log("Dont't mind me");
}
var a = new NothingSpecial(); // Dont't mind me
console.log(a); // NothingSpecial {}
</script>
<!--
NothingSpecial 只是一个普通的函数, 但是使用 new 调用时, 它就会构造一个对象并赋值
给 a, 这看起来像是 new 的一个副作用(无论如何都会构造一个对象)。 这个调用是一个构
造函数调用, 但是 NothingSpecial 本身并不是一个构造函数。
换句话说, 在 JavaScript 中对于“构造函数” 最准确的解释是, 所有带 new 的函数调用。
函数不是构造函数, 但是当且仅当使用 new 时, 函数调用会变成“构造函数调用”
-->

间接引用

<script>
function foo() {
consoles.log(this.a);
} var a = 2;
var o = {a: 3, foo: foo};
var p = {a: 4}; foo(); // 2
o.foo(); // 3
(p.foo = o.foo)(); // 2, 由于p.foo = o.foo返回的是目标函数的引用,所以调用位置是foo(),而不是p.foo()或o.foo()
</script>

1、默认绑定当独立函数被调用时,不管是否在调用栈中,this都指向全局对象(浏览器中为window)。默认绑定不适用于严格模式。

随机推荐

  1. dp求最长递增子序列并输出

    1 import java.util.ArrayList; 2 import java.util.Arrays; 3 import java.util.List; 4 5 /** 6 * Create ...

  2. C语言中的bool类型 stdbool.h

    C语言的C99标准中已经可以使用bool类型了,但有些小伙伴可能受制于编译器等原因还无法使用,我就从最新版的VS2019 中,找到了stdbool.h这个头文件的定义,其实就是一堆宏的定义,代码如下: ...

  3. 安装Yarn

    安装Yarn Yarn是比npm更高效.快速的包管理器工具,它支持并行下载程序包,并且简化了包管理的复杂度. 使用npm安装yarn,命令npm install -g yarn. 安装后,使用yarn ...

  4. 【二次元的CSS】—— 用 DIV + CSS3 画大白(详解步骤)

    原本自己也想画大白,正巧看到一位同学(github:https://github.com/shiyiwang)也用相同的方法画了. 且细节相当到位.所以我就fork了一下,在此我也分享一下.同时,我也 ...

  5. 从零开始:微信小程序新手入门宝典《一》

    为了方便大家了解并入门微信小程序,我将一些可能会需要的知识,列在这里,让大家方便的从零开始学习: 一:微信小程序的特点 张小龙:张小龙全面阐述小程序,推荐通读此文: 小程序是一种不需要下载.安装即可使 ...

  6. React 可视化开发工具 Shadow Widget 非正经入门(之五:指令式界面设计)

    本系列博文从 Shadow Widget 作者的视角,解释该框架的设计要点.本篇解释 Shadow Widget 中类 Vue 的控制指令,与指令式界面设计相关. 1. 指令式界面设计 Vue 与 A ...

  7. leetcode921. 使括号有效的最少添加

    题目描述: 给定一个由 '(' 和 ')' 括号组成的字符串 S,我们需要添加最少的括号( '(' 或是 ')',可以在任何位置),以使得到的括号字符串有效. 从形式上讲,只有满足下面几点之一,括号字 ...

  8. Vue整合Quill富文本编辑器

    Quill介绍 Quill是一款开源的富文本编辑器,基于可扩展的架构设计,提供丰富的 API 进行定制.截止2021年1月,在github上面已有28.8k的star. Quill项目地址:https ...

  9. Docker操作容器2

    Docker操作容器1:https://blog.csdn.net/Kevinnsm/article/details/ 1.如何更改docker容器中的配置文件(如nginx容器中的nginx.con ...

  10. LibreOffice(开源免费办公软件)

    LibreOffice(开源免费办公软件) 官方地址 中文网站:https://zh-cn.libreoffice.org/ 下载地址: https://zh-cn.libreoffice.org/d ...