函数、对象
一. 目标
使用arguments获取函数的所有参数 arguments是一个伪数组,可以暂且作为一个数组使用,也有参数,获取参数:实参的值赋值给形参
预解析: 预解析就是程序执行代码之前会先解析,将变量名提到当前作用域的顶部,变量的值保留不变,函数整体提升到当前作用域的顶部,优先级是函数整体比变量名要优先提升到顶部,然后自上而下解析代码
作用域和作用域链: 作用域分为:局部作用域----局部变量 全局作用域-----全局变量
匿名函数和自调用函数
对象的组成
创建自定义构造函数和创建对象
new关键字的执行过程
不同情况下this的指向
遍历对象的成员和删除对象成员
函数也是一种数据类型
二. 函数
2.1 函数体内的arguments
-
思考
写一个函数,实现计算用户输入任意个数字的总和 ?
-
arguments
- arguments,在函数体内可以使用。arguments中存放了所有的实参。
- arguments的使用:
function getSum(){ //arguments可以暂时看成是一个函数内部提供的数组,集合了所有的实参。 //arguments.length; 参数的个数 //arguments[下标]; //获取一个实参 var sum = 0; for(var index = 0;index<arguments.length;index++){ sum = sum + arguments[index]; } return sum; } var result = getSum(10,20,30,40,50); alert(result);</pre>
2.2 预解析
-
思考:
- 思考1?:
alert(a); //报错</pre>
- 思考2:
/* 对于js的执行顺序,默认是自上而下执行。 对第一个alert(a)之前并没有创建变量。按道理应该报错。 */ alert(a); //但是不会报错 var a = 123; alert(a); </pre>
- 思考3:
fn(); //报错 //函数表达式 var fn = function(){ alert(1); };</pre>
- 思考4:
fn(); //不报报错 //函数声明 function fn() { alert(1); }</pre>
-
什么是预解析
程序准备→执行。程序在执行之前,有个预备过程。 预备过程要做的事就是预解析。预备过程要做两件事,分别是:
- 把用var关键字所声明的变量名(仅仅是变量名),提升到当前执行环境的顶部。
- 把用函数声明所创建的函数(函数整体),提升到当前执行环境的顶部。
2.3 作用域
-
什么是作用域?
作用域,指的是变量或函数调用的使用范围。
-
全局作用域
- 什么是全局作用域?
> 函数之外的执行环境,就是全局作用域。
- 全局变量
> 在全局作用域中用var关键字所创建的变量,就是全局变量。 > > 全局变量的作用范围是程序中的任何地方。 > > > var a = 123; //a是全局变量 > function fn() { > alert(a); //123; > } > fn(); > alert(a); //123;</pre>
-
局部作用域
- 什么是局部作用域?
> 函数体内的环境,就是局部作用域。
- 局部变量
> 在局部作用域中用var关键字所创建的变量,就是局部变量。局部变量的作用范围是,仅仅是本函数体内使用。 > > > function fn(){ > var a = 123; > alert(a); > } > alert(a); //报错</pre>
- 函数的形参可以看成是局部变量
> > function fn(a) { > alert(a); > } > alert(a); //报错</pre>
-
看预解析
- 思考?
> > var a = 123; > function fn(){ > console.log(a); //a的值 undefined; > var a = 456; > } > fn(); > console.log(a); //a的值 123</pre>
- 预解析中的变量提升,说是提升到当前执行环境的顶部。 当前执行环境指的是当前作用域。
- 在局部作用域中使用一个变量时,若局部变量 和 全局变量重名时,在局部作用域中会优先使用局部变量。
-
作用域链
- 代码
var a = 1; function fn1(){ var a = 2; var b = '2b'; function fn2(){ var a = 3; function fn3(){ var a = 4; console.log(a); //a的值 ? consoe.log(b); //b的值 ? } } }</pre>
- 什么是作用域链? 当访问一个变量时,会先从本作用域中去找这个变量中去找,若找不到则向上一级作用域中去找,依次类推,就形成了一个作用域链。
-
JS中没有块级作用域
- 什么是块级作用域
> 在其他编程语言中,如java、c#等,在if语句、循环语句中创建的变量,仅仅只能在本if语句、本循环语句中使用。如下Java代码 > > > if(true){ > int num = 123; > system.out.print(num); //123; > } > system.out.print(num); //报错</pre>
- JS中没有块级作用域
> JS中没有块级作用域【ES5版本之前】 > > > if(true){ > var num = 123; > console.log(123); //123 > } > console.log(123); //123;</pre>
2.4 匿名函数和自执行函数
-
匿名函数
匿名函数就是没有名字的函数。在js中匿名函数需要配合运算符使用。如:
//匿名函数 常用
(function(){
alert(1);
});
//匿名函数
!function(){
alert(1);
};
//匿名函数
-function(){
alert(1);
};</pre> -
自执行函数(自调用函数)
自执行函数就是匿名函数创建后马上执行。
//匿名函数 常用
(function(){
alert(1);
})();
//匿名函数
!function(){
alert(1);
}();
//匿名函数
-function(){
alert(1);
}();</pre> -
匿名函数和自定义函数的优点
- 可以模拟块级作用域
- 可以避免全局变量污染
三. 对象
3.1 为什么要学习对象
后面的很多知识点都是通过对象调用出来的,所以我们必须务必知道对象组织数据的方式。
3.2 什么是对象
-
对象的概念
从两个层面理解:
- 生活层面,对象是单个事物抽象出来的实例。
> “万物皆对象”,一本书、一辆汽车、一个人都可以是对象,一个数据库、一张网页、一个与远程服务器的连接也可以是对象。当实物被抽象成对象,实物之间的关系就变成了对象之间的关系,从而就可以模拟现实情况,针对对象进行编程。
- 数据层面,对象是一个容器,封装了属性和方法。
> * 对象是一种数据,属于引用类型的数据 > > > * 属性:对象的静态特征。 > > > * 方法:对象的动态特征。 >
3.3 对象的创建方式
-
类和对象
- 类
> 抽象出的模板。
- 对象
> 具体的实例。
- 类和对象的关系
> 类是对象的模板,对象是类的实例。对象需要通过类来创建:具体语法如下 > > > var 对象名 = new 类名();</pre> > > [图片上传失败...(image-907306-1516642285952)]
-
方式一:通过Object类创建
- Object 类是系统提供的一个类,可以直接使用。
- 代码:
var hero1 = new Object(); //空的对象,里面属性和方法 //字面量创建 //var hero1 = {}; //和new Object()性质一样,空的对象,里面属性和方法 hero1.name = '孙悟空'; hero1.age = 18; hero1.attack = function(){ alert(this.name + '发动攻击...'); } hero01.attack();</pre>
-
方式二:通过自定义构造函数创建(自定义类)
- 在es6之前,js中没有类的概念,但可以通过构造函数模拟。
- 构造函数
> 构造函数,可以用来创建并初始化对象。
- 语法:
//创建构造函数。和普通函数创建方式一样,当命名时首字母要大写(帕斯卡命名) function 函数名(参数1,参数2...){ //this表示通过new创建的哪个当前的对象 this.键 = 参数1; this.键 = 参数2; ... } //通过构造函数创建对像 var 对象1 = new 函数名(实参1,实参2...); //new 关键字执行的过程 ① 在函数体内创建一个空的对象(看不见) ② 让当前this指向这个空的对象 ③ 通过this给当前空的对象添加键值对 ④ 返回已经添加好所有键值对的对象给外面的变量。(看不见)</pre>
- 代码:
/* 自定义构造函数(类) Hero */ function Hero(name,age){ this.name = name; this.age = age; this.sayHi = function(){ console.log('我叫' + this.name + ',我今年' + this.age + '岁'); } this.attack = function(){ console.log(this.name + '发动攻击...') } } /* 通过自定义构造函数创建对象 */ var wuKong = new Hero('孙悟空',18); wuKong.sayHi(); wuKong.attack(); var baJie = new Hero('猪八戒',20); baJie.sayHi(); wuKong.attack();</pre>
3.4 对象的操作
-
对象组织数据的方式:
对象组织数据的方式是: 键值对。
- 键,指的是属性名或方法名。
- 值,指的是实际的数据。
-
给对象增加属性和方法:
- 对象名.键名 = 值;
- 对象名['键名'] = 值;
- 代码:
var dog1 = {}; dog1.name = '旺财'; //属性 dog1['age'] = 1; //属性 dog1.call = function(){ //方法 alert(this.name + '在汪汪叫...') } //注意,方法要用函数来表示</pre>
-
访问对象中的属性和方法:
- 对象.键名;
- 对象[‘键名’];
- 代码:
var dog1 = {}; dog1.name = '旺财'; //属性 dog1['age'] = 1; //属性 dog1.call = function(){ //方法 alert(this.name + '在汪汪叫...') } //注意,方法要用函数来表示 dog1.call(); //调用 console.log(dog1['name']); console.log(dog1.age);</pre>
-
删除对象中的属性和方法:
- delete 对象.键名;
- delete 对象['键名'];
- 代码:
var dog1 = { name:'旺财', age:1, call:function(){ alert(this.name + '在汪汪叫...') } }; //删除之前访问 console.log(do1.name); //旺财 //删除 delete dog1.name; //删除之后访问 console.log(dog1.name); //undefiend //检测对中是否还要name属性 console.log(dog1.hasOwnProperty('name')); //false;</pre>
-
检测一个对象中是否存在某个属性或方法:
对象.hasOwnProperty('键名'); //返回boolean值,false表示不存在,true表示存在
-
遍历对象中的键值对
- 遍历方式 for-in
for(var key in 对象){ //key 是对象中的每一个键 //对象[key]; }</pre>
- 代码
var student1 = { name:'张三', age:17, gender:'男', scroe:100 }; for(var key in student1){ console.log(student1[key]); }</pre>
-
检测一个对象的数据类型
- 对象是引用数据类型,检测对象时不要用typeof去检测,要用instanceof
对象 instanceof 构造函数名; //返回boolean值,true表示属于,false表示不属于</pre>
- 代码
/* 创建构造函数 Person */ function Person(name,age,gender){ this.name = name; this.age = age; this.gender = gender; } // 创建一个Person类型的对象 p1 var p1 = new Person('张三',17,'男'); //检测对象p1是否属于Person console.log(p1 instanceof Person); //true</pre>
3.5 this 指向问题
-
this 介绍
this是一个关键字,这个关键字在程序执行时会指向不同的对象。也就是说这个this到底指向谁?得看程序的执行情况。</pre>
-
构造函数和普通函数调用时,this指向不同的对象
- this指向 window对象
function Person(){ this.name = '张三'; console.log(this); //window } // Person当做普通函数调用 Person();</pre>
- this指向被创建的实例对象
function Person(){ this.name = '张三'; console.log(this); //Person类型的一个实例对象 } //Person当做构造函数调用 var p1 = new Person();</pre>