一.函数与对象的爱恨情仇
一切皆为对象,但并不是所有的都是对象,其中undefined, number, string, boolean)属于简单的值类型,不是对象。剩下的几种情况——函数、数组、对象、null或者new一个对象,都是对象,他们都是引用类型。
1.对象是属性的集合(important!!!!!)
对象里面的一切都是属性,只有属性,没有方法--方法也是一种属性,因为它的属性表示为键值对的形式。关于函数与数组对象定义属性是以其他形式定义的。
反正一切(引用类型)是对象,对象是属性的集合
2.对象都是函数创建的,函数也是对象,有一种鸡生蛋蛋生鸡的逻辑(别急后面会理清这种关系的)
---关于对象都是函数创建的如:
以上代码的本质
而且 Object 和 Array 都是函数:
console.log(typeof (Object)); // function
console.log(typeof (Array)); // function
---函数也是对象,也是属性的集合
每个函数都有一个prototype属性(这就是为什么函数是对象了,因为它里面已经事先有一个属性了,而对象又是属性的集合,逻辑是不是很对!没毛病!)指向该函数的原型对象(既然是对象,也是属性的集合!!!),只要是对象就有一个__proto__ 属性指向构造函数。
3.关于对象:
i本人理解如果用构造函数的方法创造对象,形如就是先创建一个模型,其中Fn函数里定义了很多属性,既然Fn是函数,那么Fn就有prototype属性指向该函数的原型对象。该函数的原型对象你可以自己在里面定义一些属性,该函数的原型对象里有一个constructor属性指向该构造函数。如果你要想要继承我这些属性,可以通过new关键字,new出一个新的对象。
ii只要new出f1新对象了,那么f1对象就会继承函数里的所有属性,既然f1是对象,那么就有__proto__属性指向构造函数的原型即。
iii上文说过Object 和 Array 都是函数,因为要创造此类型对象要new一个出来,说明他们也是构造函数,形如function Object(){}和function Array(){}.。并且他们已经是系统创建好了。
iiii这里先讲一下new的机制为下面的原型链做下铺垫。
(这里我觉得new时,不仅把构造函数的原型对象赋给创造出来的对象,而且还继承了构造函数里定义的属性)
iiiii这里还有一个逻辑问题,关于前文说的对象都是函数创建的,函数也是对象,那么函数是怎么出来的,不可能是石头里蹦出来的吧!且看如下代码:
4.原型及原型链就以图解形式
每每看到这些图,我都有一种杀人的冲动,冲动是魔鬼,理解了以后才会明白很多问题:
(这里解释一下构造函数,所谓构造函数就是用来new对象的函数。其实严格来说,所有的函数都可以new一个对象,但是有些函数的定义是为了new一个对象,而有些函数则不是。另外注意,构造函数的函数名第一个字母大写(规则约定)例如:Object、Array、Function等)
function fn(){};
var test = new fn();
这里new的机制就是把test.__proto__=fn.prototype,实现原型继承。要想使用一个对象的属性,首先在自身查找这个属性,如果没有找到就在原型链上查找,直到为空为止。
5.this的指向问题
i在函数中this到底取何值,是在函数真正被调用执行的时候确定的,函数定义的时候确定不了。
ii 构造函数情况241行中的this在没有new时this指的是window,当new以后指向函数函数本身(也是对象)。
iii函数作为对象一个属性时
1.如果函数作为对象的一个属性时,并且作为对象的一个属性被调用时,函数中的this指向该对象。
2.注意,如果fn函数不作为obj的一个属性被调用,会是什么结果呢?
iiii特殊情况
Javascript没有块(这里的块指的是{})级作用域的概念,javascript除了全局作用域之外,只有函数可以创建作用域。所以这里的f()还是一个普通的函数,是在全局作用域下运行的。
二.作用域及闭包的问题
1.且看下面例题:
两句话特别重要:1.变量声明提前,但不会赋值2.函数声明优与变量声明
alert(a)
a();var a=3; function a(){
alert(10)
}
alert(a)
a=6;
a();
------------分割线------------------
alert(a)
a();var a=3;var a=function(){
alert(10)
}
alert(a)
a=6;
a();
第一题等价于:
第二题等价于:
2.寻找作用域问题
这里取x的值时,就需要到另一个作用域中取,有人说过要到父作用域中取,其实有时候这种解释会产生歧义,要到创建这个函数的那个作用域中取值——是“创建”,而不是“调用”。
上面描述的只是跨一步作用域去寻找。
如果跨了一步,还没找到呢?——接着跨!——一直跨到全局作用域为止。要是在全局作用域中都没有找到,那就是真的没有了。
这个一步一步“跨”的路线,我们称之为——作用域链。
我们拿文字总结一下取自由变量时的这个“作用域链”过程:(假设a是自由量)
第一步,现在当前作用域查找a,如果有则获取并结束。如果没有则继续;
第二步,如果当前作用域是全局作用域,则证明a未定义,结束;否则继续;
第三步,(不是全局作用域,那就是函数作用域)将创建该函数的作用域作为当前作用域;
第四步,跳转到第一步。
3.闭包
只要知道应用的两个情况就可以了:
第一:函数作为返回值
第二:函数作为参数传递
这里也用到跨作用域了,在执行到11行时,寻找max在自己的作用域找不到时,就跨到全局作用域去找。
本文参考:http://www.cnblogs.com/wangfupeng1988/p/3977924.html
感想:本文是在2017年11月下旬面试总结下来的,个人感觉学知识,学技术,不能知其然,不知其所以然,不能抱着侥幸的心理。