读起来使你有新认识或可以使你离更确切的定义更近时的文章不应该被忽略。
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. java使用正则表达式在文档里找匹配

    public static void main(String[] args) { String str = "123我是456张三789的学生"; String regex2 = ...

  2. 解释AOP模块?

    AOP模块用于发给我们的Spring应用做面向切面的开发, 很多支持由AOP联盟提供,这样就确保了Spring和其他AOP框架的共通性.这个模块将元数据编程引入Spring.

  3. 分享一波dubbo mybatis plus百度云链接

    https://pan.baidu.com/s/1VtfoVJwan-XPvmQfBIKMhA

  4. java模板设计

  5. hanoi(汉诺塔)递归实现

    汉诺塔:汉诺塔(又称河内塔)问题是源于印度一个古老传说的益智玩具.大梵天创造世界的时候做了三根金刚石柱子,在一根柱子上从下往上按照大小顺序摞着64片黄金圆盘.大梵天命令婆罗门把圆盘从下面开始按大小顺序 ...

  6. 3.3转1.8V(电平转换)

  7. python爬虫---虎牙直播封面采集

    代码: import requests from lxml import etree # html解析库 source = requests.get("https://www.huya.co ...

  8. SimpleDateForma求日期,2008-11月第6周星期日是几号?

    题目4: 巧妙利用SimpleDateFormat根据各种信息求日期.2008-11月第6周的星期日是几号? import java.text.ParseException;import java.t ...

  9. (ICONIP2021)On the Unreasonable Effectiveness of Centroids in Image

    目录 摘要 1.引言 2.提出的方法 2.1 CentroidTripletloss 2.2 聚合表示 3.实验 3.1 数据集 3.2 应用细节 3.3 Fashion检索结果 3.4 行人再识别结 ...

  10. springboot项目找不到符号问题以及模块聚合项目maven插件使用的相关问题

    问题如图 更换maven,清空缓存重新导入依赖依然无效后 解决方法: 方式一:删除项目中.idea文件夹,重新打开项目,选中jdk版本 ,重新导入依赖即可. 最近又遇到找不到符号问题,本地运行没问题, ...