博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
前端学习(五):深入理解原型和this、闭包
阅读量:6711 次
发布时间:2019-06-25

本文共 3091 字,大约阅读时间需要 10 分钟。

一切都是对象

数组是对象,函数是对象,对象还是对象。对象里面的一切都是属性,只有属性,没有方法。那么这样方法如何表示呢?——方法也是一种属性。因为它的属性表示为键值对的形式。 对象:

var obj = {    a:10,    b: function(){        console.log(this.a)    }}复制代码

函数

var fn = function () {            alert(100);        };        fn.a = 10;        fn.b = function () {            alert(123);        };       复制代码

函数和对象的关系

函数是一种对象

对象都是通过函数创建的

prototype 原型

每个函数都有一个属性叫做prototype。

这个prototype的属性值是一个对象(属性的集合,再次强调!),默认的只有一个叫做constructor的属性,指向这个函数本身

隐式原型

每个对象都有一个__proto__,可成为隐式原型。

每个对象都有一个__proto__属性,指向创建该对象的函数的prototype。

Object.prototype确实一个特例——它的__proto__指向的是null,切记切记!

还有——函数也是一种对象,函数也有__proto__。

对象的__proto__指向的是创建它的函数的prototype,就会出现:Object.proto === Function.prototype。用一个图来表示。

上图中,很明显的标出了:自定义函数Foo.__proto__指向Function.prototype,Object.__proto__指向Function.prototype,唉,怎么还有一个……Function.__proto__指向Function.prototype?这不成了循环引用了?

对!是一个环形结构。

其实稍微想一下就明白了。Function也是一个函数,函数是一种对象,也有__proto__属性。既然是函数,那么它一定是被Function创建。所以——Function是被自身创建的。所以它的__proto__指向了自身的Prototype。

最后一个问题:Function.prototype指向的对象,它的__proto__是不是也指向Object.prototype?

答案是肯定的。因为Function.prototype指向的对象也是一个普通的被Object创建的对象,所以也遵循基本的规则。

对于这一小节的知识点,总结起来就是以下几点:

  • Object 是所有对象的爸爸,所有对象都可以通过 proto 找到它

  • Function 是所有函数的爸爸,所有函数都可以通过 proto 找到它

  • 函数的 prototype 是一个对象

  • 对象的 __proto__属性指向原型, __proto__将对象和原型连接起来组成了原型链

instanceof

对于值类型,你可以通过typeof判断,string/number/boolean都很清楚,但是typeof在判断到引用类型的时候,返回值只有object/function,你不知道它到底是一个object对象,还是数组,还是new Number等等。

这个时候就需要用到instanceof。

Instanceof运算符的第一个变量是一个对象,暂时称为A;第二个变量一般是一个函数,暂时称为B。

Instanceof的判断队则是:沿着A的__proto__这条线来找,同时沿着B的prototype这条线来找,如果两条线能找到同一个引用,即同一个对象,那么就返回true。如果找到终点还未重合,则返回false。

原型链

访问一个对象的属性时,先在基本属性中查找,如果没有,再沿着__proto__这条链向上找,这就是原型链。

如何区分一个属性到底是基本的还是从原型中找到的呢?大家可能都知道答案了——hasOwnProperty,特别是在for…in…循环中,一定要注意

执行上下文

在一段js代码拿过来真正一句一句运行之前,浏览器已经做了一些“准备工作”,其中就包括对变量的声明,而不是赋值。变量赋值是在赋值语句执行的时候进行的。

我们总结一下,在“准备工作”中完成了哪些工作:

变量、函数表达式——变量声明,默认赋值为undefined

this——赋值

函数声明——赋值 这三种数据的准备情况我们称之为“执行上下文”或者“执行上下文环境”。

其实,javascript在执行一个代码段之前,都会进行这些“准备工作”来生成执行上下文。这个“代码段”其实分三种情况——全局代码,函数体,eval代码。

以上代码展示了在函数体的语句执行之前,arguments变量和函数的参数都已经被赋值。从这里可以看出,函数每被调用一次,都会产生一个新的执行上下文环境。因为不同的调用可能就会有不同的参数。

另外一点不同在于,函数在定义的时候(不是调用的时候,就已经确定了函数体内部自由变量的作用域

this

在函数中this到底取何值,是在函数真正被调用执行的时候确定的,函数定义的时候确定不了

情况1:构造函数

如果函数作为构造函数用,那么其中的this就代表它即将new出来的对象。

,在构造函数的prototype中,this代表着什么。

如上代码,在Fn.prototype.getName函数中,this指向的是f1对象。因此可以通过this.name获取f1.name的值。

其实,不仅仅是构造函数的prototype,即便是在整个原型链中,this代表的也都是当前对象的值。

情况2:函数作为对象的一个属性

如果函数作为对象的一个属性时,并且作为对象的一个属性被调用时,函数中的this指向该对象

情况3:函数用call或者apply调用

当一个函数被call和apply调用时,this的值就取传入的对象的值

情况4:全局 & 调用普通函数

在全局环境下,this永远是window。

不过下面的情况你需要注意一下:

情况5:箭头函数中

包裹箭头函数的第一个普通函数中的this

执行上下文栈

执行全局代码时,会产生一个执行上下文环境,每次调用函数都又会产生执行上下文环境。当函数调用完成时,这个上下文环境以及其中的数据都会被消除,再重新回到全局上下文环境。处于活动状态的执行上下文环境只有一个。

其实这是一个压栈出栈的过程——执行上下文栈

作用域

作用域在函数定义时就已经确定了。而不是在函数调用时确定。

作用域只是一个“地盘”,一个抽象的概念,其中没有变量。要通过作用域对应的执行上下文环境来获取变量的值。同一个作用域下,不同的调用会产生不同的执行上下文环境,继而产生不同的变量的值。所以,作用域中变量的值是在执行过程中产生的确定的,而作用域却是在函数创建时就确定了

所以,如果要查找一个作用域下某个变量的值,就需要找到这个作用域对应的执行上下文环境,再在其中寻找变量的值。

自由变量

在A作用域中使用的变量x,却没有在A作用域中声明(即在其他作用域中声明的),对于A作用域来说,x就是一个自由变量

闭包

你只需要知道应用的两种情况即可——函数作为返回值,函数作为参数传递

第一,函数作为返回值

第二,函数作为参数被传递

讲到自由变量跨作用域取值时,曾经强调过:要去创建这个函数的作用域取值,而不是“父作用域”

参考 :

转载地址:http://pmolo.baihongyu.com/

你可能感兴趣的文章
Maven依赖包
查看>>
去除chrome中input的黄底色
查看>>
Hyper-v之第2代虚拟机
查看>>
spring常用属性配置
查看>>
友盟报错 java.lang.NoClassDefFoundError: com.umeng.analytics.MobclickAgent
查看>>
【SNMP案例----简单网络管理协议】
查看>>
Java Map
查看>>
Deprecated:function eregi() is deprecated in /usr/local/apache/libraries/lib_lang.php on line 8
查看>>
linux生成https的key和csr文件
查看>>
Zabbix 之监控Juniper防火墙与深信服设备以及NetScaler设备
查看>>
小博浅谈MVC
查看>>
前端技术学习之选择器(四)
查看>>
Ubuntu与windows的远程控制/远程桌面
查看>>
ssh-copy-id命令解析
查看>>
自定义View的宽高设定
查看>>
进程打开的文件句柄数量超过系统默认值1024,就会提示“too many files open”信息...
查看>>
Linux下用ifconfig命令设置IP、掩码、网关
查看>>
浏览器中元素尺寸和坐标的名词解释
查看>>
我的友情链接
查看>>
IE浏览器安装低版本
查看>>