读起来使你有新认识或可以使你离更确切的定义更近时的文章不应该被忽略。
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. Vue Avoided redundant navigation to current location Error

    这个报错的根源就是vue-router组件,错误内容翻译一下是: Avoided redundant navigation to current location === 避免冗余导航到当前位置 这个 ...

  2. idea-spring-boot打包jar/var

    下面的插件配置的里面需要加上具体的main类 <groupId>org.springframework.boot</groupId> <artifactId>spr ...

  3. GC日志浅析

    //java 开发环境,使用HotSpot的虚拟机,64位,windows 开发环境 Java HotSpot(TM) 64-Bit Server VM (25.151-b12) for window ...

  4. 攻防世界baby_web

    baby_web 题目提示想想初始页,但我们一访问就会跳转到1.php我们使用bp抓包分析,我们发送到repeater模块修改请求访问1.php内容看看 发现flag隐藏了我们去hex中看看 这样我们 ...

  5. onsubmit阻止表单提交

    在实际开发中往往会遇到检查表单数据的合法性,如果数据不合法,就不让其提交. <!DOCTYPE html> <html> <head> <meta chars ...

  6. 微信小程序开发快速入手

    1.在page中的修改数据的setData函数,需要传递的是一个对象. that.setData({ src: res.tempFilePath }) 2.在 onload 事件中,可以获取wx.na ...

  7. vue+koa2即时聊天,实时推送比特币价格,爬取电影网站

    技术栈 vue+vuex+vue-router+socket.io+koa2+mongodb+pm2自动化部署+图灵机器人+[npm script打包,cdn同步,服务器上传一个命令全搞定] 功能清单 ...

  8. javaweb之修改功能

    数据库的修改功能,主要是通过查询,保留之前的数据,得到当前想要修改的页面,并进行修改. 一.dao层 在dao层需要添加两个fangfa,一个查询,一个修改(这是整个dao层,包括之前的增删.浏览) ...

  9. springMVC中获取request和response对象的几种方式(RequestContextHolder)

    springMVC中获取request和response对象的几种方式 1.最简单方式:参数 2.加入监听器,然后在代码里面获取 原文链接:https://blog.csdn.net/weixin_4 ...

  10. windows下的volatility取证分析与讲解

    volatility(win64) 1.下载 volatility 下载地址:(我下载的版本2.6,并把名字稍微改了一下) Release Downloads | Volatility Foundat ...