读起来使你有新认识或可以使你离更确切的定义更近时的文章不应该被忽略。
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. 一个 Redis 实例最多能存放多少的 keys?List、Set、 Sorted Set 他们最多能存放多少元素?

    理论上 Redis 可以处理多达 232 的 keys,并且在实际中进行了测试,每个实 例至少存放了 2 亿 5 千万的 keys.我们正在测试一些较大的值.任何 list.set. 和 sorted ...

  2. MySQL 里记录货币用什么字段类型?

    NUMERIC 和 DECIMAL 类型被 MySQL 实现为同样的类型,这在 SQL92 标准允 许.他们被用于保存值,该值的准确精度是极其重要的值,例如与金钱有关的数 据.当声明一个类是这些类型之 ...

  3. SpringDataJpa 实体类过滤伪删除

    当需要过滤实体类的数据时,根据伪删除字段进行过滤,需要使用Hibernate提供的@Where注解 使用方式: @Entity(name = "Account") @Where( ...

  4. 哪些是重要的 bean 生命周期方法?你能重载它们吗?

    有两个重要的 bean 生命周期方法,第一个是 setup , 它是在容器加载 bean 的时候被调用.第二个方法是 teardown 它是在容器卸载类的时候被调用. The bean 标签有两个重要 ...

  5. 爬虫-数据解析-bs4

    1.数据解析 解析: 根据指定的规则对数据进行提取 作用: 实现聚焦爬虫 数据解析方式: - 正则表达式 - bs4 - xpath 数据解析的通用原理: 数据解析需要作用在页面源码中(一组html标 ...

  6. Saltstack自动化扩容

    一. etcd服务的安装和使用 1.安装etcd应用: wget https://github.com/coreos/etcd/releases/download/v2.2.5/etcd-v2.2.5 ...

  7. torch.optim.SGD参数详解

    随机梯度下降法 $\theta_{t} \leftarrow \theta_{t-1}-\alpha g_{t}$ Code: optimzer = torch.optim.SGD(model.par ...

  8. swagger的作用和配置使用

    纯API项目中 引入swagger可以生成可视化的API接口页面     引入包 nuget包: Swashbuckle.AspNetCore(最新稳定版) 配置 1.配置Startup类Config ...

  9. Lambda8 表达式

    Lambda 表达式 Lambda 表达式是 JDK8 的一个新特性,可以取代大部分的匿名内部类,写出更优雅的 Java 代码,尤其在集合的遍历和其他集合操作中,可以极大地优化代码结构. JDK 也提 ...

  10. ecahrts实现动态刷新(隔几秒重新显示)

    代码: <script> var chartDom = document.getElementById('main3'); var myChart = echarts.init(chart ...