函数
函数对任何一门语言来说都是核心的概念。通过函数可以封装任意多条语句,而且可以在任何地方、任何时候调用执行。在javascript里,函数即对象,程序可以随意操控它们。函数可以嵌套在其他函数中定义,这样它们就可以访问它们被定义时所处的作用域中的任何变量,它给javascript带来了非常强劲的编程能力。
1 函数概述
– 一处定义,处处调用;
– 如果把函数作为一个对象的属性,则称为方法;
– 每次调用函数会产生一个this:谁调用这个函数或者方法,this就指向谁;
– 函数就是对象,可以给他设置属性或方法;
2 函数定义的三种方式
1)声明式 function fn() {代码}
2)定义式 var obj={name:"zs",fn:function(){}} var arr=[1,2,function fn(){}]
3)构造函数 var re=new Function("parameters","执行的代码")
4)案列 判断闰年 :
function getLeapYear(year) {
var a1=(year%4==0)&&(year%100!=0);
var a2=(year%100==0)&&(year%400==0);
if(a1||a2){
return "闰年"
}
return "平年"
}
var re=getLeapYear(2022)
console.log(re);
var re1=getLeapYear(2000)
console.log(re1);
3 函数的调用
函数的调用 最后一定会生成一个结果 函数没有返回值的话 调用结果为undefined
function fn(){
}
var re=fn();
console.log(re);
写返回值 就是返回数据
function tool(){
return 100;
};//return一旦运行 函数体后来无论还有多少代码 都不会运行了 直接生成函数结果
var re=tool();
console.log(re);
4 return关键字
不写return或者return紧跟着的后面不写代码的话就是一个空表达式 会生成结果undefined,函数不一定要写返回值,函数调用后一定有返回值。
function fn(a) {
// return;(
// a+20
// )
return(
a+20
);
}
var re=fn(100)
console.log(re);
5 变量的作用域(入门)
5.1
1)在es5中 函数的代码块内部的代码 可以访问形参变量 也可以访问外部的变量(全局) 就近优先
2)函数外面的代码不能直接访问函数内部的变量
3)作用域: 指一个变量它在哪些代码范围能够被使用,这些地方就是变量的作用域
4)只有函数才有作用域的说法,对象没有这个说法
5.2 全局变量
变量会在程序运行时 把它设置为window对象的属性
var a=20
function fn(){
a=40
}
fn()
console.log(a)
5.3 局部变量
局部变量就是函数内部能使用 外部不能使用的变量( var,形参)
var a=20
function fn(a) {
var b = 20
console.log(a, b)
}
fn(100)
console.log(a)
1)案列1
var obj={
name:"karen"
}
function fn(n){
//隐式代码: var n="karen"
n="jack"
}
fn(obj.name)//obj.name取值然后再传入函数
console.log(obj.name)
2)案列2
var obj={
name:"karen"
}
function fn(n){
//隐式操作 var n=内存中的数那个传入的对象
// n.name="jack" 其实没有修改n的值
n={name:"jack"}//把n的值改了
}
fn(obj)//obj取值操作 取的是一个引用的对象
console.log(obj.name)
6 this关键字
6.1 this官方解释
this(this代表的是 执行这个this代码的环境对象)
this基本上就代表的是对象 在及其少的时候 this不是对象(call apply bind)
6.2 详解
1)this在脚本中代表的是window的全局对象
console.log(this);
2)this在全局函数中代表的是window的全局对象
function fn666() {
console.log(this);
}
fn666();
3)var a=20 全局变量会在脚本执行时 把变量名设置为全局对象window的属性
4)function fn() {console.log(this);}全局函数会在脚本执行时 吧函数设置为全局对象window的方法
6.3 常见情况
1)this关键字代表了函数调用时的调用者
function fn() {
console.log(this);
}
fn()//这个代码不是fn在调用 fn代表一个函数 是window在调用
2)匿名函数 自调用 调用者全局变量window
(function () {
console.log(this);
})();
3)特殊
function fn() {
return function fm() {
console.log(this);
}
}
fn()()//window
6.4 函数嵌套
在js程序中无论多么复杂的程序 this只需要看离最近(嵌套)的function的这个单词的调用者
var obj={
name:"karen",
say:function(){
console.log(this)//obj
function fn(a){
console.log(a,this)//obj winodw
}
// var a=this
// fn(a)
fn(this)//fn(obj)
}
}
obj.say()//obj
6.5 调用者常见情况总结
fn()// window
obj.fn() //obj
obj.xx.xx2()//obj.xx
(function(){})() window
fn()() window
fn()[1] () // fn()返回的数组
6.7 面试题
1)
var name = 'lili';
var obj = {
name: 'liming',
prop: {
name: 'ivan',
getname: function() {
return this.name;
}
}
};
console.log(obj.prop.getname());
var test = obj.prop.getname;
console.log(test());
obj.xxxx
分析:
1.obj.prop.getname() 访问到prop的getname成员并调用,调用者为prop,因此this指向prop,返回值为name成员,打印“ivan”
2.var test = obj.prop.getname;这行代码表示将getname成员取出来,console.log(test());表示调用getname函数,此时的调用者为window,打印“lili”
2)
function Foo() {
getName = function () {console.log (1);};
return this;
}
var getName = function () {console.log (4);};
Foo()
Foo().getName ()
分析:
1.Foo()调用函数,window是调用者,将getName = function () {console.log (4);};改为getName = function () {console.log (1);};
2.Foo().getName ()=window.getName () 打印“1”
7 形参与实参
实际传入函数的参数(实参) 的个数可以比形参的个数多,按照顺序赋值,不会影响程序的执行逻辑但是会影响性能
实际传入函数的参数(实参) 的个数可以比形参的个数少,按照顺序赋值,可能会影响程序的执行逻辑
function fn(a,b,c){
c=a+b;
console.log(c);
}
fn(10,20,30);
fn(a,b,c)为形参, fn(10,20,30)为实参
7.1 函数的length属性
函数的length属性代表的是形参的个数
用法:console.log(fn.length)
7.2函数的arguments属性
arguments,代表实际传入函数的参数列表(类数组)
用法:
console.log(arguments)
console.log(arguments.length)//实参个数
7.3函数的name属性
name代表函数的名称,函数的名称一般都为自己的函数名
用法:console.log(fn.name)//fn
8 new关键字
new fn() new关键字后面跟函数 是一个表达式(运算符) 创建对象的运算 整个表达式一定会得到一个对象
8.1 new使用时的步骤
1).创建一个空对象==> 创建一个空对象{} 给它添加一个属性 proto 这个属性引用fn.prototye
2). 运行构造函数,让内部的this指向创建的对象(用创建的空对象去调用构造函数)
3). 整个表达式的结果看函数的返回值:返回值是引用数据 那么就是返回值,返回值不是引用数据 那么就是这个运行完毕之后的创建的那个对象
8.2 this-new综合案列分析
function Parent() {
this.a = 1;
this.b = [1, 2, this.a];
this.c = {
demo: 5
};
this.show = function() {
console.log(this.a, this.b, this.c.demo);
}
this.change = function() {
this.a = this.b.length;
this.c.demo = this.a++;
}
return {
show:function(){console.log(1,2,3)},
change:function(){console.log(1,2,3)}
}//"hello"
}
var parent = new Parent();
// var parent={a:4,b:[1,2,1],c:{demo:3},show:func,change:func}
parent.change();
parent.show();//4 [1,2,1] 3
分析: var parent = new Parent();构建一个空对象{proto:{}},添加成员var parent={a:4,b:[1,2,1],c:{demo:3},show:func,change:func}
parent.change();调用parent对象中的change成员 a=3,demo=3,a=4
parent.show();调用parent对象中的show成员 a=4,b=[1,2,1],c.demo=3