1、作用域是指一个变量的作用的范围,在JS中主要有两种作用域:全局作用域和局部作用域

1.1全局作用域

  • 直接编写在script标签中的JS代码,都在全局作用域;
  • 全局作用域在页面打开时创建,在页面关闭时销毁;
  • 在全局作用域中有一个全局对象window,它代表的是一个浏览器的窗口,它由浏览器创建我们可以直接使用
  • 在全局作用域中创建的变量都会作为window对象的属性保存,创建的函数都会作为window对象的方法保存
  • 全局作用域中的变量都是全局变量,在页面的任意的部分都可以访问的到

======================================================

/*
*  变量的声明提前
 * 使用var关键字声明的变量,会在所有的代码执行之前被声明(但是不会赋值),但是如果声明变量时不适用var关键字,则变量不会被声明提前
 * 
 * 函数的声明提前
 * 	使用函数声明形式创建的函数 function 函数(){},它会在所有的代码执行之前就被创建,所以我们可以在函数声明前来调用函数
 * 	使用函数表达式创建的函数,不会被声明提前,所以不能在声明前调用	
 */
console.log("a = "+a);   //a=undefined
var a = 123;

fun();
	
//函数声明式,会被提前创建
function fun(){
	console.log("我是一个fun函数");
}

//函数表达式,不会被提前创建
var fun2 = function(){
	console.log("我是fun2函数");
};

fun2();

1.2函数作用域

  • 调用函数时创建函数作用域,函数执行完毕以后函数作用域销毁
  • 每调用一次函数就会创建一个新的函数作用域,他们之间是互相独立的
  • 在函数作用域中可以访问到全局作用域的变量,在全局作用域中无法访问到函数作用域的变量
  • 当在函数作用域操作一个变量时,它会先在自身作用域中寻找,如果有就直接使用;如果没有则向上一级作用域中寻找,直到找到全局作用域;如果全局作用域中依然没有找到,则会报错ReferenceError
  • 在函数中要访问全局变量可以使用window对象

//创建一个变量
var a = 10;

function fun(){
	
	var a = "我是fun函数中的变量a";
	var b = 20;
	
	console.log("a = "+a);         //a=我是fun函数中的变量a
	
	function fun2(){
		console.log("a = "+window.a);     //a=10
	}
	
	fun2();
	
}

fun();
console.log("b = "+b);     //报错:Uncaught ReferenceError: b is not defined

/*
* 在函数作用域也有声明提前的特性,
 * 	使用var关键字声明的变量,会在函数中所有的代码执行之前被声明
 * 	声明式函数也会在函数中所有的代码执行之前执行
 */

function fun3(){
	
	fun4();
	
	console.log(a);    //a=undefined
	
	var a = 35;
	
	function fun4(){
		alert("I'm fun4");
	}
	
}

fun3();

/*
* 在函数中,不使用var关键字声明的变量都会成为全局变量
 */
var c = 33;

function fun5(){

	console.log("c = "+c);   //c=33
	
	c = 10;
	
	//d没有使用var关键字声明,则会设置为全局变量
	d = 100;
	
}

fun5();
console.log("c = "+c);    //c=10;

//在全局输出c
console.log("d = "+d);    //d=100

var e = 23;
/*
 * 定义形参就相当于在函数作用域中声明了变量
 */
function fun6(e){
	//相当于声明变量并且赋值;如var e=100;
	alert("e="+e);
}

fun6();    //弹出e=undefined
fun6(100); //弹出e=100

1.3作用域举例测试

var a = 123;
function fun(){
	alert("a="+a);    //a=123;
}
fun();

var a = 123;
function fun(){
	alert("a="+a);   //a=undefined
	var a = 456;
}

fun();
alert("a="+a);   //a=123;

var a = 123;
function fun(){
	alert("a="+a); //a=123;
	a = 456;
}

fun();
alert("a="+a);   //a=456;

var a = 123;
function fun(a){
	alert("a="+a); 
	a = 456;
}

fun();  //弹出a=undefined;
alert("a="+a);  //a=123;

var a = 123;
function fun(a){
	alert("a="+a);
	a = 456;
}

fun(110);  //弹出a=110;
alert("a="+a); //a=123;

2、JavaScript中this关键字

/*
 *解析器在调用函数每次都会向函数内部传递进一个隐含的参数,
 *这个隐含的参数就是this,this指向的是一个对象,个对象我们称为函数执行的 上下文对象.
 *根据函数的调用方式的不同,this会指向不同的对象
 * 1.以函数的形式调用时,this永远都是window
 * 2.以方法的形式调用时,this就是调用方法的那个对象
 */
function fun(){
	console.log(this.name);
}

var name="全局变量中的name";

//创建一个对象
var obj = {
	name:"孙悟空",
	sayName:fun
};

var obj2 = {
	name:"沙和尚",
	sayName:fun
};


//以函数形式调用,this指向的是window;
fun(); //全局变量中的name

//以方法的形式调用,this是调用方法的对象
obj.sayName();   //孙悟空
obj2.sayName();  //沙和尚

3、JavaScript中的数组

  • push( )

/*
* push()
 * 该方法可以向数组的末尾添加一个或多个元素,并返回数组的新的长度
 * 可以将要添加的元素作为方法的参数传递,这些元素将会自动添加到数组的末尾
 * 该方法会将数组新的长度作为返回值返回
 */
var arr = ["孙悟空","猪八戒","沙和尚"];
var result=arr.push("唐僧","蜘蛛精","白骨精","玉兔精");

console.log("result="+result);    //result=7
console.log("arr="+arr);      //arr=孙悟空,猪八戒,沙和尚,唐僧,蜘蛛精,白骨精,玉兔精
  • pop( )

/*
* pop()
 * 该方法可以删除数组的最后一个元素,并将被删除的元素作为返回值返回
 */
var arr = ["孙悟空","猪八戒","沙和尚"];
var result = arr.pop();

console.log("result = "+result);   //result = 沙和尚
console.log("arr="+arr);   //arr=孙悟空,猪八戒
  • unshift( )

/*
* unshift()
 * 向数组开头添加一个或多个元素,并返回新的数组长度
 * 向前边插入元素以后,其他的元素索引会依次调整
 */
 var arr = ["孙悟空","猪八戒","沙和尚"];
var result=arr.unshift("牛魔王","二郎神");

console.log("result = "+result);   //result = 5
console.log("arr="+arr);   //arr= 牛魔王,二郎神,孙悟空,猪八戒,沙和尚
  • shift( )

/*
*shift()
*可以删除数组的第一个元素,并将被删除的元素作为返回值返回
*/ 
var arr = ["孙悟空","猪八戒","沙和尚"];
var result = arr.shift();

console.log("result = "+result);   //result = 孙悟空
console.log("arr="+arr);   //arr= 猪八戒,沙和尚
  • 数组的遍历

var arr = ["孙悟空","猪八戒","沙和尚","唐僧","白骨精"];
	
//常用方式;
for(var i=0;i<arr.length;i++){
	console.log(arr[i]);
}

/*
 *forEach()方法需要一个函数作为参数,我们称该函数为回调函数,
 *数组中有几个元素该回调函数就会执行几次
 *在回调函数中传递三个参数:
 *	第一个参数是当前正在遍历的元素
 *	第二个参数是当前正在遍历的元素的索引
 *	第三个参数是正在遍历的数组
 */
arr.forEach(function(value,index,obj){
	console.log("value="+value);
})
  • slice( )

/*
 *slice()可以用来从数组提取指定元素
 *注意:该方法不会改变元素数组,而是将截取到的元素封装到一个新数组中返回
 *参数:
 *1.截取开始的位置的索引,包含开始索引
 *2.截取结束的位置的索引,不包含结束索引
 * 		第二个参数可以省略不写,此时会截取从开始索引往后的所有元素
 * 		索引可以传递一个负值,如果传递一个负值,则从后往前计算
 * 		-1 表示倒数第一个
 * 		-2 表示倒数第二个
 */
var arr = ["孙悟空","猪八戒","沙和尚","唐僧","白骨精"];
var result=arr.slice(1,3); 
//var result=arr.slice(2,-1); 
//var result=arr.slice(1);
console.log("result="+result);   //result=猪八戒,沙和尚
console.log("arr="+arr);  //arr=孙悟空,猪八戒,沙和尚,唐僧,白骨精
  • splice( )

/*
 *splice() 向/从数组中添加/删除项目,然后返回被删除的项目
 *注意:使用splice()会影响到原数组,会将指定元素从原数组中删除,并将被删除的元素作为返回值返回
 *参数:
 * 	第一个表示开始位置的索引
 * 	第二个表示删除的数量
 * 	第三个及以后可以传递一些新的元素,这些元素将会自动插入到开始位置索引前边
 */
var arr = ["孙悟空","猪八戒","沙和尚","唐僧","白骨精"];
var result=arr.splice(1,2);
console.log("result="+result);   //result=猪八戒,沙和尚
console.log("arr="+arr);    //arr=孙悟空,唐僧,白骨精

var arr = ["孙悟空","猪八戒","沙和尚","唐僧","白骨精"];
var result=arr.splice(1,3,"英国","德国","中国","美国");
console.log("result="+result);  //result=猪八戒,沙和尚,唐僧
console.log("arr="+arr); //arr=孙悟空,英国,德国,中国,美国,白骨精
  • concat( )

/*
* concat()可以连接两个或多个数组,并将新的数组返回
* 	- 该方法不会对原数组产生影响
*/
var arr=["UK","USA","Canada"];
var arr2=["China","Russia","India"];
var result=arr.concat(arr2);
console.log("result="+result);    //result=UK,USA,Canada,China,Russia,India
  • join( )

/*
 * join()可以将数组转换为一个字符串,该方法不会对原数组产生影响,而是将转换后的字符串作为结果返回
 * 注意:在join()中可以指定一个字符串作为数组中元素的连接符
 *     如果不指定连接符,则默认使用,作为连接符
 */
var arr=["UK","USA","Canada"];
var result=arr.join("--");
console.log("result="+result);   //result=UK--USA--Canada
console.log("arr="+arr);    //arr=UK,USA,Canada
  • reverse( )

/*
 * reverse()
 * 	- 该方法用来反转数组(前边的去后边,后边的去前边)
 * 	- 该方法会直接修改原数组
 */
var arr = ["UK", "USA", "Canada"];
arr.reverse(); 
console.log("arr=" + arr); //arr=Canada,USA,UK
  • sort( )

/*
 *在sort()可以添加一个回调函数来指定排序规则,回调函数中需要定义两个形参
 * 浏览器会根据回调函数的返回值来决定元素的顺序,
 * 	    如果返回一个大于0的值,则元素会交换位置
 * 	    如果返回一个小于0的值,则元素位置不变
 * 	    如果返回一个0,则认为两个元素相等,不交换位置
 *            如果需要升序排列,则返回 a-b
 *            如果需要降序排列,则返回b-a
 */
var arr=[12,34,23,87,38,65];
arr.sort(function(a,b){
	return a-b;
});
console.log("arr="+arr); arr=12,23,34,38,65,87

4、JavaScript中的call( )、apply( )、arguments的使用以及遍历对象中的属性;

/*
* call()和apply()
 * 	- 这两个方法都是函数对象的方法,需要通过函数对象来调用
 * 	- 当对函数调用call()和apply()都会调用函数执行
 * 	- 在调用call()和apply()可以将一个对象指定为第一个参数,此时这个对象将会成为函数执行时的this
 * 	- call()方法可以将实参在对象之后依次传递
 * 	- apply()方法需要将实参封装到一个数组中统一传递
 * 
 * 	- this的情况:
 * 		1.以函数形式调用时,this永远都是window
 * 		2.以方法的形式调用时,this是调用方法的对象
 * 		3.以构造函数的形式调用时,this是新创建的那个对象
 * 		4.使用call和apply调用时,this是指定的那个对象
 */
function fun(a,b){
	console.log("a="+a);
	console.log("b="+b);
	console.log(this);
}
	
//fun();
//fun.call();
//fun.apply();
	
var person={
	name:"tom",
	sayName:function(){
		alert(this.name);
	}
}

//fun.call(person,2,3);
fun.apply(person,[2,3]);    //call()和apply()的区别是call()方法依次传入参数就可以,apply()方法必须将参数转化为数组传入;

/*
* 在调用函数时,浏览器每次都会传递进两个隐含的参数:
 * 	1.函数的上下文对象 this
 * 	2.封装实参的对象arguments
 * 		- arguments是一个类数组对象,它也可以通过索引来操作数据,也可以获取长度
 * 		- 在调用函数时,我们所传递的实参都会在arguments中保存
 * 		- arguments.length可以用来获取实参的长度
 * 		- arguments[0] 表示第一个实参
 * 		- arguments[1] 表示第二个实参 。。。
 *		- arguments里有一个属性叫做callee,
 * 			这个属性对应一个函数对象,就是当前正在指向的函数的对象
 */
function fun(a,b){
	console.log("arguments="+arguments);  //arguments=[object Arguments]
	console.log(arguments.length+";"+arguments[0]+";"+arguments[1]);  //2;2;3
	console.log(typeof arguments);   //object
	console.log(arguments instanceof Array);   //false
	console.log(Array.isArray(arguments));  //false
	console.log(arguments.callee==fun); //true
}

fun(2,3);

//for...in 语句(对象中有几个属性,循环体就执行几次)
var person={
	name:"冯朗",
	age:25,
	sex:"男"
}

for(var prop in person){     //每次执行时都会将对象中一个属性的名字赋给变量
	console.log(prop); //name、age、sex
}

5、JavaScript中的原型

/*
 * 创建一个Person构造函数
 * - 在Person构造函数中,为每一个对象都添加了一个sayName方法,
 * 		目前我们的方法是在构造函数内部创建的,也就是构造函数每执行一次就会创建一个新的sayName方法
 * 		也就是说所有实例的sayName都是唯一的,这样就导致了构造函数执行一次就会创建一个新的方法.
 * 		这是完全没有必要,完全可以使所有的对象共享同一个方法
 */
function Person(name , age , gender){
	this.name = name;
	this.age = age;
	this.gender = gender;
	//向对象中添加一个方法
	//this.sayName = fun;
}
	
//将sayName方法在全局作用域中定义
/*
 * 将函数定义在全局作用域,污染了全局作用域的命名空间
 * 	而且定义在全局作用域中也很不安全
 */
function fun(){
	alert("Hello大家好,我是:"+this.name);
};

//向原型中添加sayName方法
Person.prototype.sayName = function(){
	alert("Hello大家好,我是:"+this.name);
};

var person=new Person("冯朗",25,"女");
var person2=new Person("冯跃",28,"男");
person.sayName();
person2.sayName();

/*
 * 原型prototype
 * 利用构造函数方式创建的每一个函数,解析器都会向函数中添加一个属性prototype
 * 		这个属性对应着一个对象,这个对象就是我们所谓的原型对象
 * 如果函数作为普通函数调用prototype没有任何作用
 * 	当函数以构造函数的形式调用时,它所创建的对象中都会有一个隐含的属性,
 * 	指向该构造函数的原型对象,我们可以通过__proto__来访问该属性
 * 
 * 原型对象就相当于一个公共的区域,所有同一个类的实例都可以访问到这个原型对象,
 * 	我们可以将对象中共有的内容,统一设置到原型对象中。
 * 
 * 当我们访问对象的一个属性或方法时,它会先在对象自身中寻找,如果有则直接使用,
 * 	如果没有则会去原型对象中寻找,如果找到则直接使用
 * 
 * 以后我们创建构造函数时,可以将这些对象共有的属性和方法,统一添加到构造函数的原型对象中,
 * 	这样不用分别为每一个对象添加,也不会影响到全局作用域,就可以使每个对象都具有这些属性和方法了
 */
function MyClass(){
	
}

//向MyClass的原型中添加属性a
MyClass.prototype.a = "我是prototype中的a";

//向MyClass的原型中添加一个方法
MyClass.prototype.sayHello = function(){
	alert("hello");
};

var mc = new MyClass();

var mc2 = new MyClass();

//console.log(MyClass.prototype);  //[object Object]
//console.log(mc2.__proto__ == MyClass.prototype);  //true

//向mc中添加a属性
mc.a = "我是mc中的a"; 

//console.log(mc.a);   //我是mc中的a
//console.log(mc2.a);  //我是prototype中的a

//mc.sayHello();
mc2.sayHello();

/*
* 创建一个构造函数
 */
function MyClass(){
	
}

//向MyClass的原型中添加一个name属性
MyClass.prototype.name = "我是原型中的名字";

var mc = new MyClass();
mc.age = 18;

//console.log(mc.name);   //我是原型中的名字

//使用in检查对象中是否含有某个属性时,如果对象属性中没有但是原型中有也返回true
//console.log("name" in mc);   //true
//console.log("age" in mc);    //true
 
//可以使用对象的hasOwnProperty()来检查对象自身中是否含有该属性
//使用该方法只有当对象自身中含有属性时,才会返回true
//console.log(mc.hasOwnProperty("age"));   //true
//console.log(mc.hasOwnProperty("name"));   //false
 
 
/*
 *原型对象也是对象,它也有原型
 *当我们使用一个对象的属性或方法时首先会现在自身中寻找,
 * 	如果自身中如果有则直接使用
 * 	如果没有则去原型对象中寻找,如果原型对象中有则使用
 * 	如果没有则去原型的原型中寻找,直到找到Object对象的原型
 * 	Object对象的原型没有原型,如果在Object原型中依然没有找到,则返回undefined
 */
console.log(mc.__proto__.__proto__.hasOwnProperty("hasOwnProperty"));  //true 

JavaScript知识点总结

相关文章: