this指向最后调用该函数的对象

		// 示例一:
var name = "windowsName";
function a() {
var name = "Cherry";
console.log(this) // window
console.log(this.name); // windowsName
console.log("inner:" + this); // inner: Window
}
a(); // 相当于 window.a()
console.log("outer:" + this) // outer:Window // 示例二:
var name = "windowsName";
var a = {
name: "Cherry",
fn : function () {
console.log(this) // a
console.log(this.name); // Cherry
}
}
window.a.fn(); // 相当于 a.fn() // 示例三:
var name = "windowsName";
var a = {
name: "Cherry",
fn : function () {
console.log(this) // window
console.log(this.name); // windowsName
}
}
var f = a.fn;
f(); // 相当于 window.f() // 示例四:
var name = "windowsName";
function fn() {
var name = 'Cherry';
console.log(this) // window
console.log(this.name); // windowsName
innerFunction(); }
function innerFunction () {
console.log(this.name); // windowsName
}
fn() // 相当于 window.fn()

匿名函数的 this 永远指向 window

注意,这里我们没有使用严格模式,如果使用严格模式的话,全局对象就是 undefined,会报错 Uncaught TypeError: Cannot read property 'name' of undefined。

	var name = "windowsName";
var a = {
name : "Cherry",
func1: function () {
console.log(this.name)
},
func2: function () {
console.log(this) // a
setTimeout(function () {// 匿名函数的 this 永远指向 window
console.log(this) //window
this.func1()
},100);
}
};
a.func2() // this.func1 is not a function

改变 this 的指向的几种方法:

  1. 使用 ES6 的箭头函数
  2. 在函数内部使用 _this = this
  3. 使用 apply、call、bind
  4. new 实例化一个对象

1.箭头函数的 this 始终指向函数定义时的 this,而非执行时

箭头函数中没有 this 绑定,必须通过查找作用域链来决定其值,如果箭头函数被非箭头函数包含,则 this 绑定的是最近一层非箭头函数的 this,否则,this 为 undefined

	var name = "windowsName";
var a = {
name : "Cherry",
func1: function () {
console.log(this.name)
},
func2: function () {
setTimeout( () => {
console.log(this) // a,  不是window
this.func1()
},100);
}
};
a.func2() // Cherry

2.在函数内部使用 _this = this。先将调用这个函数的对象保存在变量 _this 中,然后在函数中都使用这个 _this,这样 _this 就不会改变

var name = "windowsName";
var a = {
name : "Cherry",
func1: function () {
console.log(this.name)
},
func2: function () {
var _this = this;
setTimeout( function() {
_this.func1()
},100);
}
};
a.func2() // Cherry

3.使用 apply、call、bind 函数也是可以改变 this 的指向。

3.1 apply

语法:fun.apply(thisArg[, argsArray])

含义:该方法调用一个函数, 使用该函数(fun)的方法,同时改变函数中this的指向为thisArg。

参数:具有一个指定的this值,以及作为一个数组(或类似数组的对象)提供的参数

thisArg:在 fun 函数运行时指定的 this 值。注意:指定的 this 值并不一定是该函数执行时真正的 this 值,如果这个函数处于非严格模式下,则指定为 null 或 undefined 时会自动指向全局对象(浏览器中就是window对象),同时值为原始值(数字,字符串,布尔值)的 this 会指向该原始值的自动包装对象。

argsArray:一个数组或者类数组对象,其中的数组元素将作为单独的参数传给 fun 函数。如果该参数的值为null 或 undefined,则表示不需要传入任何参数。从ECMAScript 5 开始可以使用类数组对象。

var a = {
name : "Cherry",
func1: function () {
console.log(this.name)
},
func2: function () {
setTimeout( function () {
this.func1()
}.apply(a),100); // 此处省略第二个参数
}
};
a.func2() // Cherry

3.2 call

语法:fun.call(thisArg[, arg1, arg2,....])

注:与apply用法类似,不同之处:第二个参数为参数列表,使用逗号分割

var a = {
name : "Cherry",
func1: function () {
console.log(this.name)
},
func2: function () {
setTimeout( function () {
this.func1()
}.call(a),100); // 此处省略第二个参数
}
};
a.func2() // Cherry

3.3 bind

 语法:fun.bind(thisArg[, arg1, arg2, ...])()

含义:bind()方法创建一个新的函数, 当被调用时,将其this关键字设置为提供的值,在调用新函数时,在任何提供之前提供一个给定的参数序列

// 示例一:
var a = {
name : "Cherry",
func1: function () {
console.log(this.name)
},
func2: function () {
setTimeout( function () {
this.func1()
}.bind(a)(),100);
}
};
a.func2() // Cherry // 示例二:
var a ={
name : "Cherry",
fn : function (a,b) {
console.log( a + b)
}
}
var b = a.fn;
b.bind(a,1,2)() // 3

对于不支持 bind 的浏览器,兼容性写法:

		Function.prototype.bind = Function.prototype.bind || function(context) {
var self = this;
// console.log(this, context)
return function() {
console.log(arguments); // console [3,4] if ie<6-8>
return self.apply(context, arguments); }
} // 调用
var obj = {
a: 1,
b: 2,
getCount: function(c, d) {
return this.a + this.b + c + d;
}
};
window.a = window.b = 0;
var func = obj.getCount.bind(obj)(3, 4);
var apply = obj.getCount.apply(obj, [3, 4]);
var call = obj.getCount.call(obj, 3, 4); console.log(func, apply, call) // 10 // 或者:
Function.prototype.bind = Function.prototype.bind || function( context ){
var self = this; // 保存原函数 - 调用者
   context = [].shift.call( arguments ), // 需要绑定的 this 上下文
   args = [].slice.call( arguments ); 剩余的参数转化为数组
return function(){ // 返回一个新的函数
return self.apply( context, [].concat.call( args, [].slice.call( arguments ) ) );
// 执行新的函数的时候,会把之前传入context当作新函数体内的this
// 并且组合两次分别传入的参数,作为新的函数的参数
}
};
// 调用
var obj = {
name: 'sven'
};
var func = function( a, b, c, d ){
alert ( this.name ); // sven
alert ( [ a, b, c, d ] ) // [ 1, 2, 3, 4 ]
}.bind( obj, 1, 2 ); // obj ==> context func( 3, 4 );

4.构造函数Sum,如果我们直接调用这个构造函数Sum(),那么这个this代表window对象;但是我们对它进行实例化var obj = new Sum(),这样this.a上的this代表当前对象obj;

function Sum(a, b){
console.log(this); // 1=>window; 2=>实例化对象obj
this.a = a;
this.b = b;
this.add = function(){
console.log(this) // obj.add()=>实例化对象obj
return this.a+this.b;
}
} // 1.直接调用:
Sum(2, 3);
console.log(a, b); // 2, 3
// 2.实例化:
var obj = new Sum(2, 3);
var num = obj.add();
console.log(num); // 5

new 的过程:

  1. 创建一个空对象 obj;
  2. 将新创建的空对象的隐式原型指向其构造函数的显示原型。
  3. 使用 call 改变 this 的指向
  4. 如果无返回值或者返回一个非对象值,则将 obj 返回作为新对象;如果返回值是一个新对象的话,那么直接直接返回该对象。

    注:构造器显式地返回了一个 object 类型的对象,那么此次运算结果最终会返回这个对象;

    构造器不显式地返回任何数据,或者是返回一个非对象类型的数据才会返回这个构造器实例
function Person(name,age){
this.name = name
this.age = age
return [1,2,3]
} var p = new Person('taurus_wood', 20) // [1, 2, 3] // 数组的类型是对象 function Person2(name,age){
this.name = name
this.age = age
return 1
} var p2 = new Person2('taurus_wood', 20) // {name:'taurus_wood', age: 20}

代码显示实例化过程

var a = new myFunction("Li","Cherry");
// 伪代码表示:
new myFunction{
var obj = {};
obj.__proto__ = myFunction.prototype; //建立了obj对象的原型链:obj->Animal.prototype->Object.prototype->null
var result = myFunction.call(obj,"Li","Cherry");
return typeof result === 'obj'? result : obj;
} // 或者:
Function.method('new', function() {
// this指向Function对象
// that是构造器对象
var that = Object.create(this.prototype);
// other是调用构造器之后生成的对象,跟这行代码一个意思: var other = new Person()
var other = this.apply(that, arguments);
// 如果它返回的不一个对象,就返回该新对象
return (typeof other === 'object' && other) || that;
})

函数调用的方法:

  1. 作为普通函数调用
  2. 函数作为方法调用(作为对象的方法调用)
  3. 使用构造函数调用函数(作为构造器调用)
  4. 作为函数方法调用函数(call、apply)

1.单纯的函数调用

// 如上例:
var name = "windowsName";
function a() {
var name = "Cherry";
console.log(this.name); // windowsName
console.log("inner:" + this); // inner: Window
}
a(); // 单纯的函数调用
console.log("outer:" + this) // outer: Window

2.函数作为对象的方法调用‘

// 如上例:
var a = {
name : "Cherry",
func1: function () {
console.log(this.name)
},
func2: function () {
setTimeout( function () {
this.func1()
}.bind(a)(),100);
}
};
a.func2() // Cherry 作为a对象的方法调用

3.使用构造函数调用函数

如上例

4.作为函数方法调用函数(call、apply)

在 JavaScript 中, 函数是对象。

JavaScript 函数有它的属性和方法。

call() 和 apply() 是预定义的函数方法。 两个方法可用于调用函数,两个方法的第一个参数必须是对象本身

JS - this 总结的更多相关文章

  1. Vue.js 和 MVVM 小细节

    MVVM 是Model-View-ViewModel 的缩写,它是一种基于前端开发的架构模式,其核心是提供对View 和 ViewModel 的双向数据绑定,这使得ViewModel 的状态改变可以自 ...

  2. js学习笔记:操作iframe

    iframe可以说是比较老得话题了,而且网上也基本上在说少用iframe,其原因大致为:堵塞页面加载.安全问题.兼容性问题.搜索引擎抓取不到等等,不过相对于这些缺点,iframe的优点更牛,跨域请求. ...

  3. js学习笔记:webpack基础入门(一)

    之前听说过webpack,今天想正式的接触一下,先跟着webpack的官方用户指南走: 在这里有: 如何安装webpack 如何使用webpack 如何使用loader 如何使用webpack的开发者 ...

  4. JS调用Android、Ios原生控件

    在上一篇博客中已经和大家聊了,关于JS与Android.Ios原生控件之间相互通信的详细代码实现,今天我们一起聊一下JS调用Android.Ios通信的相同点和不同点,以便帮助我们在进行混合式开发时, ...

  5. jquery和Js的区别和基础操作

    jqery的语法和js的语法一样,算是把js升级了一下,这两种语法可以一起使用,只不过是用jqery更加方便 一个页面想要使用jqery的话,先要引入一下jqery包,jqery包从网上下一个就可以, ...

  6. 利用snowfall.jquery.js实现爱心满屏飞

    小颖在上一篇一步一步教你用CSS画爱心中已经分享一种画爱心的方法,这次再分享一种方法用css画爱心,并利用snowfall.jquery.js实现爱心满屏飞的效果. 第一步: 利用伪元素before和 ...

  7. node.js学习(三)简单的node程序&&模块简单使用&&commonJS规范&&深入理解模块原理

    一.一个简单的node程序 1.新建一个txt文件 2.修改后缀 修改之后会弹出这个,点击"是" 3.运行test.js 源文件 使用node.js运行之后的. 如果该路径下没有该 ...

  8. JS正则表达式常用总结

    正则表达式的创建 JS正则表达式的创建有两种方式: new RegExp() 和 直接字面量. //使用RegExp对象创建 var regObj = new RegExp("(^\\s+) ...

  9. 干货分享:让你分分钟学会 JS 闭包

    闭包,是 Javascript 比较重要的一个概念,对于初学者来讲,闭包是一个特别抽象的概念,特别是ECMA规范给的定义,如果没有实战经验,很难从定义去理解它.因此,本文不会对闭包的概念进行大篇幅描述 ...

  10. JS核心系列:理解 new 的运行机制

    和其他高级语言一样 javascript 中也有 new 运算符,我们知道 new 运算符是用来实例化一个类,从而在内存中分配一个实例对象. 但在 javascript 中,万物皆对象,为什么还要通过 ...

随机推荐

  1. 11G 新特性之 密码延迟认证

    11G 新特性之 密码延迟认证 11G 新特性之 密码延迟认证 Table of Contents 1. 特性简述 2. 特性潜在引发问题 3. 关闭特性 1 特性简述 为了防止用户密码的暴力破解,从 ...

  2. react目录结构、demo实例详解、属性数据绑定方式

    1.目录结构 2.demo实例详解 a)创建Home.js import React, { Component } from 'react'; //创建一个组件必须要集成Component组件,且组件 ...

  3. Apache Kafka系列(六)客制化Serializer和Deserializer

    已经迁移,请移步:http://www.itrensheng.com/archives/apache-kafka-repartition

  4. 十八:jinja2之include标签

    用于将页面的某一块地方抽取出来,要嵌入内容的时候使用,继承的概念 把具体内容分别放到其他地方同一管理,要用的时候使用include继承 使用include的时候可以直接使用接收的数据

  5. Linux下搭建Git服务器

    1.安装Git 见 Jenkins持续集成环境部署 第四节 2.创建Git用户和用户组 groupadd git useradd git -g git 3.创建证书切换到git用户创建证书 su gi ...

  6. 如何利用Prometheus监控你的应用

    Prometheus作为一套完整的开源监控接近方案,因为其诸多强大的特性以及生态的开放性,俨然已经成为了监控领域的事实标准并在全球范围内得到了广泛的部署应用.那么应该如何利用Prometheus对我们 ...

  7. Swift 发送邮件和附件

    public function send($filename, array $render = [],$subject = '审核通知') { // Create the Transport $tra ...

  8. python-爬取糗事百科热图

    此次运用requests和beautifulSoup爬取糗事百科热图,常用的网络库有:urllib,urllib3,requests,选取其中之一就行了:HTML/XML解析器有:lxml,Beaut ...

  9. Android 透明主题

    转至:https://blog.csdn.net/zhangwenchaochao/article/details/78654128 Activity采用透明主题有两种方式: 重要的内容说三遍: 采用 ...

  10. 最常见的Python异常报错Error

    内置异常 官网链接:https://docs.python.org/zh-cn/3/library/exceptions.html 在 Python 中,所有异常必须为一个派生自 BaseExcept ...