1.闭包
闭包就是能够读取其他函数内部变量的函数。(变量所在的函数就是闭包函数)
例如在javascript中,只有函数内部的子函数才能读取局部变量,所以闭包可以理解成“定义在一个函数内部的函数“。
闭包不是函数套函数
是因为需要局部变量,所以才把 num 放在一个函数里,如果不把 num 放在一个函数里,num 就是一个全局变量了,达不到使用闭包的目的——隐藏变量
闭包中的函数是可以没有return语句
因为如果不 return,你就无法使用这个闭包。把 return fn2 改成 window.fn2 = fn2 也是一样的,只要让外面可以访问到这个 fn2 函数就行了。
所以 return fn2 只是为了 fn2 能被使用,也跟闭包无关。
闭包的作用
闭包可以用在许多地方。它的最大用处有两个:
可以读取函数内部的变量(延伸变量的作用范围,但仅能读取访问,不能修改)
让这些变量的值始终保持在内存中
2.原型
<script>
/*
var arr1 = [1, 0, 0, 8, 6];
//var arr1 =new Array[1, 0, 0, 8, 6];
var arr2 = [1, 0, 0, 8, 6, 1, 1];
//var arr2 =new Array[1, 0, 0, 8, 6, 1, 1];
arr1.sort(function(a,b){
return a-b;
});
arr2.sort(function(a,b){
return a-b;
});
console.log(arr1);
console.log(arr2);
console.log(arr1===arr2); //false
//因为arr1和arr2中的元素个数不一样,arr1===arr2---false
console.log(arr1.sort===arr2.sort); //true
//因为arr1和arr2所用的排序方法是相同的,也就是说sort方法是arr1和arr2,公共方法。
//这个公共的sort方法不是arr1和arr2是Array的方法
//我们通过Array创建了arr1和arr2者两个数组对象,此时arr1和arr2者两个数组对象会从Array继承到sort方法。
*/
/*
var arr1 = [1, 0, 0, 8, 6];
var arr2 = [1, 0, 0, 8, 6, 1, 1];
//数组求和方法
Array.prototype.getSum = function() {
var sum = 0;
for(var i = 0; i < this.length; i++) {
sum += this[i];
}
return sum;
}
console.log(arr1.getSum()); //输出15
console.log(arr2.getSum()); //输出17
//arr1.getSum()结果为15,arr2.getSum()结果有错误,arr1有求和方法,arr2没有求和方法
//由此可知getSum()不是公共方法,意味着getSum()在Array中没有。
//如果我们希望arr2也能有getSum()求和方法,目前我没有2中做法
//做法1:就是给arr2编写一个与arr1一样的求和方法
//缺点是我们编写了一堆重复的代码
//做法2:将getSum()求和方法交给Array,成为公共方法。
//问题:如何将getSum()求和方法交给Array?
//结构:Array.prototype.属性/方法
*/
/*
//prototype
//想要知道prototype是什么玩意,干什么的,就得从对象的创建开始了解。
//创建对象的几种方式
//方式1:定义+创建
//var Person={
//name:"zhangsan",
//age:23,
//address:"西安",
//test1:function(){
//console.log("Person对象中的方法");
//}
//}
//console.log(Person.name);
//Person.test1();
//缺点:当需要多个对象的时候我们就会产生大量的代码重复。
//方式2:先定义,后创建
function Person(name,age,address){
this.name=name;
this.age=age;
this.address=address;
this.test1=function(){
console.log("Person对象中的方法");
}
}
//我们将创建对象的函数成为构造函数
//问题2:如何用构造函数创建对象【new】
var zs=new Person("zhangsan",23,"西安");
console.log(zs.name);
zs.test1();
var ls=new Person("lisi",24,"北京");
console.log(ls.name);
ls.test1();
//问题3:构造函数中的属性和方法是如何交给创建出来对象?
//对象实例和它的构造函数之间建立一个链接,之后通过上溯原型链,在构造函数中找到这些属性和方法。
//这个链接是对象的__proto__属性,是一个通过构造函数创建的对象
//console.log(zs.__proto__);
//对象的__proto__属性是由构造函数的prototype属性派生的
//console.log(Person.prototype);
//当我们通过构造函数创建对象的时候,实际上是创建了2个对象,
//第一个对象就是用来调用属性和方法的实例对象[zs,ls]
//第二个对象就是构造函数.prototype得到的对象【原型对象】--- 构造函数
*/
//1.每个函数上面都有一个属性(prototype)指向了函数的原型对象(Person.prototype)。
//即使你只定义了一个空函数,也存在一个prototype的属性。
//2.每个实例上面都有一个隐式原型(__proto__)指向了函数的原型对象
//3. 实例访问属性或者方法的时候,遵循以为原则:
//3.1 如果实例上面存在,就用实例本身的属性和方法。
//3.2 如果实例上面不存在,就会顺着__proto__的指向一直往上查找,查找就停止。
//4.每个函数的原型对象上面都有一个constructor属性,指向了构造函数本身。
function Person(name,age,address){
this.name=name;
this.age=age;
this.address=address;
this.test1=function(){
console.log("Person对象中的方法");
}
}
var zs=new Person("zhangsan",23,"西安");
alert(Person.prototype.constructor);
alert(zs.constructor);
</script>
3.原型链
<script type="text/javascript">
//对象在寻找某一属性时,如果自身属性没找到就去他对应的原型对象去找。
//若在原型上面找到对应的属性则停止,否则继续去原型的原型找对应的属性,这样构成了一条原型链。
//Object的原型对象是原型链的最顶端。
/*
Object.prototype.test1=function(){
console.log("Object的原型对象中的test1方法");
}
function Person(name,age,address){
this.name=name;
this.age=age;
this.address=address;
}
var p1=new Person("zhangsan",23,"西安");
p1.test1();
*/
//Object的原型对象的原型对象
console.log(Object.prototype.__proto__); //null
</script>