JS高级
函数
-
函数声明
-
函数声明的时候,函数体不会执行,只要函数被调用的时候才会执行
-
函数一般用来干一件事情,函数名称一般使用动词
function 函数名(){
//函数体
}
-
-
函数表达式
var fn =function(){
//函数体
} -
函数的调用
-
函数体只有在调用的时候才会执行,调用需要()进行调用,可以调用多次
函数名();
// 声明函数
function sayHi() {
console.log("吃了没?");
}
// 调用函数
sayHi();
-
-
函数的参数
- 形参:声明函数时,给函数设置参数,这个参数没有具体的值,只起到占位作用。
- 实参:如果函数声明设置了形参,调用时就需要传入对应的参数,这个传入的参数叫实参
-
函数的返回值
- 当函数执行完毕时,我们期望函数给我们一些反馈(比如计算的结果返回进行后续的运算)这就是返回值,通过return返回一个返回值。
- 函数的调用结果就是返回值,可以直接对函数调用结果进行操作。
- 返回值详解
- 函数没有 return 返回 undefined
- 函数 有return 跟在return后面的值就是函数的返回值
- 函数有return后面没有任何值,返回 undefined
- 函数使用return语句,这个函数就会在执行完return之后停止并立即退出,return后面的所有代码不再执行。
-
匿名函数
- 没有名字的函数
- 将匿名函数赋值给一个变量,通过变量进行调用
- 或者匿名函数自调用
-
自调用函数
-
匿名函数不能直接通过调用来执行,因此可以通过匿名函数自调用的方式来执行
(function () {
alert(123);
})();
-
-
函数是一种数据类型
-
函数作为参数
- 函数可以作为另一个函数的参数,在另一个函数中调用
-
函数作为返回值
- 函数可以作为返回值从函数内部返回
function fn(b) {
var a = 10;
return function () {
alert(a+b);
}
}
fn(15)();
-
new关键字
- new在执行时会做四件事情:
- new会在内存中创建一个新的空对象
- new 会让this指向这个新的对象
- 执行构造函数 目的:给这个新对象加属性和方法
- new会返回这个新对象
this 详解
对象的使用
-
遍历对象的属性
-
for in 可以遍历对象的成员
for (var key in obj){
console.log(key)//-->属性名
console.log(obj[key])//--对应的属性值
} -
删除属性
delete 对象.属性名
构造函数
对象的属性和方法叫做对象的成员
- 函数内部创建的属性和方法叫做实例对象/对象成员
- 跟对象相关的成员,将来使用对象的方式调用
- 静态成员:直接给构造函数增加成员
- 静态成员不能使用对象的方式调用,使用构造函数调用(Hero.成员)
- 实例成员与对象有关,静态成员与对象无关
原型对象
- 每个构造函数都有一个属性,就是原型对象prototype
- 构造函数通过原型对象增加的方法和属性,构造函数创建的所有对象都可以访问,而且在在内存中只有一份
- 对象通过打点的方式增加属性,而 构造函数.prototype 也是一个对象,也可以通过打点的方式增加方法,而且构造函数创建的所有对象都可以增加了这个方法(语法:构造函数.prototype.方法=function(){})
- 使用原型对象增加方法和在构造函数内增加方法的区别:当调用对象的属性或方法,先去找对象的属性或方法,如果对象没有该属性/方法,此时去调用原型中的属性或方法
- 对象.proto = 构造函数.prototype (通过构造函数(Hero)创建对象(hero1))
- 只要有对象,都有proto这个属性,在原型对象中有个属性叫constructor,这个属性叫构造函数,可以打印出这个构造函数,访问方式,对象.constructor,constructor记录了创建给对象的构造函数,可以判断这个对象是由哪个构造函数创建的
构造函数 原型对象 实例/对象 之间的关系
- 构造函数创建对象
构造函数的原型属性prototype 构造函数 拥有 原型对象
- 对象的属性proto 指向 构造函数的原型对象
原型链
- 原型链的顶端是null
- s1对象的原型对象的原型对象就是Object构造函数的原型对象
s1.proto.proto===Object.prototype - 读取属性时,先在对象本身查找,找不到就去原型链里找
- 设置属性时,不会搜索原型链,而是给这个对象新增一个属性并赋值
- 当我们改变构造函数的prototype时,需要重新设置constructor属性
- 先设置原型属性,在创建对象,才可以访问原型对象中的成员
原型对象的应用
数组或String中的prototype是不可以重新赋值修改的
继承
面向对象三大特征: 封装 继承 多态(抽象)
继承:类型和类型之间的关系
继承的目的::把子类型中共同的成员提取到父类型中,代码重用
原型继承:无法设置构造函数的参数
借用构造函数(造函数的属性继承)
- call()改变函数的this,直接调用函数,call的第一个参数是要改变的指向对象
- 在函数内部,通过 call(借用的函数,参数),借用了构造函数继承了属性成员
- 借用构造函数的方法只有在构造函数内方法可以继承,通过原型对象增加的方法不能继承
组合继承
- 组合继承:借用构造函数+ 原型继承
- 借用构造函数(在函数内部使用call) + 原型继承(子类型.protopyte=父类型.prototype)
- 借用构造函数,让teacher继承person里的属性,设置teacher的原型对象,继承person里的方法(teache.prototypr=new Person();),
函数的进阶
-
函数声明和函数表达式的区别:函数表达式的变量会提升,结果为undifined,函数声明不会提升
-
if语句内,函数不会提升
-
函数定义方式:函数也是对象,可以传参,有属性和方法
var fn=new Function('a','b','console.log(a+b));
fn(1,2);
函数的调用方式
-
普通函数调用:this指向window,谁调用这个方法,this指向谁
function fn(){
console.log(this)
}
fn(); -
方法调用:this指向调用该方法的对象
var obj={
fn:function(){
console.log(this)
}
}
obj.fn(); -
作为构造函数调用【call ()】:this指向由这个构造函数创建的对象
-
作为事件的处理函数调用:this指向触发该事件的对象
btn.onclick=function(){
console.log(this)
} -
作为定时器的参数:this指向window
setInterval(function(){
console.log(this)
},1000)
==函数内部的this是由函数调用的时候确定其指向==
call 、apply 和bind()改变函数中的this
function fn(x,y){
console.log(this);
console.log(x+y);
}
fn(5,6) //this-->window
var obj={
name:'zs'
}
fn.call(obj,5,6); //-->obj对象和11
fn.apply(obj,[1,8]);//fn内需要几个参数,数组中传几个参数
//-->obj和9
//bind不会调用函数,要想调用需要用一个变量接收bind的返回值
var f=fn.bind(obj,2,2);
f();//不用传递参数直接调用
- call方法:
- 调用函数,改变函数中的this
- 第一参数,设置函数内部this的指向,其他参数,对应函数的参数
- 函数的返回值,call的返回值就是fn函数的返回值
- apply方法:
- 调用函数,改变函数中的this
- 第一个参数: 设置函数内部this的指向,第二个参数是数组
- 函数的返回值,call的返回值就是fn函数的返回值
- bind方法:
- 改变函数中的this,但不会调用函数,而是把函数复制一份
- 第一参数,设置函数内部this的指向,其他参数,对应函数的参数
- 函数的返回值,call的返回值就是fn函数的返回值
call的应用
Array.prototype.getSum=function(){
this指谁?
}
var arr=[1,2,3];
arr.getSum();//通过数组调用,this指向这个数组
arr.push(); //数组本身提供了,push、splice方法
arr.splice(); //删除数组元素 splice(从那一项删除,删除几项)
伪数组
var Obj={
0:100,
1:10,
2,:11,
3:20,
length:4
};
给这个数组追加属性:
方法一:
obj['4']=12; //(数字不能作为变量和属性开头,所以用obj['4'])
obj.length++;
方法二:
数组的push方法(让伪数组借用数组的方式)
Array.prototype.push.call(obj,30);
//给Array的原型对象push一个对象,
//并且通过call改变this指向,
//指向obj,就给obj追加了数组
所有的对象都有toString()这个方法
- object.toString()--->Object(代表是一个对象) object(这个对象的类型)
- arr.tostring()-->数组里的值 1,2,3
- Object.prototype.toString.call(arr) ---> object Array (数组对象的类型)
apply的应用
语法:fn.apply(,[])
常用于把数组展开,传递给前面的方法
var arr = [5,8,10,2]
console.log(Math.max(arr))//--.NAN Math.max不能求数组中的最大值
<!--可以把数组中的每一项展开,传给max,返回最大值-->
Math.max.apply(null,arr)
<!--max中的this指向math,所以不用改变指向-->
Math.max.apply(Math,arr)
bind的应用
bind和apply、call的区别在于bind不会去调用方法,而是去复制方法
-
应用一
var obj = {
name:'zs',
fun:function(){
setInterval(function(){
console.log(this.name)
}.bind(this),1000);
}
}
obj.fun()
-
应用二
btn.onclick=function(){
}.bind(obj)
小结
- call 和 apply 特性一样
- 都是用来调用函数,而且是立即调用
- 但是可以在调用函数的同时,通过第一个参数指定函数内部 this 的指向
- call 调用的时候,参数必须以参数列表的形式进行传递,也就是以逗号分隔的方式依次传递即可
- apply 调用的时候,参数必须是一个数组,然后在执行的时候,会将数组内部的元素一个一个拿出来,与形参一一对应进行传递
- 如果第一个参数指定了 null 或者 undefined 则内部 this 指向 window
- bind
- 可以用来指定内部 this 的指向,然后生成一个改变了 this 指向的新的函数
- 它和 call、apply 最大的区别是:bind 不会调用
- bind 支持传递参数,它的传参方式比较特殊,一共有两个位置可以传递
- 在 bind 的同时,以参数列表的形式进行传递
- 在调用的时候,以参数列表的形式进行传递
- 那到底以谁 bind 的时候传递的参数为准呢还是以调用的时候传递的参数为准
- 两者合并:bind 的时候传递的参数和调用的时候传递的参数会合并到一起,传递到函数内部
函数中的其他成员
- arguments
- 伪数组,获取到的是函数的实参,实参集合
- caller
- 函数的调用者,在全局范围调用的时候caller是null
- name
- 函数的名称,字符串类型
- length
- 函数的形参个数
arguments应用
//当函数的参数个数不固定的时候
//在函数内部,可以通过arguments获取到实际传过来的参数
function max(){
var max = arguments[0];//假设第一个参数为最大值
for(var i=0,i<arguments.length;i++){
if(max<arguments[i]){//如果最大值小于遍历的这个参数
max=arguments[i];//那么让这个参数为最大值
}
}
}
console.log(max(2,7,9,4)); //-->9
网友评论