共计 6016 个字符,预计需要花费 16 分钟才能阅读完成。
作用域(Scope)
作用域指变量的作用范畴
在 JS 中一共有两种作用域
全局作用域和函数作用域(部分)
全局作用域
间接编写在 script 标签中的 JS 代码,都在全局作用域
全局作用域在页面关上时创立,在页面敞开时销毁
在全局作用域中有一个全局对象 window 咱们能够间接应用
它代表的是一个浏览器的窗口,由浏览器创立咱们能够间接销毁
在全局作用域中,创立的变量都会作为 window 对象的属性保留
全局作用域中的变量都是全局变量,在页面的任意局部都能够拜访的到
var a = 10;
console.log(window.a) // 输入 10
创立的函数都会组为 window 对象的办法保留
function fun(){console.log("我是 fun 函数")
}
window.fun(); // 输入我是 fun 函数
函数作用域(部分)
变量的申明提前
应用 var 关键字申明的变量,会在所有的代码执行前被申明(然而不会赋值)
console.log("a ="+a)
a = 123; // 输入 undefined,不会报错因为在执行前申明 var a
然而如果申明变量时不应用 var 关键字,则变量不会被申明提前
console.log("a ="+a)
a = 123; // 报错
函数的申明提前
应用函数申明模式创立的函数(fun)function 函数 (){}
它会在所有的代码执行之前就被创立,应用咱们能够在函数申明之前调用函数
应用函数表达式创立的函数(fun2)不会被申明提前,所以不能在申明前调用
fun(); // 输入我是一个 fun 函数
fun2(); // 报错
function fun(){console.log("我是一个 fun 函数");
}
var fun2 = function(){console.log("我是 fun2 函数");
}
函数作用域(部分)
调用函数时创立函数作用域,函数执行结束当前,函数作用域销毁
每调用一次函数就会创立一个新的函数作用域,他们之间是互相独立的
在函数作用域在能够拜访到全局的变量,在全局作用域中无法访问到函数作用域的变量
当在函数作用域中操作一个变量时,它会先在本身作用域中寻找,如果有就间接应用,如果没有则向上一级作用域中寻找,直到找到全局作用域,如果全局作用域中仍然没有找到,则会报错
在函数中要拜访全局变量能够应用 window. 对象
var a = 10;
function fun(){
var a = "我是函数中的作用域"
var b = 20;
console.log(a); // 输入我是函数中的作用域
}
fun();
console.log(b); // 报错
在函数作用域中也有申明提前的个性
应用 var 关键字申明的变量,会在函数中所有的代码执行前被申明
function fun3(){console.log(a);
var a = 35; // 输入 undefined
}
在函数中不应用 var 申明的变量都会成为全局变量
定义形参就相当于在函数作用域中申明了变量
this
解析器在调用函数时每次都会向函数外部传递一个隐含的参数
这个隐含的参数就是 this,this 指向的是一个对象
这个对象咱们称为函数执行的上下文对象,
依据函数的调用形式的不同,this 会指向不同的对象
1. 以函数的模式调用时,this 永远都是 window
2. 以办法的模式调用时,this 就是调用办法的那个对象
function fun(){console.log(this); //window
}
fun()
var obj = {
name:"孙悟空",
sayName:fun
};
//console.log(obj.sayName == fun); //true
obj.sayName(); //object 孙悟空
fun() //window
var name = "全局";
function fun(){console.log(this.name); // 如果没有 this 上面两个输入将都是孙悟空
}
var obj = {
name:"孙悟空",
sayName:fun
}
var obj2 = {
name:"沙和尚",
sayName:fun,
}
//fun(); // 全局
// 咱们心愿调用 obj.sayName()时能够输入 obj 的名字
obj.sayName(); // 孙悟空
obj2.sayName(); // 沙和尚
应用工厂办法创建对象
应用工厂办法创立
通过该办法能够大批量的创建对象
function createPerson(name, age, gender) {
// 创立一个新对象
var obj = new Object();
// 向对象中增加属性
obj.name = name;
obj.age = age;
obj.gender = gender;
obj.sayName = function() {alert(this.name);
};
// 将新的对象返回
return obj;
}
var obj2 = createPerson("猪八戒", 28, "男");
var obj3 = createPerson("白骨精", 16, "女");
var obj4 = createPerson("蜘蛛精", 18, "女");
console.log(obj2); // 输入 obj2 所有内容
console.log(obj3); // 输入 obj3 所有内容
console.log(obj4); // 输入 obj4 所有内容
obj3.sayName() // 输入白骨精
构造函数
应用工厂办法创立的对象,应用构造函数都是 Object
所以创立的对象都是 Object 这个类型
就导致咱们无奈辨别出多种不同类型的对象
创立一个构造函数,专门用来创立 Person 对象的
构造函数就是一个一般函数,黄建形式和一般函数没有区别
不同的是构造函数习惯上首字母大写
构造函数和一般函数的区别就是调用形式的不同
一般函数是间接调用,而构造函数须要应用 new 关键字调用
构造函数的执行流程,
1. 立即创立一个新的对象
2. 将新建的对象设置为函数中 this,在构造函数中能够应用 this 来援用新建的对象
3. 逐行执行函数中的代码
4. 将新建的对象作为返回值返回
应用同一个构造函数创立的对象,咱们称为一类对象,也将一个构造函数成为一个类
咱们将通过一个构造函数创立的对象,称为该类的实例
this 的状况:
1. 当以函数的模式调用时,this 是 window
2. 当以办法的模式调用时,谁调用办法 this 就是谁
3. 当以构造函数的模式调用时,this 就是新创建的那个对象
function Person(name,age,gender){
this.name = name;
this.age = age;
this.gender = gender;
this.sayName = function(){alert(this.name);
};
}
function Dog(){}
var per = new Person("孙悟空",18,"男");
var per2 = new Person("玉兔精",16,"女");
var per3 = new Person("奔走霸",38,"男");
var dog = new Dog;
console.log(dog); // 类型为 Dog
console.log(per); // 类型为 Person
console.log(per2);
console.log(per3);
应用 instanceof 能够查看一个对象是否是一个类的实例
语法:
对象 instanceof 构造函数
如果是返回 true,否则返回 false
console.log(per instanceof Person); //true
console.log(dog instanceof Person); //false
所有的对象都是 object 的后辈,所以任何对象和 object 做 instanceof 查看时都会返回 true
console.log(dog instanceof Object); //true
创立一个 Person 构造函数
在 Person 构造函数中,为每一个对象都增加了一个 sayName 办法,
目前我的办法切实构造函数外部创立的,
也就是构造函数每执行一次就会创立一个新的 sayName 办法
也是所有实例的 sayName 都是惟一的
这样就导致构造函数执行一次就会创立一个新得办法
执行 10000 次就会创立 10000 个新得办法,而 10000 个办法都是截然不同的
这是齐全没有必要,齐全能够使所有的对象共享同一个办法
function Person(name,age,gender){
this.name = name;
this.age = age;
this.gender = gender;
// 向对象中增加一个办法
this.sayName = fun;
}
// 将 sayName 办法在全局作用域中定义
function fun (){alert("hello, 我是"+this.name)
};
// 创立一个 Person 的实例
var per = new Person("孙悟空",18,"男");
var per2 = new Person("猪八戒",28,"男");
console.log(per.sayName == per2.sayName); //true
原型变量
原型 prototype
咱们所创立的每一个函数,解析器都会向函数中增加一个属性 prototype
这个属性对应着一个对象,这个对象就是咱们所谓的原型对象
如果咱们的函数作为一般函数调用 prototype 没有任何作用
当函数通过结构函数调用时,它所创立的对象中都会有一个隐含的属性
指向该构造函数的原型对象,咱们能够通过 proto 来拜访该属性
原型对象就相当于一个公共的区域,所有同一个类的实例都能够拜访到这个对象,
咱们能够将对象中共有的内容,对立设置到原型对象中。
当咱们拜访对象的一个属性或办法时,它会当初对象本身中寻找,如果有则间接应用,如果没有则会去原型对象中寻找,如果找到则间接应用
当前创立构造函数时,能够将这些对象共有的属性和办法,对立增加到构造函数的原型对象中,这样不必别离为每一个对象增加,也不会影响到全局作用域,就能够使每个对象都具备这些属性和办法了。
function MyClass(){}
// 向 MyClass 的原型中增加属性 a
MyClass.prototype.a = 123;
// 向 MyClass 原型中增加一个办法
MyClass.prototype.sayHello = function(){alert("hello")
}
var mc = new MyClass();
var mc2 = new MyClass();
//console.log(mc.__proto__ == MyClass.prototype); //true
//console.log(mc2.__proto__ == MyClass.prototype); //true
// 向 mc 中增加属性 a
mc.a = "我是 mc 中的 a"
console.log(mc.a) // 我是 mc 中的 a
console.log(mc2.a) //123(去原型中找)mc.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
// 能够应用对象的 hasOwnProperty()来查看对象本身中是否含有该属性
// 应用该办法只有当对象本身中含有该属性时,才会返回 true
console.log(mc.hasOwnProperty("name")) //false 因为没有
console.log(mc.hasOwnProperty("age")) //true
原型对象也是对象,所有它也有原型
当咱们应用一个对象的属性或办法时,会先在本身中寻找
本身如果有,则间接应用
如果没有则去原型对象中寻找,如果原型对象中有则应用
如果没有则去原型的原型中寻找, 直到找到 Object 对象的原型
Object 对象的原型没有原型,如果在 Object 中仍然没有找到,则返回 undefined
console.log(mc.__proto__.__proto__); //true
console.log(mc.__proto__.__proto__.hasOwnProperty("hasOwnProperty")); //true
console.log(mc.__proto__.__proto__.__proto__); //null
toString()
function Person(name,age,gender){
this.name = name;
this.age = age;
this.gender = gender;
}
批改原型的 toString
Person.prototype.toString = function(){return "Person[name="+this.name+",age="+this.age+",gender="+this.gender+"];"
};
创立一个 person 实例
var per = new Person("孙悟空",18,"男");
var per2 = new Person("猪八戒",28,"男");
当咱们间接在页面中打印一个对象时,实际上是输入的对象的 toString()办法的返回值
如果咱们心愿在输入对象时不输入 [object Object], 能够为对象增加一个 toString() 办法
//per.toString = function(){
// return "我是一个高兴的小 person";
// return //"Person[name="+this.name+",age="+this.age+",gender="+this.gender+"];"
// };
// var result = per.toString();
//console.log(per.__proto__.__proto__.hasOwnProperty("toString"));
console.log(per);
console.log(per2);
垃圾回收(GC)
就像人生存的工夫长了会产生垃圾一样,程序运行过程中也会产生垃圾,
这些垃圾积攒过多当前,会导致程序运行的速度过慢,
所以咱们须要一个垃圾回收的机制,来处理程序运行过程中产生的垃圾
当一个对象没有任何的变量或属性对它进行援用,此时咱们将永远无奈操作该对象,
此时这种对象就是垃圾,这种对象过多会占用大量的内存空间,导致程序运行变慢
所以这种垃圾必须进行清理。
在 JS 中领有主动的垃圾回收机制,会主动将这些垃圾对象从内存中销毁
咱们不须要也不能你进行垃圾回收的操作
咱们须要做的只是将不再应用的对象设置为 null 即可
var obj = new Object();
// 对对象进行各种操作
obj = null