前端学习历程--js--原型&闭包

时间:2023-09-19 11:01:02

一、数据类型

1、值类型:undefined, number, string, boolean,不是对象

2、引用类型:函数、数组、对象、null、new Number(10)都是对象

3、引用类型判断(instanceof):

var fn = function () { };
console.log(fn instanceof Object); // true

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

二、函数和对象

1、函数可以创建对象,函数本身也是对象

前端学习历程--js--原型&闭包既对象通都是过函数创建的;var obj = { a: 10, b: 20 };其中省略了构造函数的步骤而已。

三、prototype

1、函数的prototype:默认的只有一个叫做constructor的属性,指向这个函数本身。也可以新增属性如

前端学习历程--js--原型&闭包

2、prototype的Object:

前端学习历程--js--原型&闭包

四、_proto_:

1、为什么函数创建的对象可以调用函数的 属性 :

由于fn.__proto__ === Fn.prototype

这里的"__proto__"成为“隐式原型”---既fn.__proto__也最终指向Object,所以每个对象都有一个__proto__属性,指向创建该对象的函数的prototype。

2、Object.prototype:Object也是对象,但它指向null

3、函数的创建:函数也是对象,对象需要函数创建,所以,函数这个对象是由Function创建出来

前端学习历程--js--原型&闭包既为Function创建函数的过程

4、Function:Function也是对象最终指向本身 既Function是被自身创建的,函数与对象的死循环  到此为止

五、instanceof

1、typeof与instanceof :typeof在判断到引用类型的时候,返回值只有object/function,你不知道它到底是一个object对象,还是数组,还是new Number等等。

            所以用到instanceof前端学习历程--js--原型&闭包

2、instanceof 的判断规则::Instanceof运算符的第一个变量是一个对象,暂时称为A;第二个变量一般是一个函数,暂时称为B。沿着A的__proto__这条线来找,同时沿着B的prototype这条线来找,如果两条线能找到同一个引用,即同一个对象,那么就返回true。如果找到终点还未重合,则返回false。

六、继承和原型链;

1、javascript中的继承是通过原型链来体现的:如

前端学习历程--js--原型&闭包

其中f1.b是怎么来的呢?——从Foo.prototype得来,因为f1.__proto__指向的是Foo.prototype既:访问一个对象的属性时,先在基本属性中查找,如果没有,再沿着__proto__这条链向上找,这就是原型链

2、hasOwnProperty:

区分一个属性到底是基本的还是从原型中找到的 如

前端学习历程--js--原型&闭包

而hasOwnProperty的来历是:f1--_proto_--Foo.prototype--_proto_--Object.prototype---------->这也就是  继承

3、自定义函数prototype中的方法:

前端学习历程--js--原型&闭包

七、执行上下文环境

1、执行上下文:其实就是js预编译的过程,过程完成三个动作

前端学习历程--js--原型&闭包

2、上下文环境的产生:全局是一个环境,之后函数每被调用一次,都会产生一个新的执行上下文环境。

3、*变量和作用域:

*变量的值要在生成该变量所在函数的作用域中找。

前端学习历程--js--原型&闭包把fn赋值给f,调用f(),实际调用的是fn()

八、this

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

2、在构造函数中:

前端学习历程--js--原型&闭包this-->Foo-->f1

前端学习历程--js--原型&闭包this-->Foo-->window

3、函数作为对象属性时:

前端学习历程--js--原型&闭包this-->function-->obj

前端学习历程--js--原型&闭包this-->function-->onj.fn-->fn1-->window

4、被call和apply调用时:

前端学习历程--js--原型&闭包obj继承fn属性并调用fn;this-->fun-->fn-->obj

5、全局 & 调用普通函数

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

前端学习历程--js--原型&闭包this-->fun f-->f-->fn:fun-->obj.fn-->window

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

九、执行上下文栈、作用域

1、正常来讲处于活动状态的执行上下文环境只有一个,新的上下文环境开始预编译,上一个环境就要出栈销毁

2、作用域:javascript没有块级作用域。所谓“块”,就是大括号“{}”中间的语句。例如if语句:

前端学习历程--js--原型&闭包

所以,我们在编写代码的时候,不要在“块”里面声明变量,要在代码的一开始就声明好了。以避免发生歧义。

我们在声明变量时,全局代码要在代码前端声明,函数中要在函数体一开始就声明好。

3、作用域的创建:javascript除了全局作用域之外,只有函数可以创建的作用域。作用域有上下级的关系,上下级关系的确定就看函数是在哪个作用域下创建的。

4、作用域用处:作用域最大的用处就是隔离变量,不同作用域下同名变量不会有冲突。

前端学习历程--js--原型&闭包三个作用域下都声明了“a”这个变量,但是他们不会有冲突。

5、作用域的生命周期

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

作用域只是一个“地盘”,一个抽象的概念,其中没有变量。要通过作用域对应的执行上下文环境来获取变量的值。

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

十、从*变量到作用域链

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

前端学习历程--js--原型&闭包x要到创建这个函数的那个作用域中取值——是“创建”,而不是“调用”,切记切记

——其实这就是所谓的“静态作用域”。

2、作用域链:就是*变量一步一步寻找变量值,直到全局的过程

十一、闭包

1、闭包的使用情况:函数作为返回值,函数作为参数传递。

2、函数作为返回值

前端学习历程--js--原型&闭包bar函数作为返回值,赋值给f1变量。执行f1(15)时,用到了fn作用域下的max变量的值。

3、函数作为参数传递

前端学习历程--js--原型&闭包fn函数作为一个参数被传递进入另一个函数,赋值给f参数。执行f(15)时,max变量的取值是10,而不是100。

4、闭包:

前端学习历程--js--原型&闭包

执行完第17行,fn()调用完成。按理说应该销毁掉fn()的执行上下文环境,但是这里不能这么做。注意,重点来了:因为执行fn()时,返回的是一个函数。函数的特别之处在于可以创建一个独立的作用域。而正巧合的是,返回的这个函数体中,还有一个*变量max要引用fn作用域下的fn()上下文环境中的max。因此,这个max不能被销毁,销毁了之后bar函数中的max就找不到值了。

执行到第18行时,全局上下文环境将变为活动状态,但是fn()上下文环境依然会在执行上下文栈中。另外,执行完第18行,全局上下文环境中的max被赋值为100。

前端学习历程--js--原型&闭包

执行到第20行,执行f1(15),即执行bar(15),创建bar(15)上下文环境,由于fn没有销毁,仍然能找到max=10。

所以,使用闭包会增加内容开销。