JS的类型
1.基本类型有: String、Number、Boolean、Undefined、Null
2.复杂类型有:Function、RegExp、Array、Object、Date、Error
3.全局数据类型:Math
JS闭包
闭包简单的说就是一个函数能访问外部函数的变量,这就是闭包,比如说:
function a(x){
var str=3;
function b(y){
console.log(x+y+str);
}
}
要理解闭包,首先必须理解Javascript特殊的变量作用域。变量的作用域无非就是两种: 全局变量和局部变量;js中的特殊就在于它们两个内部的函数是可以访问外部全局变量的,但是外部是无法访问函数内的局部变量的比如:
//访问外部函数
var str = 123;
function test(){
console.log(str)
}
test()//结果为 123
-----------
//访问内部函数
function test2(){
var str2 = 234
}
test2();
console.log(str2)//报错‘str2 is not defined’
注意 :在访问内部函数的时候 如果申明变量没有使用 var 或者 let(ES6语法) 申明 ,js会认为这是一个全局变量,所以可以直接访问比如:
function test3(){
str3 = 234
}
test3();
console.log(str3)//结果为 234
现实中的各种需求有时候也不讲道理的,可能你就真的需要去访问闭包里面的函数来达到你想要的效果,这时也难不住我们各路大神,比如:
function fn1(){
var numb = 8899;
function fn2(){
console.log(numb)
}
return fn2
}
var fn3 = fn1();
fn3()
上面的函数运行时fn3()的结果就是 8899; 运用闭包的函数特点,可以访问父级函数的值, 当运行fn3的时候相当于运行了fn1,fn2可以直接获取fn1的局部变量,然后fn1直接返回fn2的值,这样当运行fn3的时候就得到了numb的值了
为什么会这样呢?原因就在于f1是f2的父函数,而f2被赋给了一个全局变量,这导致f2始终在内存中,而f2的存在依赖于f1,因此f1也始终在内存中,不会在调用结束后,被垃圾回收机制(garbage collection)回收;
参考:http://www.jb51.net/article/24101.htm
什么是闭包:
当内部函数 在定义它的作用域 的外部 被引用时,就创建了该内部函数的闭包 ,如果内部函数引用了位于外部函数的变量,当外部函数调用完毕后,这些变量在内存不会被 释放,因为闭包需要它们.
标志性的闭包函数题:
var str = '全局变量';
var Fn = {
str:'局部变量',
getStr: function(){
return function(){
return this.str
}
}
}
console.log(Fn.getStr()())//结果为 ’全局变量‘
js函数继承
参考链接:https://www.zhihu.com/question/41466747/answer/132562725
1.原型继承
比如:
function a(name){
this.name = name
}
a.prototype.consName = function(){
console.log(this.name)
}
function b(age){
this.age = age
}
b.prototype = new a('hh')
var c = new b(12)
console.log(c.name)//结果'hh'
console.log(c.age)//结果为12
c.conName()//结果为hh
这样b通过原型继承了a,在new b的时候,c中有个隐藏的属性__proto__
指向构造函数的prototype
对象,在这里是a对象实例,a对象里面也有一个隐藏的属性__proto__
,指向a构造函数的prototype
对象,这个对象里面又有一个__proto__
指向Object
的prototype
这种方式有2个缺点,第一个缺点是所有子类共享父类实例,如果某一个子类修改了父类,其他的子类在继承的时候,会造成意想不到的后果。第二个缺点是在构造子类实例的时候,不能给父类传递参数。
2.构造函数继承
function a(name){
this.name = name
}
function b(age,name){
this.age = age;
a.call(this,name)
}
var c = new b(12,'hha')
c.age//结果为12
c.name//结果为hha
注意,在确定需要将(call())a对象给b时, b()的参数必须要带上,否则会显示为空,或者你访问一个不存在的参数会显示未定义
采用这种方式继承是把a中的属性加到this
上面,这样name
相当于就是b的属性。这种方法的缺点是父类的prototype
中的函数不能复用。
js执行顺序
js中国 函数(function)的优先级要高于var变量申明;
例如:
var name = 'hello';
(function(){
if(typeof name === 'undefined'){
console.log('123'+name)
}else{
console.log('234'+name)
}
})()
结果为:234hello
var name = 'hello';
(function(){
if(typeof name === 'undefined'){
var name = 'world';
console.log('123'+name)
}else{
console.log('234'+name)
}
})()
结果为 :123world;
注意: 一般函数内部 使用变量会优先使用函数内部(相同于全局变量名称)的局部变量,
所以情况一 没有局部变量,自执行函数会直接使用 全局变量 ,而全局变量name
为hello
;所以结果为234hello;
情况二 自执行函数执行的时候 name
值未申明所以 是未定义,结果为123world
网友评论