通过调用标识符确定this
一. 纲
this的性质
作用:表示函数执行时的环境
值:一个对象
特点:动态性
确定this的难度
- JS语言的动态性:
函数的this在执行时才能确定
- 函数为一级公民
可作实参、返回值、数据赋值进行传递
解决方法
- 书写函数时,要预想该函数会被如何调用
- 以调用标识符确定this值
- 以变量代替this、使用绑定
函数的调用标识符
1. 函数是复杂数据类型
2. 变量可获取函数值--引用地址
3. 函数调用时,该调用名字是该函数此次调用时的标识符
以标识符确定this值
唯一能确定this的途径:函数的调用标识符
- 未使用绑定字: 函数的调用标识符是否属于一个对象的成员
是:this就指向该对象
否:宽松模式是window;严格模式是未定义
- 使用绑定字 (执行时) : 把this绑定到指定对象上
开启严格模式
在函数体内使用严格关键词
class方法与模块方法自动运行在严格模式中
不包括方法简写
例
// 伪代码
//以下fn均表示一個宽松环境的函数, obj表示一个对象
fn(); // window
obj1.fn(); // obj1
obj2.obj3.fn() // obj3
fn.call(obj4) // obj4
new fn() // 实例
函数
fn
执行时,其调用标识符均是fn
每个标识符
fn
所属的对象都不同,其this
就不同
fn()
: 调用标识符fn不属于任何对象:this
是window
obj1.fn()
: 调用标识符fn属於对象obj1
的成员:
this
是obj1
obj2.obj3.fn()
: 调用标识符fn属於对象obj2
的成员:
this
是obj3
未使用绑定时,函数的调用标识符属于对象的一个成员时,其
this
就是该对象
二. 未使用绑定字
确定 this 值 :
只要查看该函数调用时的标识符
该标识符决定当前函数执行时的this值
1 函数自我调用
调用标识符是该函数本身的标识符
该标识符不属于任何对象的属性
此时this指向
宽松模式:全局对象
window、global(node环境)·
严格模式: this为未定义
立即执行函数也是函数自我调用,
其调用标识符是
anonymou
其this,永远是window/未定义
2 一个函数的多种调用形式
函数的引用地址被赋值给一个对象的属性
函数调用时: 若调用标识符属于对象的一个成员
this就指向该对象
例:
1.函数作为数据进行赋值
// 伪代码: fn表示宽松模式的下的函数
const A = {
fn: fn
};
const B = {
b1: A.fn,
b2: A
};
var c = objA.fn;
fn(); // window
A.fn(); // A
B.b1() // B
B.b2.fn(); // A
c(); // window
函数的调用属于地址引用,可赋值给不同变量
调用函数时的标识符 ,决定了此函数执行时的其内部的this值
分析表
调用形式 调用标识符 标识符所属对象 this fn0()
fn0
无 window
A.fn()
fn()
A
A
B.b1()
b1()
B
B
B.b2.fn()
fn()
b2
,b2
的值是A
A
c()
c()
无 window
2. 函数作为数据进行赋值
var obj = {
y: function fn1(x) {
console.log(this);
while (x) {
fn1(x - 1);
break;
}
},
z: function fn2(x) {
console.log(this);
while (x) {
obj.z(x - 1);
break;
}
},
};
obj.y(1); //obj 、 window"
obj.z(1); //obj 、window"
调用形式 | 调用标识符 | 标识符所属对象 | this |
---|---|---|---|
obj.y(1) |
y() |
obj |
obj |
fn1(x - 1) |
fn1() |
无 | window |
obj.z(1) |
z() |
obj |
obj |
obj.z(x-1) |
z() |
obj |
obj |
3.函数作为参数传入
1.参数传递是一种隐式赋值
2.传参:类似于:
argument = A.fn ;
参数cb获取了函数fn的引用
// 伪代码: fn表示宽松模式的下的函数
let A = {
fn,
fn2: (function () {
console.log(this);
})()
},
B = {};
function b(cb) {
console.log(this); // window
B.fn = cb;
cb(); // window
B.fn(); // B
}
A.fn(); // A
b(fn);
调用形式 | 调用标识符 | 标识符所属对象 | this |
---|---|---|---|
A.fn() |
fn() |
A |
A |
b(fn) |
b() |
无 | window |
cb() |
cb() |
无 | window |
B.fn() |
fn() |
B |
B |
3.参数所属对象要看情况
1.如在浏览器方法中的定时器
其回调函数参数是属于window
对象的成员
回调函数this
是window
对象
var obj = {
fo: function fo() {
'use strict'
console.log(this);
}
};
obj.fo(); // obj
setTimeout(obj.fo, 100); // window
2.如事件监听
其回调参数所属对象是元素本身
其他
getter 与 setter函数同理
实例中继承的方法同理
class语法的super调用的方法中的this
1.super是静态的,指向当前类的基类
2.但是super调用的方法时,进行了绑定
把this绑定到使用
super·
的类例
function fn() { };
let obj = {};
Function.prototype.f1 = function () {
console.log(this);
return function f2() {
console.log(this);
}
}
Function.prototype.x(); // Function.prototype
Function.x() // Function
obj.f = fn.f1(); //fn
obj.f(); // obj
fn.f1()(); // window
let f2 = fn.f1();
f2(); // window
调用形式 | 调用标识符 | 标识符所属对象 | this |
---|---|---|---|
Fn.proto.x() |
x() |
Fn.proto |
Fn.proto |
fn.f1() |
f1() |
fn |
fn |
f2的this,同样只能在其被调用时决定
不在于它被赋值给谁
调用形式 | 调用标识符 | 标识符所属对象 | this |
---|---|---|---|
obj.f() |
f() |
obj |
obj |
fn.f1()() |
匿名函数() |
无 | window |
f2() |
f2() |
无 | window |
3.事件处理
内联事件:
事件触发函数执行,该函数的调用标识符决定
this
传入this实参
内联事件中的this实参是该事件的元素本身
<button onclick="fn(this)">AMTF</button>
<button onclick="obj.fn(this)">JLSJ</button>
function fn(v) {
console.log(this, v); // window、 button-AMTF
}
let obj = { fn }; // obj、 button-JLSJ
document.getElementsByTagName("button")[0]
.onclick = function () {
console.log(this); // button-AMTF
}
外联事件与事件监听
相当于把函数赋值给该元素的某个属性
触发该函数执行时,调用者是这个元素
this指向调用该函数的元素--
e.currentTarget
btn.addEventListener('click', fn);
function fn(e) {
if (e.target == this) {
// 只在元素本身被觸發時執行
// doSomething...
console.log(e.target, this);
}
}
IE的
attachEvent
的回调函数的this是window
修改this:把函数赋值给对象,再执行这个对象的方法
function attachEvent (elm, event, cb) {
elm.attachEvent(("on" + event), function () {
elm.cb = cb;
elm.cb(window.event);
delete elm.cb;
});
}
// 或者使用绑定
function attachEvent(elm, event, cb) {
elm.attachEvent(("on" + event), cb.bing(elm, window.event));
}
三.使用绑定
确定this值: 绑定关键字指定对象即为this值
同样只能在函数执行时确定
四个绑定关键词: new、call、apply、bing
1.call
与apply
直接指定一个对象作为 this 的值
可使用
apply
来展开一个数组ES5:可传入类数组对象
2. 硬绑定bing
- 原理
function fakeBind(fn, obj) {
return function () {
return fn.apply(obj, arguments);
};
}
- 返回一个新函数
- 新函数与原函数的函数体相同
- 但其this被绑定到指定的对象
在使用了
bing
的函数是尚未执行的,其
this
是不确定的: 只能在执行时确定使用new调用:为
new
创建的对象没使用new调用:为
bing
绑定的对象只会被
new
改变
3. 构造器的new
绑定
一定會用新创建的实例对象替换原來的this
无论该函数是否已被其他绑定字绑定过
4. 自带绑定
JS、库、宿主环境的内置函数,提供一个参数
用于绑定 this值
例:数组的forEach
的参数2
5. 绑定到空/原始值
- 不错的空对象:
Object.create(null);
- 绑定到
null / undefined
- 宽松模式:绑定到全局对象
- 严格模式:
null / undefined
- 绑定到原始值(字符串类型、布尔类型或者数字类型)会封装成对应的对象
new String、new Boolean、new Number
let o = {
a: function () {
console.log(this);
}
};
o.a(); // o
o.a.call(null); // window
o.a.call(1); // Number(1)
四. 箭头函数
确定this值 :
箭头函数没有this值
通过引用其上属函数的this值
若该箭头函数没有上属函数,则其this值为未定义
无法使用绑定关键词修改箭头函数的this值
因为他没有this值
唯一修改this值:
给他套上普通函数,再修改该普通函数的this
function x() {
return (a) => {
//this 取自 x()
console.log(this.a);
};
}
var oA = { a: 2 };
var oB = { a: 3 };
var y = x.call(oA);
y.call(oB); // 2
由于x
的 this
绑定到 oA
箭头函数的this
指向 oA
: y的this
也指向 oA
- 确定箭头函数的
this
:- 没有所属函数时,只能是未定义
- 有所属函数,取决于所属函数执行时的
this
五.例
1.闭包函数
在一个函数中返回另一个函数
function f1() {
console.log(this);
return function f2() {
console.log(this);
}
}
f1()();
函数f1返回的函数的this值,由调用时决定
f1( )( )·
:两次this
都是指向了window
f2执行时,如立即执行函数
const obj = {};
obj.y = f1();
obj.y();
let fn = fn1();
fn();
把f1的返回值,赋值给一个变量
f2的this:调用时决定--fn()、obj.y()
调用标识符所属的对象不相同
其 f2的this也不相同
2. 反柯里化:
反柯里化:让对象去借用一个原本不属于它的方法
普通函數寫法
Function.prototype.uncurrying = function () {
var self = this;
return function () {
let thisArg = [].shift.call(arguments);
return self.apply(thisArg, arguments);
}
}
箭頭函數寫法
Function.prototype.uncurrying = function () {
return (...args) => this.call( ...args)
}
箭头函数的this是取值其外层函数的this,
外层函数
uncurrying
的this值,决定于调用时的
let push = Array.prototype.push.uncurrying();
- 此时
uncurrying
的调用者是push
函数
则此时的this
是指向push
函数
3. bing的实现
- 工具函数
objectCreate = Object.create || function (proto) {
var F = function () { };
F.prototype = proto;
return new F();
}
let slice = Array.prototype.slice.uncurrying();
let concat = Array.prototype.concat.uncurrying();
- 实现逻辑
Function.prototype.bind = function (thisArg) {
if (typeof this !== "function") {
throw new TypeError("被绑定的不是函數");
}
var self = this;
var baseArgs = slice(arguments, 1);
var bind = function () {
return self.apply(
this instanceof self ? this : thisArg,
concat(baseArgs, slice(arguments))
);
}
bind.prototype = objectCreate(self.prototype);
return bing;
};
4. 自定义默认绑定对象
实现:修改例3的bind
函數的返回值的apply
的参数1
默认绑定--只当this
指向全局对象或者undefined
时
把this绑定到默认的对象
return self.apply(
((!this || this === (window || global)) ?
thisArg : this
),
concat(baseArg, slice(arguments))
);
对apply
参数1的定制,可实现多种绑定
5. 多重綁定
const obj1 = {
name: "obj1"
};
const obj2 = {
name: "obj2"
};
function f1() {
console.log(this);
}
function f2() {
f1.call(this);
}
const f3 = () => f2.call(this);
f2.call(obj1); // obj1
f3.call(obj2); // window
f2 .call(obj1 )
:
f2
的this被綁到了obj1
,所以f1.call(this)
的this是obj1
;使得f1
的this為obj1
f3.call(obj2)
:
f3
是箭頭函數--this綁定無效,但其沒有所屬的函數,所以f2.call(this)
的this值為未定義
而在寬鬆模式下的綁定到未定義會改爲绑定到全局对象
6. 立即执行函数
let o = {
a: (function () {
console.log(this); // window
return function () {
console.log(this); // 看情况:调用标识符决定
}
})()
};
(function (fn) {
console.log(this); // o
fn.call(this); // window
(() => console.log(this))(); // o
}).call(o, () => console.log(this));
立即执行函数的this
- 未使用绑定时,永远是window/未定义
- 执行时使用绑定,是被绑定的对象
- 箭头函数,其this如同继承的属性,取自其所属的函数
7.函数式编程相关
在函数中返回一个对象,进行链式调用
let x = function () {
let obj = { y, z }
return obj; // 等效于 return { y, z };
function y() { console.log(this); return this }
function z() { console.log(this); return this }
};
x().y().z();
因为返回的是对象
x() === obj
,而x().y() === obj.y()
x().y() === obj
,而x().y().z()=== obj.z()
通过调用标识符确定this的更多相关文章
- JSON-RPC轻量级远程调用协议介绍及使用
这个项目能够帮助开发人员利用Java编程语言轻松实现JSON-RPC远程调用.jsonrpc4j使用Jackson类库实现Java对象与JSON对象之间的相互转换.jsonrpc4j包含一个JSON- ...
- JSON-RPC远程调用协议
1. JSON-RPC简介 2. 请求 3. 响应 4. 错误 4.1. 错误对象 4.2. 错误码 5. 批量调用 6. 示例 6.1. 列表形式参数 6.2. key-value形式参数 6.3. ...
- js 闭包 理解
1.什么是闭包 定义:是指有权访问另一个函数作用域中的变量的函数 创建闭包:在一个函数内部创建另一个函数 基本特点 在返回的匿名函数中 可以调用外部函数的变量 如下例中所示 内部函数(匿名函数) 可以 ...
- 关于C语言的一些trick
很多东西已经记不起来了,想到一点写一点,碰到一点写一点,慢慢累积. 关于# #在宏定义中用于替换传入变量的字符,例如: #define whole_operation(n) do { printf( ...
- Atitit.js javascript的rpc框架选型
Atitit.js javascript的rpc框架选型 1. Dwr1 2. 使用AJAXRPC1 2.2. 数据类型映射表1 3. json-rpc轻量级远程调用协议介绍及使用2 3.1. 2.3 ...
- php static延迟静态绑定
如果你是一个懒惰的程序员,你看到以下代码可能会恼火 abstract class U{ } class u1 extends U{ public static function create(){ r ...
- angularjs入门学习【指令篇】
一.首先我们来了解下指令API 属性 含义 restrict 申明标识符在模版中作为元素,属性,类,凝视或组合,怎样使用 priority 设置模版中相对于其它标识符的运行顺序 Template 指定 ...
- [机翻] WIRER ON THE WIRE - SIGNALR协议的非正式描述
原文 原文很简单,以下为机翻 WIRER ON THE WIRE - SIGNALR协议的非正式描述 我已经看到询问有关SignalR协议的描述的问题出现了很多.哎呀,当我开始关注SignalR时,我 ...
- php分享二十二:php面向对象
1:static访问符 在类中使用static有两种主要用途.定义静态成员和定义静态方法.静态成员只保留一个变量的值,这个值对所有实例都是有效的 类的方法是static的,他所访问的属性也必须是sta ...
随机推荐
- C#LeetCode刷题之#840-矩阵中的幻方(Magic Squares In Grid)
问题 该文章的最新版本已迁移至个人博客[比特飞],单击链接 https://www.byteflying.com/archives/3752 访问. 3 x 3 的幻方是一个填充有从 1 到 9 的不 ...
- JavaScript正则、错误处理、操作表单
一.正则表达式:用单个字符串描述或者匹配符合特定语句规则的字符串 一些字符序列组合在一起,可以简单也可以复杂模式的,可以去搜索,可以去替换 二.语法: /表达式/修饰符(可选) var para=/i ...
- win10中搭建Linux子系统
win10自带的Linux子系统,简称WSL(Windows Subsystem for Linux).优点是打通了Linux系统和windows系统,改变了传统虚拟机/双系统造成的两个系统相互隔绝的 ...
- 常用sql语句整理
1.开/关 外键约束 -- 关 SET FOREIGN_KEY_CHECKS = 0; -- 开 SET FOREIGN_KEY_CHECKS = 1; 2.查看表的容量大小 use informat ...
- 第6篇 Scrum 冲刺博客
1.站立会议 照骗 进度 成员 昨日完成任务 今日计划任务 遇到的困难 钟智锋 重构游戏逻辑代码 改写部分客户端代码,制作单机版 庄诗楷 进行了相关的装饰改进 与其他部分合成完成游戏 合成遇到bug, ...
- 更换git远程仓库地址
通过命令直接修改远程仓库地址 git remote 查看所有远程仓库 git remote xxx 查看指定远程仓库地址 git remote set-url origin 你新的远程仓库地址 先删除 ...
- Java GUI 图书管理系统
01 概述 一款功能强大的图书馆管理系统,功能齐全,小白/大学生项目实训,学习的不二之选. 02 技术 此系统使用 java awt 实现.java.awt是一个软件包,包含用于创建用户界面和绘制图形 ...
- java项目的心得,java项目的代码层次的架构划分
java项目使用的架构是ssm(Spring+SpringMVC+MyBatis). 一.后台代码一般分三层,Controller,Service,Dao. 1.Controller层是对前端或者接口 ...
- 区块链入门到实战(6)之区块链 – 哈希(Hash)
密码学中,最重要的函数之一是哈希函数.哈希函数将任意大小的数据(内容)映射到固定大小的数据(哈希值). 哈希函数是单向的,从内容生成哈希值很容易,但从哈希值映射到内容很难. 比特币使用SHA-256哈 ...
- C# DataTable查询示例
代码 public void Test() { #region 初始化数据 /* 数据 张三 语文 34.00 张三 数学 58.00 张三 英语 61.00 李四 语文 45.00 李四 数学 87 ...