js深入讲解1-变量、作用域、函数

当为数组、对象等时,使用typeof返回的都为object,所以需要使用instanceof来判断具体的类型,并且只能和引用类型使用,基本类型不能使用该方法

 

js没有块级作用域

 

js变量:$ _  字母和数字组成,不能以数字开头

 

jquery中 $==jquery

underscore:以_开头

js中区分大小写,保留字:程序中保留用作关键字,可以在之后的功能可以实现为关键字

 

 

js中变量的命名要有意义,要一致

使用下划线或者驼峰式

btn_confirm  btn_cancel

btnConfirm   btnCancel 

 

 

var score; 变量的声明

 

 

 

数据类型和堆栈

 

 

区别就是引用类型的值可以修改,而基本类型的值不能修改,例如:

字符串方法都是返回新的字符串,而原字符串并未改变

 

person是一个引用类型,而person的值发生了变化

 

基本类型不能添加属性  输出undefined

 

但是上面基本类型字符串却可以使用replace属性方法,该方法哪来的?

基本类型调用方法会找到相应的包装对象,

1--->Number对象

"adf"-->String对象

它们的方法和属性都在包装对象上

 

内存分为堆内存和栈内存两种,栈的大小是固定的,堆内存的空间大小不固定

而地址值的大小都是一样的,所以将引用类型的地址保存到栈中,并命名,可以更好的定位到堆的位置,同时堆中的大小可以变化,

所以栈内存中如果是基本类型会直接返回值,引用类型的话返回地址值,然后再去堆内存中访问相应的值,这也就是变量的两种访问方式,按值访问和按引用访问。

 

 

输出false

 

用来判断引用对象的内容是否一样

 

遍历数组是否相等

 

复制对象,浅拷贝 ,两个对象

为什么是浅拷贝?

原因:

当有引用类型时,它的复制为基本数据类型的复制,所以直接将family的地址值复制过去,结果指向同一个family的堆空间

 

jquery的$.extend()方法既可以浅拷贝又可以深拷贝(???),

深拷贝涉及函数递归的知识

 

引用类型的参数传递的是地址值,

 

 

Person.name输出的为xm

上述代码:person指向一个空对象1,调用setName()方法,person的地址值赋值给obj,obj也指向这个空对象1,将其名字设置为xm;然后obj指向空对象2,将空对象2的name设置为xh,但是person的指向未发生改变,仍然指向对象1

 

 

返回false,instanceof只能和引用类型连用,不能和基本类型连用

 

全局作用域和局部作用域:

变量的作用域:变量赖以生存的环境,1.它的生命周期 2.在哪里可以访问到它

js中的局部作用域指的是函数作用域,因为js中没有块级作用域

 

 

全局作用域:当程序执行完之后,全局变量才会失效,而局部变量则是函数执行完就会失效

 

 

全局中的属性和函数都属于window对象的,window为全局作用域的变量对象,

fn作用域也存在一个变量对象 拥有sex属性和fn2()方法,js引擎可以使用到

fn2  作用域也同理,也存在一个变量对象

 

注意:console.log(person) 报错:person不存在

console.log (window.person) 当它变成属性的时候则不报错,输出为undefined

 

作用域链:从内到外,作用域链的尾部是window,

查找一定是沿着作用域链的,在查找的作用域内先查找相应的,如果未找到,则向外一层作用域查找,直到找到window

 

当作用域很长的时候,局部变量的查找速度快于全局变量,所以在jquery源码中将window对象通过参数传递到函数里面,一个原因就是局部的速度更快,

 

可以使用with延长作用域链,但是不要使用

 

 

with生成person作用域,在person作用域内相当于有一个person变量对象,而name,sex,score则为它的属性,name=person.name (类似window作用域中的name=window.name)

 

 

JS解析机制:

打印xh

 

此时打印为undefined

上面代码:

window下面有:

   name

   age

   fn

 

fn变量对象下面有:

   name

   age

   arguments(参数相当于局部变量)

 

预解析:分别在两个作用域内查找var字样

 将其值定为 undefined

window:  name=undefined  age=undefined  (两个var)

再接着查找全局范围内的function关键字,直接拿过来,不是赋值

                   function fn(arguments){

                                 console.log(name);

                                  name='xm';

                                  age=10;

}      

所以预解析的时候函数就已经声明了

全局作用域解析完

局部作用域:

fn:

    name=undefined

     age=undefined

     arguments=undefined

 

预解析完开始逐行读代码:

灰色部分不用再读了,预解析时已经声明了,直接fn()

此时console.log(name)  所以输出undefined

 

 

预解析冲突:

当变量名=函数名时,此时变量name就被函数name给干掉了,

此时预解析则是后面一个函数有效

 

注意:在代码块内的函数可能不能预解析,所以不要在代码块内定义函数

 

 

 

1中输出undefined

2中报错,虽然a为全局变量,但是没有var 字样,不能进行预解析,在逐行解析时,在一行时,a没有定义,所以报错

 

预解析:var a=undefined (XXX) 

              function a()后一个生效      

逐行解析:输出a()  1   1  3   3   报错

最开始预解析完后a为一个函数名,然后接着将它赋值为1 和3  (此时function函数声明部分不会再逐行解析,只有函数执行的时候才会执行它的代码)

因为函数被赋值为了数字,所以a()就会报错,此时不能当成函数来执行

 

 

js解析是分标签进行的,例子:

此时报错,因为先解析上面一个script标签,而a未声明,所以报错

 

此时上面标签预解析过了,也逐行解析过了,所以此时输出1

 

输出undefined   1

 

输出1     2

 

输出:undefined   1

函数中的参数相当于局部变量,fn(a)的a也有预解析,var a =undefined

 

输出:1   1

a=1作为参数传递过去。所以在函数内部console.log(a)时为1

 

 

 

垃圾收集机制:

 

标记清除的方法:将内存中的所有变量都打上标记,当变量还没有离开它的环境时,就把它上面的标记清除,还剩标记的即为离开了环境的变量,垃圾回收机制就清除它们的值,回收它们所占的内存

引用计数:不常用,当值的引用次数为0时,就回收其内存空间,例子:

此时{name:'xm',age:18}对象的引用次数为2,

而xh,xm都指向新的变量之后,{name:'xm',age:18}对象的引用次数变为0,不能访问到它,它就可以被回收了

 

引用计数会造成循环引用

 

函数执行完后相当于xm=null,xh=null,但是它们的引用次数都是变为1,不为0,不会回收

 

IE中此时也出现循环引用

解决:

将它们再次-1 ,即为0,此时就可以回收了

 

 

内存管理:

将没用的数据设置为null,解除引用,适合大量的全局变量

 

 

 

 

 

 

 

js函数深入讲解

 

对象的创建方式:

1.字面量创建方式:

2.构造函数创建对象(下面两种方式是等价的):

3.ECMscript5提供的:

 

 

删除之后输出undefined

 

in用来判断某个属性是否在对象中,在返回true,否则返回false

 

遍历对象:

使用forvar p in cat{}

 

Cat.p输出undefined,因为p是字符串,相当于cat."name",

应该使用cat[p];

 

 

函数:

 

 

函数的二象性:1 调用

2:函数也是对象

函数的两种定义方式:

 

函数也可以添加属性和方法

 

函数还可以:

add变量保存函数的地址值,就是函数本体,

第一个输出1

第二个输出函数function(){return 1}

 

 

此时函数作为参数,传递到另一个函数中去,

fn函数名就是函数本体,加()则代表函数执行,所以上面传递的时候只要将fn函数本体传递就可以了

 

函数作为返回值,

新函数的调用等价于上面()()

 

所以把函数当做对象来使用

 

函数的三种定义方式:

Var add=functino fn(){}

此时在外部调用使用add(),不能使用fn(),而在内部使用fn()进行调用,fn相当于一个局部变量

 

使用构造函数时,参数一定要是字符串,第三个参数为函数体,也要为字符串

 

 

预解析过程中:几种方式有区别,可能会报错

 

此时都输出1

 

而使用赋值语句的形式声明函数:

输出1

 

但是写到前面时,报错,

预解析时,查找varfunction字样,而function一定要在开头位置,才可以预解析到

 

此时报错,因为js解析器将其作为一个声明,声明就不能同时调用

所以改为不要用function开头,就可以调用匿名函数了,

也可以用括号括起来,也就不是function开头

 

 

 

 

方法的调用:

 

这也是方法的调用,将匿名函数赋值给document对象的方法onclick,浏览器帮我们调用该方法,

而下面这条语句则实现了调用,而不是浏览器的调用

 

@‘特殊的名字属性(方法) 和调用使用[]

 

方法的链式调用:

 

构造函数的调用:

一定要使用new关键字,普通函数一定有返回值,当没有return时返回undefined,有return就返回return的值,而构造函数都会返回一个对象

 

函数的间接调用:每个函数下面都有apply方法和call方法,帮助我们间接调用函数

 

 

 

此时返回的是person.name的值,即为’xh‘

第一个参数是this指向,指向window对象,返回xm

apply()方法,只传一个参数时,同call方法,

call()的参数是一个一个的传,而apply()的参数只有两个,第一个为this的指向,而第二个为数组。

当得到的数据为数组时,使用函数的apply方法,就可以直接将整个数组传递过去,而不需要将数组内的值一个一个的传递参数

 

callapply方法还可以判断数据的类型,是数组还是对象,….

链式调用:需要返回this对象

 

参数的类型:

参数传递的本质都是实参赋值给形参,当实参为引用时,形参和实参指向同一个地址的对象

 

参数个数:

实参>形参的情况:

arguments(类数组,它是一个对象)

 

 

arguments

属性不是合法标识符时,需要使用引号引起来

 

 

arguments.callee 指代函数本体,一般在递归中使用

 

严格模式下不能使用arguments.callee,

就可以使用以下方法:

当函数名发生变化时,就不用更改里面的那个函数名

arguments.callee()加上“()”就可以调用,不加“()”时代表函数本体

 

arguments.length是实参的个数,add.length是形参的个数

throw手动抛出错误

 

什么可以作为参数:基本数据类型,数组,对象,函数

 

 

用对象做参数,当参数在三个以上时,使用对象做参数更好,

 

函数作为参数的例子:回调函数(不会立即调用,满足某些条件的时候就会调用)

 

可选参数时,要把可选参数放在后面

 

return:返回值

作为数组返回,可以返回多个值

 

返回对象

 

注意return的一个问题:

此时报错,因为编程风格问题

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值