【笔记】探索js 的this 对象 (第二部分)

了解this 对象之后 我们明白了this 对象就是指向调用函数的作用域
那么接下来我们便要清除函数究竟在哪个作用域调用
找到调用的作用域首先要了解一下几点:

1、调用栈: 调用栈就是一系列的函数,表明当前函数是由哪些上层函数调用的包括它自身,我们关心的调用位置就在当前正在执行的函数的前一个调用中。

function baz(){
    //调用栈:baz 函数的内部

    console.log("baz 函数内部");
    bar();
}

function bar(){
    //调用栈分别是baz -> bar
    //调用位置为 baz 因此bar 的this指针指向 baz

    console.log("bar 函数内部");
    foo();
}

function foo(){
    //调用栈分别为 baz -> bar -> foo
    //调用位置是bar 内部 因此 foo的 this 指针指向了 bar

    console.log("foo 函数的内部");
}

baz()//baz的调用位置是 全局作用域

这段代码的意思是,函数再哪个区域被调用 那个区域就是它的执行环境

找到了调用位置就要理解一下函数对 this对象的绑定了
一般分为一下4种:

1、默认绑定

指函数在调用的过程中没有任何干涉调用位置的代码 浏览器引擎根据调用栈默认绑定

默认绑定,函数的this 对象会指向了window 对象 而在严格模式下函数访问this 会显示undefined

例子:

function foo(){
    console.log(this.a);
}
var a = "i‘m window";
foo();//输出2 因为全局变量也是window对象的属性

2、隐式绑定

函数没有调用任何方法绑定 而是在调用时根据对象上下文绑定了this 的作用域

看一下下面的例子

function foo(){
    console.log(this.a);
}

var obj = {
    a: "i‘m obj",
    foo: foo //对象obj 中包含着 foo的引用
}

obj.foo();

//通过obj 调用 函数foo,所以foo的this 对象绑定在了 obj上
//严格来说 函数foo 不属于obj对象 但由于函数是通过obj 引用并调用的所以this 指向了obj

 

另外对象调用链中只有最靠近被调用函数那层会影响函数的调用位置

即:函数在某一个对象里面 通过那个对象调用函数 this永远指向那个对象

例如:

function bar(){
    console.log(this.a);
}

var obj2 = {
    a: "i‘m obj2",
    bar: bar,
}

var obj1 = {
    a: "i‘m obj1",
    obj2: obj2,
    bar: bar
}

obj1.obj2.bar();

这里的意思是:obj1 调用 obj2 然后obj2 再调用 bar这个函数引用

从逻辑上说 bar这个函数调用怎么也是属于 obj2 吧

另外dom 的事件绑定回调函数也会把this 绑定在执行事件的 dom元素对象上

小分支:

2.1、隐式丢失

隐式绑定的函数会丢失原来的this所引用的对象
丢失后的this 会引用到全局对象或 undefined

例1:
把函数的引用赋值给全局变量 会丢失原来的this 绑定

function foo(){
    console.log(this.a);
}

var obj = {
    a: "i‘m obj",
    foo: foo
}

var bar = obj.foo;

//把obj foo属性里面对 foo 函数的引用赋值给了全局变量bar

var a = "global window";
bar();

这里的函数 foo 的引用虽然是obj 里面的一个属性值,但是后面却把函数的引用赋值给了一个全局变量并且在全局环境执行,所以foo 的this 对象指向了window 对象

其实这里真正的误区是我们一直以为在对象字面量中属性值为函数就是函数this 绑定的区域,其实不然

回顾一下第一部分的话,函数在哪里调用,那里才是它this 对象绑定的环境

所以这次函数 foo的引用在(保存在了bar中)在全局调用所以this 指向了全局

例2:

把函数的引用当作参数传进另外一个函数被执行 会造成隐式丢失

function foo(){
    console.log(this.a);
}

function dofoo(fn){
    fn();
}

var obj = {
    a: "i‘m obj",
    foo: foo
}

var a = "global window";

dofoo(obj.foo);

这里 dofoo 的输出结果是  "global window"

同时,回调函数也会造成隐式丢失

setTimeout(obj.foo,1000);//"global window"

3、显式绑定

通过语言内置的方法 将函数硬性绑定在了某一对象上执行
例如通过 call(),apply(),bind() 方法
此时函数的this 对象绑定在了bind() 和 apply() 方法的参数上

例如:

function foo(){
    console.log(this.a);
}

var obj = {
    a: "i‘m obj",
}

// 把foo函数绑定在obj 上执行

foo.call(obj);//i‘m obj

3.1、硬绑定

通过提供的方法,将函数绑定在某一对象上执行
例:

function foo(){
    console.log(this.a);
}

var obj = {
    a: "i‘m obj",
}

setTimeout(function timer(){
    //回调函数通常会丢失this
    //在回调函数中使用硬性绑定就不会出现这个现状了

    foo.call(obj);//把foo 硬性绑定在obj 上执行

},1000);//i‘m obj

obj.call(window);//硬性绑定之后 无法再绑定其他对象

apply和call 方法能够执行这种硬性绑定

除了这两个 es5 语法还定义了新方法 bind()

例:

function foo(num){
    return this.a + num;
}

var obj = {
    a: 2
}

var bar = foo.bind(obj);//把foo 函数的引用绑定在了 obj上

var result = bar(3);

console.log(result);//5

new 绑定:

js 的new 关键字不等同于其他面向对象语言里的new
js 的new 关键字仅仅是调用它的目标函数而已
1、调用new 关键字会创建一个新对象
2、新对象会与函数的原型连接
3、将函数的this 绑定到了新对象上
4、如果函数没有返回指定的新对象 那么就会返回一个默认的对象

例:

function foo(){
    this.a = "who can take me go";
}

var bar = new foo();
console.log(bar.a);

上例中我们通过new 将foo函数实例化 并将this 指针指向了bar
于是bar 便拥有了函数中的 a属性

以上四种绑定的优先级

默认绑定最低
隐式绑定低于显示绑定
隐式绑定又低于 new绑定
而new 与显示绑定其实两个本身的并没有什么影响很难说明优先级

如下例:

function foo(arg1){
    this.a = arg1;
}

var obj = {};

var bar = foo.bind(obj);
// 将foo 函数的引用绑定在obj 上
// 然后将obj 上对函数foo 的引用传值给 bar

bar(2);
console.log(obj.a);

//现在将引用这 foo.bind(obj)的变量bar 实例化
var baz = new bar(5);
console.log(baz.a);//5
//此操作没有修改obj 的属性a 值,并且把新值添加到了新的对象上 baz

小结:

这部分内容主要讲述了函数的this绑定位置以及各种的绑定方式,有如下结论

1、当函数被new 实例化时,this 对象指向新返回的对象

2、当函数调用了 call(),apply()或者 bind(),this绑定在指定的对象

3、函数在某个对象字面量里面调用,this绑定在了这个对象字面量里面

4、以上都没有被操作,在非严格模式下函数的this 指向了window对象,严格模式下为undefined

时间: 2024-10-12 09:15:29

【笔记】探索js 的this 对象 (第二部分)的相关文章

JS查看Object对象的内容

以一个例子来说,下面是他的Object: JS: 如果想直接获取到total的值,那就先把获取到的Json先Eval(),然后json.total就能取到total的值了, 但是如果想取到rows里面的值呢,我们先得进去rows,那就应该是:json.rows,但是我们alert的时候发现,这个rows有三个参数,我们要取第一个的话,那就应该是json.rows[0],然后再取 里面的strUserName或者strUserPwd就应该是Json.rows[0].strUserName了. 假设

js面形对象(2)

1.?原型与in操作符     有两种方式使用in操作符:单独使用和在for-in循环中使用.在单独使用时,in操作符会在通过对象能够访问给定属性时,返回true,无论该属性是存在实例或者是存在于原型之中. 看看下面的代码: console.debug(p1.hasOwnProperty('name'));//false 实例中没有name属性 console.debug('name' in p1);//输出true 实例或者原型中有name属性 p1.name = 'Lebron'; cons

4月8日--课堂笔记--JS内置对象

JavaScript Day8 一.    JS内置对象 字符串String a) 属性length:字符数量,不管是ASCII还是Unicode,都算1个字符 b) 查询方法: i.           charAt:根据索引位置查找字符,可以用[索引]代替(除了旧版IE) ii.           charCodeAt:根据索引位置查找字符编码 iii.           indexOf:根据字符(串)查找首次出现位置,如果找不到则返回-1:不指定第二个起始位置时从头开始查找,如果指定则

读书笔记-你不知道的JS上-对象

好想要对象··· 函数的调用位置不同会造成this绑定对象不同.但是对象到底是什么,为什么要绑定他们呢?(可以可以,我也不太懂) 语法 对象声明有两个形式: 1.字面量 => var obj = { ... }; 2.构造形式 => var obj = new Object(); 两种形式生成的对象是一样的,唯一的区别是,在文字声明中可以添加多个键值对,构造形式只能逐个添加. 类型 JS中有六种主要类型:string.number.booleam.null.undefined.object.

5月15日上课笔记-js中 location对象的属性、document对象、js内置对象、Date事件对象、

location的属性: host: 返回当前主机名和端口号 定时函数: setTimeout( ) setInterval() 二.document对象 getElementById(); 根据ID值获取一个DOM对象 getElementsByName(); 根据name属性值获取多个Dom对象 getElementsByTagName(); 根据标签获取多个DOM对象 获取标签体内容 innerHTML 获取input的value值 value 获取下拉框选中的值 value this 代

20170907笔记:JS对象&jQuery对象转换

JS对象转到jQuery对象 // JS与jQuery对象互转 // JS获取对象 var obj = document.getElementById('id'); // 把JS对象转换到jQuery对象 var $obj = $(obj); jQuery对象转到JS对象 // JS与jQuery对象互转 // jQuery获取对象 var $obj = $('#id'); // jQuery对象转换到JS对象 var obj = $obj.get(0);

笔记-Node.js中的核心API之HTTP

最近正在学习Node,在图书馆借了基本关于Node的书,同时在网上查阅资料,颇有收获,但是整体感觉对Node的理解还是停留在一个很模棱两可的状态.比如Node中的模块,平时练习就接触到那么几个,其他的一些模块暂时只会在学习的时候接触到,不常用便就荒废了.正所谓好记心不如烂笔头,多做笔记还是更有利于理解和记忆.自己做的总结也方便回头复习,所以决定踏上漫长的修炼之旅-- Node提供了许多API,其中一些比较重要.这些核心的API是所有Node应用的支柱,你会不停的用到他们. HTTP服务器 Nod

Android深度探索HAL与驱动开发 第二章

Android深度探索HAL与驱动开发 第二章 搭建Android开发环境 读书笔记 一.Android底层开发需要的工具 1.JDK6或以上版本 2.Eclipse3.4或以上版本 3.ADT(用于开发Android的应用程序) 4.CDT(用于开发Android NDK程序) 5.Android SDK 6.Android NDK 7.交叉编译环境 8.Linux内核源代码 9.Android源代码 10.用于调试开发板的串口工具:minicom 二.安装JDK 下载JDK后在终端输入 #

JS内置对象-String对象、Date日期对象、Array数组对象、Math对象

一.JavaScript中的所有事物都是对象:字符串.数组.数值.函数... 1.每个对象带有属性和方法 JavaScript允许自定义对象 2.自定义对象 a.定义并创建对象实例 b.使用函数来定义对象,然后创建新的对象实例 二.JS内置对象-String 1.string对象 string对象用于处理已有的字符串 字符串可以使用单引号或者双引号 2.indexOf( )  在字符串中查找字符串,如果匹配成功返回首字母所在的位置,否则返回-1 3.match() 匹配成功,返回匹配成功的数组,