一、作用域
作用域是可访问变量的有效范围。
作用于所有代码执行的环境 (整个script标签内部) 或独立的js文件。
作用于函数内的代码环境,就是局部作用域。
在全局作用域下(函数外部)声明的变量叫做全局变量。
- 网页中所有脚本和函数均可使用全局变量
- 如果变量在函数内没有声明(没有使用 var 关键字),该变量为全局变量(不建议使用)
var global = '全局变量';
function test1() {
var name = 'zhangsan';
console.log(global);
console.log(name);
}
test1();
function test3() {
age = '未声明的变量';
console.log(age);
}
test3();
console.log(age);
在局部作用域下(函数内部)声明的变量叫做局部变量。
- 局部变量只能在该函数内部使用。
- 局部变量在函数开始执行时创建,函数执行完后局部变量会自动销毁。
- 因为局部变量只作用于函数内,所以不同的函数可以使用相同名称的变量。
- 函数参数只在函数内起作用,是局部变量。
function test2() {
var name = 'lisi';
console.log(name);
}
test2();
- 全局变量: 网页中所有脚本和函数均可使用,只有在浏览器关闭时才会被销毁,因此比较占内存
- 局部变量: 只在函数内部使用,当其所在的代码块被执行时,会被初始化,当代码块运行结束后,就会被销毁,因此更节省内存空间
- 全局变量/函数,可以覆盖window对象的变量/函数。
window.variable = 'window对象的变量';
var variable = '全局变量';
console.log(variable);
- 局部变量/函数,可以覆盖window对象的变量和全局变量/window对象的函数和全局变量的函数。
function test4() {
var variable = '局部变量';
console.log(variable);
}
test4();
二、闭包
函数 和 函数内部能访问到的变量 的总和,就是一个闭包。
function fn1() {
var num = 10;
function fn2() {
return num;
}
return fn2;
}
var f = fn1();
f();
console.log(f());
function test1() {
var local = "变量";
function foo() {
return local;
}
return foo;
}
function test2() {
var t1 = test1();
var val = t1();
alert(val);
}
test2();
闭包的作用:
闭包常常用来 间接访问一个变量。换句话说,隐藏一个变量修改权利。
错误的认识:
-
闭包不是函数套函数 是因为需要局部变量,所以才把 local 放在一个函数里,如果不把 local 放在一个函数里,local 就是一个全局变量了,达不到使用闭包的目的——隐藏变量 -
闭包中的函数是可以没有return语句 因为如果不 return,你就无法使用这个闭包。把 return foo 改成 window.foo = foo 也是一样的,只要让外面可以访问到这个 foo 函数就行了。 所以 return foo 只是为了 foo 能被使用,也跟闭包无关。
三、原型
var arr1 = [1, 0, 0, 8, 6];
var arr2 = [1, 0, 0, 8, 6, 1, 1];
arr1.sort(function (a, b) {
return a - b;
});
arr2.sort(function (a, b) {
return a - b;
});
console.log(arr1);
console.log(arr2);
console.log(arr1 === arr2);
console.log(arr1.sort === arr2.sort);
JavaScript是如何做到让sort方法是arr1和arr2的公共方法?
arr1.getSum = function () {
var sum = 0;
for (var i = 0; i < this.length; i++) {
sum += this[i];
}
return sum;
}
var a = arr1.getSum();
console.log(a);
var b = arr2.getSum();
console.log(b);
那么有没有解决方案,函数只定义一次,然后提供给不同的变量使用呢?
答案是有的:将getSum定义为原型方法
Array.prototype.getSum = function () {
var sum = 0;
for (var i = 0; i < this.length; i++) {
sum += this[i];
}
return sum;
}
console.log(arr1.getSum());
console.log(arr2.getSum());
Array.prototype.getSum = function(){}将getSum()方法给了Array.prototype,此时getSum()方法就成了原型方法,由此可知Array.prototype是数组的原型对象。
得到的结果是对象arr1和arr2就可以共享getSum方法了。
下面以构造函数方式创建对象,把不变的方法直接定义在 prototype 对象上,这样所有对象的实例就可以共享这些方法。
function Star(uname, age) {
this.uname = uname;
this.age = age;
}
Star.prototype.sing = function () {
console.log('我会唱歌');
}
var ldh = new Star('刘德华', 20);
var zxy = new Star('张学友', 25);
ldh.sing();
zxy.sing();
构造函数通过原型分配的函数是所有对象所共享的。
JavaScript 规定,每一个构造函数都有一个**prototype 属性**,指向另一个对象。
注意:这个prototype就是一个对象,这个对象的所有属性和方法,都会被构造函数所拥有。
我们可以把那些不变的方法,直接定义在 prototype 对象上,这样所有对象的实例就可以共享这些方法。
对象都会有一个属性 __proto__ ,指向构造函数的 prototype 原型对象。
之所以对象可以使用构造函数 prototype 原型对象的属性和方法,就是因为对象有 __proto__原型 的存在。
|