this

  • ES6中的箭头函数采用的是词法作用域。
  • 为什么要使用this:使API设计得更简洁且易于复用。
  • this即不指向自身,也不指向函数的词法作用域。
  • this的指向只取决于函数的调用方式

this绑定规则

  • new > 显示绑定 > 隐式绑定 > 默认绑定

默认绑定

  • 当独立函数调用时,不管是否在调用栈中,this都指向全局对象(浏览器中为window)
  • 严格模式下,不能将全局对象用于默认绑定。
var a = 2;
function foo(){
console.log(this.a);
}
function bar(){
var a = 5;
foo();
}
bar(); // 2

隐式绑定

  • 当函数引用有上下文对象时,隐式绑定规则会把函数调用中的this绑定到这个上下文对象。
  • 对象属性引用链中只有最后一层在调用位置中起作用。
  • 要求:对象内部必须包含一个指向函数的属性,该对象可通过这个属性间接引用函数。
function foo() {
console.log( this.a );
} var obj2 = {
a: 42,
foo: foo
}; var obj1 = {
a: 2,
obj2: obj2
}; obj1.obj2.foo(); // 42
  • 隐式丢失
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"

和回调函数的情况下(参数传递时的隐式赋值)

function foo() {
console.log( this.a );
} function doFoo(fn) {
// 参数传递时,相当于fn = obj.foo,就和上个例子一样了
fn(); // <-- call-site!
} var obj = {
a: 2,
foo: foo
}; var a = "oops, global"; // `a` also property on global object doFoo( obj.foo ); // "oops, global"

显式绑定

  • 采用call()和apply(),通过传入一个对象(若为基本类型,会被封装函数转为对象—装箱),将this绑定到该对象。
  • 硬绑定
function foo() {
console.log( this.a );
} var obj = {
a: 2
}; var bar = function() {
foo.call( obj );
}; bar(); // 2
setTimeout( bar, 100 ); // 2 // 硬绑定后bar无论怎么调用,都不会影响foo函数的this绑定
bar.call( window ); // 2

硬绑定的典型应用是如下的包裹函数:

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
console.log( b ); // 5

即将内部函数用apply硬绑定到某个对象,无论怎么调用这个包裹函数,都不会影响内部函数的this。
bind辅助函数如下:

function foo(something) {
console.log( this.a, something );
return this.a + something;
} // simple `bind` helper
function bind(fn, obj) {
return function() {
return fn.apply( obj, arguments ); // 利用参数将obj传入进去
};
} var obj = {
a: 2
}; var bar = bind( foo, obj ); // bind( foo, obj )会返回一个包裹函数 var b = bar( 3 ); // 2 3
console.log( b ); // 5

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

new绑定

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

1. 创建一个新对象(若该函数不是JS内置的,则创建一个新的Object对象);
2. 将this绑定到这个对象;
3. 执行构造函数中的代码(为这个新对象添加属性);
4. 若函数没有返回其他对象,则自动返回这个新对象;若函数有return返回的是非对象,则还是自动返回这个新对象,即覆盖那个非对象。

function foo(a) {
this.a = a;
} var bar = new foo( 2 );
console.log( bar.a ); // 2

补充说明

  • 间接引用
function foo() {
console.log( this.a );
} var a = 2;
var o = { a: 3, foo: foo };
var p = { a: 4 }; o.foo(); // 3
(p.foo = o.foo)(); // 2,由于p.foo = o.foo的返回值是目标函数的引用,所以调用位置是foo(),而不是p.foo()或o.foo()
  • 箭头函数:不使用这四个this规则,根据词法作用域来决定this。
function foo() {
// 返回一个箭头函数
return (a) => {
// `this` here is lexically adopted from `foo()`
console.log( this.a );
};
} var obj1 = {
a: 2
}; var obj2 = {
a: 3
}; // foo()不是箭头函数,他的this被绑定到obj1
var bar = foo.call( obj1 ); // foo.call( obj1 )返回箭头函数,所以bar为箭头函数
bar.call( obj2 ); // 2! 箭头函数的this无法被修改,new也不行

如下为和箭头函数一样的模式:

function foo() {
var self = this; // lexical capture of `this`
setTimeout( function(){
console.log( self.a );
}, 100 );
} var obj = {
a: 2
}; foo.call( obj ); // 2

this绑定的趣题:

知乎链接-arguments对象调用

函数中的this的四种绑定形式

更多博客:https://github.com/Lmagic16/blog

原文地址:https://segmentfault.com/a/1190000016678888

JS中this的4种绑定规则的更多相关文章

  1. 深入理解this机制系列第一篇——this的4种绑定规则

    × 目录 [1]默认绑定 [2]隐式绑定 [3]隐式丢失[4]显式绑定[5]new绑定[6]严格模式 前面的话 如果要问javascript中哪两个知识点容易混淆,作用域查询和this机制绝对名列前茅 ...

  2. js中this的四种使用方法

    0x00:js中this的四种调用模式 1,方法调用模式 2,函数调用模式 3,构造器调用模式 4,apply.call.bind调用模式 0x01:第一种:方法调用模式 (也就是用.调用的)this ...

  3. this的四种绑定规则总结

    一.默认绑定 1.全局环境中,this默认绑定到window 2.函数独立调用时,this默认绑定到window console.log(this === window);//true functio ...

  4. 【温故知新】——原生js中常用的四种循环方式

    一.引言 本文主要是利用一个例子,讲一下原生js中常用的四种循环方式的使用与区别: 实现效果: 在网页中弹出框输入0   网页输出“欢迎下次光临” 在网页中弹出框输入1   网页输出“查询中……” 在 ...

  5. JS 中深拷贝的几种实现方法

    JS 中深拷贝的几种实现方法1.使用递归的方式实现深拷贝 //使用递归的方式实现数组.对象的深拷贝 function deepClone1(obj) { //判断拷贝的要进行深拷贝的是数组还是对象,是 ...

  6. JS中常见的几种报错类型

    1.SyntaxError(语法错误) 解析代码时发生的语法错误 var 1a; //Uncaught SyntaxError: Invalid or unexpected token 变量名错误 c ...

  7. 关于原生js中函数的三种角色和jQuery源码解析

    原生js中的函数有三种角色: 分两大种: 1.函数(最主要的角色)2.普通对象(辅助角色):函数也可以像对象一样设置属于本身的私有属性和方法,这些东西和实例或者私有变量没有关系两种角色直接没有必然的关 ...

  8. js中继承的几种用法总结(apply,call,prototype)

    一,js中对象继承 js中有三种继承方式 1.js原型(prototype)实现继承 <SPAN style="BACKGROUND-COLOR: #ffffff">& ...

  9. JS中常见的几种继承方法

    1.原型链继承 // 1.原型链继承 /* 缺点:所有属性被共享,而且不能传递参数 */ function Person(name,age){ this.name = name this.age = ...

随机推荐

  1. IDEA安装配置Thrift

    下载exe:http://archive.apache.org/dist/thrift/0.9.3/ 新建一个thrift目录放进来,并将名字改成thrift

  2. Word文档怎么从第二页加页码

    1.首先将光标放到首页的最后位置 2.“页面布局”—“分隔符”—“下一页” 3.“插入”—“页码”—选一种样式的页码 4.将光标定位到第二页的页脚处,“设计”—取消“链接到前一条页眉” 5.将第二页的 ...

  3. pycharm创建.py文件时,自动添加头文件注释

    File->settings->Editor->Code Templates->Python Script 添加以下代码: #!/usr/bin/env python # -* ...

  4. LeetCode 230. 二叉搜索树中第K小的元素(Kth Smallest Element in a BST)

    题目描述 给定一个二叉搜索树,编写一个函数 kthSmallest 来查找其中第 k 个最小的元素. 说明:你可以假设 k 总是有效的,1 ≤ k ≤ 二叉搜索树元素个数. 示例 1: 输入: roo ...

  5. 19个JavaScript简化编码小技巧

    这篇文章适合任何一位基于JavaScript开发的开发者.我写这篇文章主要涉及JavaScript中一些简写的代码,帮助大家更好理解一些JavaScript的基础.希望这些代码能从不同的角度帮助你更好 ...

  6. react 的基础知识

    react 是目前最流行的框架: 其中是采用 mvvm 的思想,让我们把所有的只关注视图层和逻辑层, 从而可以更好的书写代码: 在 react 中我们的 html 结构也是通过 js 来实现的,而且在 ...

  7. DP&图论 DAY 6 下午 考试

    DP&图论  DAY 6  下午  考试 样例输入 样例输出 题解 >50 pt      dij 跑暴力 (Floyd太慢了QWQ    O(n^3)) 枚举每个点作为起点,dijks ...

  8. 理解MVC/MVP/MVVM的区别

    转载至[http://www.ruanyifeng.com/blog/2015/02/mvcmvp_mvvm.html] MVC 所有的通信都是单向的. M(Model)V(View)C(Contro ...

  9. Collapse 折叠面板

    通过折叠面板收纳内容区域 基础用法 可同时展开多个面板,面板之间不影响 <el-collapse v-model="activeNames" @change="ha ...

  10. phpstrom--------config php interpreter

    phpstrom是一款比较好用的php代码编辑器,使用phpstrom进行代码编辑时我可能会需要看一下在网页上的实际效果,但是PHPstrom本身只是一款编辑器,不具备运行功能,我们需要自己安装一个服 ...