1.作用域
作用域是可访问变量的有效范围
1.1局部作用域
函数内声明的变量为局部作用域
局部变量只能在函数内部访问
局部变量只作用在函数内部,所以不同的函数可使用相同的变量名称
局部变量在函数开始执行时创建,函数执行完后局部变量会自动销毁
函数的参数只在函数内部作用为局部变量
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>局部作用域</title>
<script>
//局部作用域
function test() {
// name为局部变量
var name = "wangxiao";
// 在函数内部自由提取
alert(name);
}
// 函数外不能使用name变量
alert(name);
//测试不同函数内变量名称重复互不影响
function test2() {
var name = "wangerxiao";
alert(name);
}
//测试函数的参数为局部变量
function test3(name1) {
alert(name1);
}
function test4() {
alert(name1);
}
test3("zhangsan")
// test4("zhangsan")会报错
</script>
</head>
<body>
<h4>局部作用域</h4>
<p>作用域是可访问变量的有效范围</p>
<p>函数内声明的变量为局部作用域</p>
<p>局部变量只能在函数内部访问</p>
<p>局部变量在函数开始执行时创建,函数执行完后局部变量会自动销毁</p>
<p>局部变量只作用在函数内部,所以不同的函数可使用相同的变量名称</p>
<p>函数的参数只在函数内部作用为局部变量</p>
<input type="button" value="测试局部变量" onclick="test();">
<input type="button" value="测试不同函数内变量名称重复" onclick="test2();">
</body>
</html>
1.2全局变量
在函数外定义的变量为全局变量
网页中的所有函数和脚本均可使用
函数内未声明的变量就是window对象的变量,为全局变量
在 HTML 中, 全局变量是 window 对象: 所有数据变量都属于 window 对象
全局变量,或者函数,可以覆盖 window 对象的变量或者函数
局部变量,包括 window 对象可以覆盖全局变量和函数
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>全局变量</title>
<script>
var name = "wangxiao"; //全局变量
alert(name);
function test1() {
//在函数内也可访问
alert(name);
}
//如在函数内未声明变量
function test2() {
//未声明的变量就是window对象的
name1 = "wangerxiao"
window.alert(name1);
}
function test3() {
window.alert(name1);
}
// 测试全局变量,或者函数,可以覆盖 window 对象的变量或者函数
window.age = 30; //window对象的变量
var age = 40;
alert(age); //40
// 测试 局部变量,包括 window 对象可以覆盖全局变量和函数。
var city = "beijing"; //全局变量
function test4() {
var city = "shanghai";
alert(city);
}
test4(); //shanghai
</script>
</head>
<body>
<h3>全局变量</h3>
<p>在函数外定义的变量为全局变量</p>
<p>网页中的所有函数和脚本均可使用</p>
<p>函数内未声明的变量就是window对象的变量,为全局变量</p>
<input type="button" value="测试" onclick="test1();">
<input type="button" value="测试函数内未声明变量" onclick="test2();">
<input type="button" value="测试其他函数能否调用未声明变量" onclick="test3();">
</body>
</html>
2.闭包
<script>
// 闭包
var name = "wangxaio";
function test() {
console.log(name)
}
</script>
[函数」和「函数内部能访问到的变量」的总和,就是一个闭包.
闭包不是函数套函数
闭包中的函数可以没有return语句(return语句在闭包中只是为了变量能被使用)
闭包的作用是--隐藏一个变量的修改权限(只能用不能修改)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>闭包</title>
<script>
// 闭包
/* var name = "wangxaio";
function test() {
console.log(name)
}*/
// 使用闭包
function test1() {
var name = "wangxaio";
function bb() {
console.log(name)
return name;
}
return bb;
}
function test2() {
var te = test1(); //得到bb函数
var name1 = te() //得到输出的变量值
console.log(name1); //控制台输出
}
test2();
</script>
</head>
<body>
<h3>闭包</h3>
<p>[函数」和「函数内部能访问到的变量」的总和,就是一个闭包</p>
<p>闭包不是函数套函数</p>
<p>闭包中的函数可以没有return语句</p>
<p>return语句在闭包中只是为了变量能被使用</p>
<h3>闭包的作用是--隐藏一个变量的修改权限</h3>
</body>
</html>
3.原型与原型链
var arr1 = [11, 2, 1, 15];
var arr2 = [0, 19, 20, 5];
//排序
arr1.sort(function(a, b) {
return a - b;
});
arr2.sort(function(a, b) {
return a - b;
});
console.log(arr1); //[1, 2, 11, 15]
console.log(arr2); //[0, 5, 19, 20]
// 数据类型相同,数据个数不同
console.log(arr1 === arr2); //false
//sort为Array的公共方法(不是arr1或arr2的)排序方法相同
console.log(arr1.sort === arr2.sort); //true
//通过Array创建了arr1和arr2者两个数组对象,此时arr1和arr2者两个数组对象会从Array继承到sort方法。
var arr1 = [11, 2, 1, 15];
var arr2 = [0, 19, 20, 5];
// 数组求和
arr1.getsum = function() {
var sum = 0;
for (var i = 0; i < this.length; i++) {
sum = sum + this[i];
}
return sum;
}
console.log(arr1.getsum()); //29
// console.log(arr2.getsum()); //arr2没有求和方法。所以报错
将求和方法交给Array
// 将求和方法交给Array
// 语法
var arr1 = [11, 2, 1, 15];
var arr2 = [0, 19, 20, 5];
Array.prototype.getsum1 = function() {
var sum = 0;
for (var i = 0; i < this.length; i++) {
sum = sum + this[i];
}
return sum;
}
console.log(arr1.getsum1());//29
console.log(arr2.getsum1());//44
prototype属性
// 创建构造函数
function person(name, age) {
this.name = name;
this.age = age;
this.test = function() {
console.log("person内的一个方法")
}
}
//构造函数创建对象
var zs = new person("张三", 20);
console.log(zs.name); //张三
zs.test(); //person内的一个方法
var wx = new person("王小", 30);
console.log(wx.age); //30
wx.test(); //30
// 对象实例和它的构造函数之间建立一个链接,之后通过上溯原型链,在构造函数中找到这些属性和方法。
//这个链接是对象的__proto__属性,是一个通过构造函数创建的对象
console.log(zs.__proto__);
// 对象的__proto__属性是由构造函数的prototype属性派生的
console.log(person.prototype);
console.log(person.prototype === zs.__proto__);//true
对象的__proto__属性是由构造函数的prototype属性派生的
当我们通过构造函数创建对象的时候,实际上是创建了2个对象,
第一个对象就是用来调用属性和方法的实例对象per1
第二个对象就是构造函数.prototype得到的对象【原型对象】--- 构造函数
每个函数上面都有一个属性(prototype)指向了函数的原型对象(Person.prototype)。
即使你只定义了一个空函数,也存在一个prototype的属性
实例访问属性或者方法的时候,遵循以为原则:
如果实例上面存在,就用实例本身的属性和方法。
如果实例上面不存在,就会顺着__proto__的指向一直往上查找,查找就停止。
每个函数的原型对象上面都有一个constructor属性,指向了构造函数本身
//每个函数的原型对象上面都有一个constructor属性,指向了构造函数本身。
function Person(name, age) {
this.name = name;
this.age = age;
this.test1 = function() {
console.log("Person对象中的方法");
}
}
//实例对象
var wx = ("王小", 30);
console.log(Person.prototype.constructor); //person这个函数
console.log(wx.constructor); //ƒ Number() { [native code] }
原型链
对象在寻找某一属性时,如果自身属性没找到就去他对应的原型对象去找。
若在原型上面找到对应的属性则停止,否则继续去原型的原型找对应的属性,这样构成了一条原型链。
Object.prototype.test = function() {
console.log("Object的原型对象是原型链的最顶端")
}
function person(name, age) {
this.name = name;
this.age = age;
this.ff = function() {
console.log("person函数内的方法")
}
}
// 实例
var wx = new person("王小", 30);
console.log(wx.name); //30
wx.ff(); //person函数内的方法
console.log(wx.__proto__);
console.log(person.prototype);
console.log(person.prototype === wx.__proto__); //true
console.log(Object.prototype.__proto__); //null