JavaScript内置一些方法的实现原理--new关键字,call/apply/bind方法--前戏
new关键字,call/apply/bind方法都和this的绑定有关,在学习之前,首先要理解this。
一起来学习一下this吧
首先。this是一个对象。
对象很好理解,引用类型值,可以实现如this.xxx、this.xxx()等等的操作。
验证:
接着,this只有当执行上下文创建执行时,才会被绑定。
在全局执行上下文中。(当浏览器碰到有JS代码要执行时,就会创建全局执行上下文,可以简单理解为打开网页就创建了)
this指向window对象
验证:
1 <script> 2 console.log(this === window);// true 3 </script>
函数内的this,只有当函数被调用时才会被绑定。
首先,一般的函数内部都有this这个特殊的对象。(箭头函数除外)
调用函数,引擎工作机制是创建一个函数执行上下文,进入函数执行上下文,执行这里的代码。(这里涉及到了执行栈、变量对象,作用域链等等)
不看上面那段话也很好理解,代码演示:
1 function fn() { 2 console.log(this); 3 }
以上代码声明了一个函数fn,fn函数做的事情就是在控制台输出this。
只有fn函数被调用时,我们才知道函数内部的this指向何处。
那this究竟指向何处呢(箭头函数单独讨论,以下函数都是指function关键字声明的函数)
第一种情况,当函数被普通调用时(如:fn()),this指向window对象。
代码演示:
1 fn(); // window
这种情况下,不管函数嵌套的有多深。this指向的都是window。验证:
1 function fn() { 2 console.log(this); 3 } 4 const obj = { 5 fn: function(fn) { 6 fn(); 7 } 8 } 9 obj.fn(fn);// window
第二种情况,当函数被new 关键字调用时(如:new Fn()),this指向new关键字新创建的对象。
代码演示:
1 function Fn() { 2 console.log(this); 3 window.myCheckThis = (obj) => { 4 console.log(this === obj); 5 } 6 } 7 const fn = new Fn(); 8 myCheckThis(fn);// true
以上代码通过new关键字调用Fn函数后,返回一个对象。保存在fn中。
在函数内部定义了一个全局的方法,检查函数内部的this指向。
这里利用了箭头函数没有this这个特性,以及闭包的特性。(在函数内部创建一个函数,那么这个函数可以访问外层函数作用域链上的变量)
通过作用域链访问到了外层函数的this。验证结果输出true。
也可以只通过闭包实现这种验证。代码演示:
1 function Fn() { 2 const self = this; 3 console.log(this); 4 window.myCheckThis = function(obj) { 5 console.log(self === obj); 6 } 7 } 8 const fn = new Fn(); 9 myCheckThis(fn);// true
以上代码,把外层函数的this保存在self中。内层函数通过作用域链就可以访问到这个这个变量。
注意,内层函数直接访问的this。是内层函数自身的this。
第三种情况,当函数被call--apply--bind方法调用时(如:fn.call(obj)),this指向这些方法绑定的对象。
在实际中,函数的this会指向这些方法的第一个参数。
当参数为null,undefined,window时,this指向window。
当参数是基本类型值时,指向该基本类型值的包装类型值。代码演示:
1 function fn() { 2 console.log(this); 3 } 4 fn.call();// window,apply、bind同理 5 fn.call('fn'); // String {"fn"},其他基本类型值、apply、bind同理
以上都不是重点,emmmm.....
当参数是引用类型值时,指向该对象。代码演示:
function fn() {console.log(this); } fn.call({name: 'xm'});// {name: "xm"},apply、bind同理。
需要注意的是:bind方法返回一个函数,apply方法第二个参数是数组或类数组对象。
代码演示:
function fn() {console.log(this); } const fn1 = fn.bind({name: 'xm'}); fn1();// {name: "xm"}
1 function add(a, b) { 2 console.log(a + b); 3 } 4 add.apply(null, [1, 2]);// 3
这三个方法还有很多别的用途,最常见的莫过于把类数组对象转换成数组对象了。
代码演示:
1 function fn(a, b, c, d) { 2 const args = Array.prototype.slice.call(arguments, 0); 3 return args.reduce((_a, _b) => { 4 return _a + _b; 5 }, 0); 6 } 7 console.log(fn(1, 2, 3, 4));// 10
以上函数内部属性arguments对象是类数组对象,.slice()方法是在Array原型对象创建的方法,
该方法内部this指向Array实例,通过call()方法,把this指向了arguments。
第二行代码可以简单理解为arguments.slice(0),返回一个新的数组对象。
然后在调用数组的reduce()方法。
第四种情况,当函数作为对象的方法调用时,this指向该对象。
这是很常见的一个情况,代码演示:
1 const obj = { 2 name: 'xm', 3 say: function () { 4 console.log(this.name); 5 } 6 } 7 obj.say();// xm
第五种情况,箭头函数的this。
箭头函数本身没有this。在函数内部访问this。会沿着函数的作用域链往外查找this。
代码演示:
1 const obj = { 2 say: () => { 3 console.log(this); 4 } 5 } 6 obj.say();// window
以上在obj对象上创建了say方法。由于采用了箭头函数的书写方式,函数内部没有this。
在内部访问this时,会沿着作用域链往外查找。往外就是全局执行上下文了,这里的this就是window。
在看下面的例子:
1 const obj = { 2 say: function() { 3 return () => { 4 console.log(this); 5 } 6 } 7 }; 8 const fn = obj.say(); 9 fn();// obj
以上代码调用obj.say()方法,返回匿名的箭头函数,保存在fn中,接着调用fn()函数。
由于箭头函数没有this,在内部访问this会沿着作用域链往外查找,它的外层函数是obj.say()函数。
该函数在第八行被调用时,this绑定了obj对象。因此箭头函数的this也是指向obj。
如果say方法也是箭头函数,会继续往外层找,那时就是指向window了。
在看一个例子:
1 const obj = { 2 say: function() { 3 return () => { 4 console.log(this); 5 } 6 } 7 }; 8 const say = obj.say; 9 const fn = say(); 10 fn();// window
以上代码,第九行普通调用say函数,this指向window。因此箭头函数的this也是指向window。
那么箭头函数与普通函数(function)的区别是什么?构造函数(function)可以使用 new 生成实例,那么箭头函数可以吗?为什么?
箭头函数是普通函数的另一种写法(简短的写法)。书写方式不同是第一大区别。
箭头函数内部没有arguments对象,如果要用,可以用 rest 参数代替。即(...rest) =>{console.log(rest)}。
箭头函数内部没有this对象。
箭头函数不能通过new操作符调用。(因为箭头函数没有自己的this。也无法调用call/apply方法。也没有prototype属性。无法给实例添加指向构造函数原型对象的原型指针)
箭头函数使用 yield 操作符。(生成器函数返回操作)
看到这里,想必已经了如指掌,学有所成,胸有成竹... emmmm....
接下来让我们实战一下吧,看看面试题是如何挖坑的。
1 const length = 10; 2 function fn() { 3 console.log(this.length); 4 } 5 const obj = { 6 length: 5, 7 method: function(fn) { 8 fn(); 9 arguments[0](); 10 } 11 }; 12 obj.method(fn, 1);
点击查看答案
这里主要考察函数普通调用时this的指向、作为对象的方法调用时this的指向,以及var、let、const声明变量的区别,加上对window对象、arguments对象的了解程度。
首先,第一行代码在全局作用域中声明了length变量。值为10。
在全局作用域下,var声明变量会成为window对象的属性,如有同名属性则覆盖。
let、const声明的变量不在同一作用域(会产生自己的块级作用域,在作用域中直接通过标识符访问,不能用window.xxx访问),则没有这种功效了。
如图:
接着看第十二行,调用obj.method()方法。传入两个参数,第一个参数是函数fn。
然后开始执行第八行,调用fn()函数,此时函数仅仅是普通调用,则函数内部的this指向window。
接着开始执行第九行,注意,此时函数是作为arguments对象的方法调用,函数内部的this指向arguments对象。
非常具有迷惑性,控制台输出下arguments对象一目了然。
转载于:https://www.cnblogs.com/caimuguodexiaohongmao/p/11176080.html
JavaScript内置一些方法的实现原理--new关键字,call/apply/bind方法--前戏相关推荐
- JavaScript 内置对象(一):Array 对象(构造函数、属性和方法)
Date 对象就是日期对象,它可以表示从年用毫秒的所有时间和日期.该对象是 JavaScript 内置对象中使用频率最高的一个对象. 1.Date 对象的构造函数 Date 对象的构造函数有以下4种: ...
- JavaScript 内置对象(二):Date 对象(构造函数、属性和方法)
Date 对象就是日期对象,它可以表示从年用毫秒的所有时间和日期.该对象是 JavaScript 内置对象中使用频率最高的一个对象. 1.Date 对象的构造函数 Date 对象的构造函数有以下4种: ...
- jQuery 中 data 方法的实现原理
jQuery 中 data 方法的实现原理 前言:jQuery 作为前端使用最多最广泛的 JS 库,其源码每个 JSer 都应该研究一下.早就打算看却一直被各种事拖着,上次某公司面试时被问到 jQue ...
- JavaScript进阶 - 第7章 JavaScript内置对象
第7章 JavaScript内置对象 7-1 什么是对象 JavaScript 中的所有事物都是对象,如:字符串.数值.数组.函数等,每个对象带有属性和方法. 对象的属性:反映该对象某些特定的性质的, ...
- javascript内置顶层函数
javascript 内置顶层函数 名词解释: 1.函数 2.内置: ECMAscript 内置函数:ECMAscript 自带的函数 Number() 宿主函数: BOM DOM al ...
- 对JavaScript内置对象arguments的一些见解
深入理解JavaScript内置对象arguments 这两天有伙伴问到我关于arguments的问题,使我产生了一种arguments对象容易被学习者忽略的想法,想分享一下自己对于JavaScrip ...
- 链式调用方法的实现原理和方法
1.什么是链式调用? Person person = new Person().setName(fog).setAge(18).setSex(man).setJob(software engineer ...
- javascript内置函数是什么
js内置函数是浏览器内核自带的,不用任何函数库引入就可以直接使用的函数.javascript内置函数一共可分为五类: 1.常规函数 2.数组函数 3.日期函数 4.数学函数 5.字符串函数 第一类:常 ...
- JavaScript内置对象(对象/数组/)
文章目录 一. 内置对象 1) 对象 2) Array 数组 1. 创建 2. 特点 3. 属性和方法 4. 二维数组 3)String 对象 1. 创建 2. 特点 3. 属性 4. 方法 4) M ...
最新文章
- 如何营造专属你的企业技术影响力氛围感?我不允许你还不知道
- springboot项目层次结构_Spring Boot 默认的指标数据从哪来的?
- Android 截屏并写入SD卡中
- 老实工作没有其他收入,为什么还要补缴个税?
- C++ Primer 5th笔记(chap 16 模板和泛型编程)转发参数包
- 无刷电机和有刷电机的详解区别
- 怎么将matlab滤波器系数导出_matlab与FPGA数字信号处理系列(1)——通过matlab工具箱设计FIR数字滤波器...
- UEFI学习——使用gRT->GetVariable读取Setup选项值
- 关于欧拉四面体公式的推导及证明过程
- 华为手机录音m4a格式怎么转换为MP3格式
- 2013.12.26 泡面吧--判断一个数是否为质数
- 配置和安装PIA过程中的常见问题
- 中秋快乐版二维码生成器实现
- 硬件部分第二次培训——中断详解
- java椭圆写字距离_编java代码求椭圆和长方形的面积和周长.
- 超火的ChatGPT技术原理与我们关系
- 汇编寄存器之内存访问
- 使用vue视频播放器上增加云台控制面板
- 开发一套完整的直播平台源码,必须具备完善的功能
- Sybase SQL查询字段类型
热门文章
- python软件是免费的吗-谁说程序员不懂浪漫?用Python每天自动给女朋友免费发短信...
- 北京理工大学python系列课程-北理工《Python语言程序设计》荣获中国最美慕课一等奖...
- python中常见的流程结构-Python学习笔记5程序的控制结构
- python变量类型-Python 变量类型详解
- 中国最大的python社区-python求最大数
- 简单python画圣诞树图片-python圣诞树代码
- python入门编程-对没有编程基础的人来说,直接学Python入门IT合适吗?
- python能做什么游戏ll-一个简单的python game游戏
- python3读取excel数据-Python3将爬取的数据存储到Excel
- python安装步骤win10-教你如何在Win10系统安装Python?