继承:
Call:
var lipi={
name:"李皮",
play:function(foo){
console.log(this.name+"正在玩"+foo);
}
}
lipi.play("和泥")
liujiaming想拿到lipi里面的play方法
var liujiaming = {
name:"刘嘉明"
}
lipi.play.call(liujiaming,"回旋踢");
call第一个参数改变this的指向,第二个参数是play这个方法要传递的值,可以多个,用逗号隔开,比如,lipi.play.call(liujiaming,"回旋踢",3,4);但是如果方法里面没传两个形参play:function(foo,a,b)的话3,4是不会输出,也不会报错,但是如果形参传了实参没传就是undefined
案例1
var aLi = document.getElementById("list").getElementsByTagName("li");
console.log(aLi instanceof Array) //fasle,用这种方法获取的数组是伪数组
var aLi = document.getElementById("list").getElementsByTagName("li");
var arr = [].slice.call(aLi) //true,借用真数组arr的方法使aLi变为真数组
console.log(arr instanceof Array)
案例2
function fn(){}
var a = new fn();
console.log(typeof a)//object typeof只能判断基本数据类型,当判断复杂数据类型是typeof只会判断为object
1 function fn(){}
console.log(Object.prototype.toString.call(fn))//[object Function]
2 var obj ={};
console.log(Object.prototype.toString.call(obj))//[object object]
后面为数据类型,使用这个方法就可以判断复杂数据类型了
老师笔记:
Object.prototype.toString.call():检测一个复杂数据类型是一个什么样的类型
instanceof:判断一个对象是不是另一个对象创建出来的
typeof:只能判断基本数据类型 引用数据类型统计返回OBject
apply:(同样具有call的用法,但它的第二个参数可以传数组)

Math.max(取出最大值)这个方法没办法放数组
所以。。。
var arr = [10,20,30,40]
var arr1 = [];
console.log(Math.max.apply(arr1,arr));//40
先创建arr1再让this指向arr1跟直接传 [ ]是一样的,但是var这样占用内存空间
因此:
var arr = [10,20,30,40]
console.log(Math.max.apply([],arr));//40
max是Math的方法,数组通过apply跟Math借,第一个依然是改变this的指向,所以传this指向一个数组,第二个传判断哪个数组的最大值
---------------------------------------------------------------------------------------------
1、属性继承:


但是lipi并没有继承到Person里面的属性

使用call跟Person借属性,第一个参数改变this指向,指向Man,后面传要借的属性

这时候call已经成功继承到Person的属性和方法了
但是一般为了节省内存空间,都会把方法放在prototype上面


但是放了之后却继承不到方法了,所以call只能继承属性,不能继承方法,想继承的话又会耗费内存,所以一般只用call和apply来做属性继承
笔记:call和apply一般情况下我们都用来做属性继承
---------------------------------------------------------------------------------------------
prototype__proto__constructor:原型链
笔记(背会)
prototype:每一个函数里面都有一个prototype ,这个属性叫做原型,这个原型指向一个对象 我们把这个对象叫做原型对象
prototype原型对象里面有2个东西
1、constructor:构造器--作用指向创建自己的那个构造函数
2、__proto__:1 每一个对象里面都会有一个__proto__这个属性
2 __proto__指向了一个对象 这个对象就是原型对象
3 实例化对象可以直接访问__proto__里面的一些方法
原型链:由__proto__组成的链条就叫做原型链


---------------------------------------------------------------------------------------------
实例化的过程就是创建对象的过程,new的过程就是创建对象的过程


方法在_proto_里面

//结果为true
---------------------------------------------------------------------------------------------

本来访问实例化对象访问__proto__里面的方法需要console.log(p1.__proto__.eat)
但却直接console.log(p1.eat)就可以直接访问,所以说 实例化对象可以直接访问__proto__里面的一些方法
---------------------------------------------------------------------------------------------

---------------------------------------------------------------------------------------------

原型链:
可以通过 console.log(p1.__proto__.__proto__.toString)
访问父级Person的方法,p1里没有tostring这个方法,是使用链条访问到父级的方法(p1的父级是Person,Person的父级是object)
---------------------------------------------------------------------------------------------
2、原型继承(极度简单,但也极度不推荐使用,因为会污染父级)

方法work要加在原型上面

属性都通过call继承到了,但方法却只继承到了work一个,因为他本来就放在Man上面,但是它也要继承到person的方法


这时候所有属性和方法就都继承到了
---------------------------------------------------------------------------------------------

输出父级

发现Man的work方法也加到了父级上面,这就是污染父级
---------------------------------------------------------------------------------------------
3、原型拷贝 (不能直接继承父级以上的东西,只能一层层嵌套)

那既然会污染父级,我们就把Man.prototype = Person.prototype;改为下面的拷贝继承

复制父级的方法,这样就父级的方法就不会发生变化,输出p1和父级看一下

子级继承到父级Person的方法了,父级的方法也没有被子级污染到,貌似看起来没什么问题.
但是不能继承父级以上的东西(也就是Person的以上就不能继承了)
---------------------------------------------------------------------------------------------


依然保留Man拷贝Person的循环,再加上shengwu这个方法,也加一个拷贝的循环,一层层嵌套,依然输出p1和person

这时候Person继承到了父级shengwu的increase的方法,P1继承也到了父级的父级的方法
但这样需要多层嵌套,一层一层的获取,是原型拷贝的唯一缺点
---------------------------------------------------------------------------------------------
4 、原型链继承 (多了无用的属性,并且constructor构造器没了,原型对象的指向也发生改变)
原型链:由__proto__组成的链条就叫做原型链

因为prototype里面的东西跟实例化对象里面的__proto__的东西是一样的,
所以我们让子级Man的prototype等于父级的实例化里面的东西(p1.eat=p1.___proto___.eat,所以直接省略___proto___就可以访问了)

因为是原型链继承 ,所以是形成链条一样的,但这时候确实是访问到了父级的方法,但是多了无用的属性,并且constructor构造器没了,原型对象的指向也发生改变

console.log( [Person] )这时候父级也没有被污染
原型链继承的缺点:丢失构造器,多了一些无用的属性,原型对象的指向也发生改变
---------------------------------------------------------------------------------------------

原型链链条

object再上面就是null,所以说null是原型链的顶端
---------------------------------------------------------------------------------------------
5 、混合继承(完美继承方式)

person.prototype里面的东西本身就跟new Person 的__proto__里面的东西一样,所以跟上面的原型链继承差不多,只不过自己加个constructor构造器上去

父级并没有被污染

constructor构造器有了,父级的方法也继承到了,所以说混合继承是完美的继承方式
---------------------------------------------------------------------------------------------
6 、寄生继承 (没有混合继承的方法代码少)


所以又要再给它加上构造器


这时候就有了,所以这种方法也是好,但是没有混合继承的方法代码少,所有混合继承的方式最好
总结:
<script>
(模板例子)
function Person(name,age,sex){
this.name = name;
this.age = age;
this.sex = sex;
}
Person.prototype.eat = function(){}
Person.prototype.sleep = function(){}
function Man(y,name,age,sex){
this.y = y;
Person.call(this,name,age,sex)
}
-----------------------------------
//继承语句
Man.prototype = {
constructor:Man,
__proto__:Person.prototype
}
-----------------------------------
Man.prototype.work = function(){} //写在继承语句下面,不然添加不到Man上
var p1 = new Man();
console.log(p1);
console.log([Person])
-----------------------------
继承主要语句:
//混合继承(完美继承方式)
Man.prototype = {
constructor:Man, //添加少了的构造器
__proto__:Person.prototype
}
//寄生继承
function fn(){}; //寄生壳
fn.prototype = Person.prototype;
Man.prototype = new fn();
//原型拷贝(不能拷贝父级的父级)
for(var key in Person.prototype){
Man.prototype[key] = Person.prototype[key];
}
//原型链继承(多了无用东西,少了构造器)
Man.prototype = new Person();
//原型继承(污染父级,不推荐)
Man.prototype = Person.prototype;
//属性继承(只能继承属性)
Person.call(this,name,age,sex)
Person.apply(this,name,age,sex)
</script>
闭包:
闭包:闭包就是能够读取其他函数内部的变量的函数
全局变量:任何范围之内都能访问
局部变量:只能在当前作用域内访问
好处:1 可以让局部的变量在全局进行访问
2 保留i的值
坏处:1 占用内存空间
2 在IE浏览器下可能会造成内存溢出
3 所以不要滥用闭包,如果用完记得销毁

通过return接受值

正常情况下每次调用后都会被销毁,但在闭包里面就不会
垃圾回收机制:
当函数运行完毕以后如果内部的变量或者函数没有在全局挂载的话,
那么这个函数就会被销毁掉
如果第二次执行这个函数的时候里面的代码就会重新执行(所以就是因为这样才每次调用都会销毁重置让a=10,所以外面输出的结果都是11)

a已经被return出去变成全局的了,所以在外面调用两次都会进行++ //11 //12
面试题:

同上,也就是把局部的变量挂载到全局上面,所以全局可以访问到进行累加

挂载在全局后如果不销毁的话会一直在里面进行++,不会销毁重置,所以值才能在全局一直累加,会占用内存,所以不要滥用闭包,如果用完记得销毁

让b=null;就是销毁了,再调用就是没有了
---------------------------------------------------------------------------------------------

这时候i一下子就等于4了

放在立即执行函数里面,就形成闭包,这样子就可以保留i的值了