一、instanceof 操作符
instanceof:js的关键字。
作用:用来判断一个对象是否是某种类型的实例。
用来判断对象的原型链中是否包含了类型的原型对象。
类型的原型对象是否在对象的原型链中。
如果在原型链中返回true,否则返回false。
结论:子类型对象永远是父类型的实例。
<script>
//父类型的构造函数。可以作为多个子类型的父类型
//比如工人,农民,学生都是人的子类型。
//Person类型是所有的子类型中的公共的部分提取出来形成的。
function Person(name, age, gender) {
this.name = name;
this.age = age;
this.gender = gender;
}
//在父类型的原型中添加了方法
Person.prototype.eat = function () {
console.log (this.name + "\t是一个吃货!");
}
function Student(name, age, gender, classId, score) {
//借用构造函数继承。
Person.call(this,name,age,gender);
this.classId = classId;
this.score = score;
}
//原型链继承
//子构造函数的原型指向父类型的一个实例。不需要传参
Student.prototype = new Person();
//子构造函数原型的constructor属性的修正。
Student.prototype.constructor = Student;
//添加其他的方法。
Student.prototype.study = function () {
console.log (this.name + "\t是一个学霸");
}
var stu = new Student();
console.log (stu instanceof Student);//true
console.log (stu instanceof Person);//true
console.log (stu instanceof Object);//true
</script>
二、hasOwnProperty方法介绍
hasOwnProperty:是在Object的原型中定义的。
所以任何的实例对象都可以使用该方法。
作用:用来检测某个属性是否是当前对象的私有属性的?
如果是,返回true,否则返回false。
结论:hasOwnProperty 对于私有属性返回是true,原型中的内容和静态成员都是false
<script>
var obj = {
name:"tom",
age:17,
study : function () {
console.log ("study");
}
}
console.log (obj);
console.log (obj.hasOwnProperty("name"));//true
console.log (obj.hasOwnProperty("study"));//true
console.log (obj.hasOwnProperty("score"));//false
function Person(name, age, gender) {
this.name = name;
this.age = age;
this.gender = gender;
}
//在父类型的原型中添加了方法
Person.prototype.eat = function () {
console.log (this.name + "\t是一个吃货!");
}
//静态成员
Person.MAX_AGE = 150;
var person = new Person("小刚",18,"男");
console.log (person.hasOwnProperty("name"));//true
console.log (person.hasOwnProperty("gender"));//true
console.log (person.hasOwnProperty("age"));//true
console.log (person.hasOwnProperty("eat"));//false
console.log (person.hasOwnProperty("MAX_AGE"));//false
</script>
三、in关键字
in js的关键字。
作用:用来判断某一个属性是否可以被某个对象使用。
语法:属性 in 对象
返回:可用:true,不可用false。
对于一个对象来说,原型中的内容和私有的内容都是可以被对象使用的。
结论:使用 hasOwnProperty 和in 可以精确的判断一个属性是私有的还是原型对象中的。
<script>
function Person(name, age, gender) {
this.name = name;
this.age = age;
this.gender = gender;
}
//在父类型的原型中添加了方法
Person.prototype.eat = function () {
console.log (this.name + "\t是一个吃货!");
}
//静态成员
Person.MAX_AGE = 150;
var jerry = new Person("jerry",3,"男");
console.log ("name" in jerry);//true
console.log ("age" in jerry);//true
console.log ("gender" in jerry);//true
console.log ("eat" in jerry);//true
console.log ("MAX_AGE" in jerry);//false
</script>
四、作用域链
掌握:为什么js可以在不同的作用域下可以访问不同作用域中定义的内容。
问题:js中存在不同的作用域,那么js是通过什么样的机制来保证,在不同的作用域下,可以访问不同的内容。
1:【执行环境】:Execution Context
【执行环境】是js中第一个非常重要的概念。在【执行环境】中定义了变量或者是函数有权访问其他的属性。决定了它们能够各自使用那些方法。在每个【执行环境】中都有一个与之关联的【变量对象】。执行环境中的所有的可以访问的变量和函数都在对应的变量对象中保存。
不同的【执行环境】对应着不同的变量对象。【变量对象】就保存了对应的执行环境中定义的内容。
【执行环境】分类:
a:全局的执行环境
是一个最外围的执行环境,默认的全局执行环境就是window对象。所有的全局的变量和方法都作为window对象的属性和方法创建。
b:每个函数对应的局部的执行环境。
当开始进入一个函数的内部开始执行的时候,就开始进入函数的局部的执行环境了。函数执行完毕之后,退出函数的局部执行环境。退出到进入该函数的执行环境之前的环境。
c:eval()执行环境(了解)
2:【变量对象】(Variable Object)
每个【执行环境】中都有一个与之关联的【变量对象】。在该执行环境中定义的所有的成员,都包含在与其对应的【变量对象】中。
全局的变量对象就是window对象。
函数的局部执行环境是下面提到的函数的【活动对象】
3:【活动对象】
当一个函数调用的时候,一个特殊的对象就被创建了。称为【活动对象】,该对象中包含了形参和arguments对象以及函数内定义的局部变量。这个【活动对象】就被当做当前函数的【局部执行环境】中的【变量对象】使用。
4:不同的执行环境切换的时候的执行的过程
在任何的执行环境中都有该环境下需要执行的js代码。当我们在某一个执行环境中执行完毕之后。
该环境中定义的所有的成员也随之销毁。当一个函数执行完毕之后,和函数相关的局部成员都被销毁。全局作用域中定义的成员直到页面关闭才被销毁。
5:【作用域链】:【变量对象】形成的一个链条。
当代码在一个执行环境中执行时候,就会创建【变量对象】的一个作用域链。
【作用域链】:用途保证在不同的执行环境中有权有序的访问成员。
【作用域链】的最前端是当前的执行环境的下的【变量对象】。如果这个环境是函数的执行环境
那么【变量对象】就是当前的【活动对象】。【作用域链】的下一个变量对象是包含当前执行环境的上一个执行环境。【作用域链】中的第一个变量对象一定是全局的环境下的window。
【作用域链】:【变量对象】形成的一个链条。
【作用域链】的本质是指向变量对象的指针列表。
【作用域链】就是指针列表。指向不同变量对象的指针形成的列表。
6:对于任何第一个函数内部都有一个属性。该属性是[[scope]] 作用域的意思。
该属性不能被访问。该属性指向 变量对象的指针列表。
<script>
var value = 10;
function fn1() {
var value = 20;
console.log (value);
}
function fn2() {
console.log (value);
}
//去全局的执行环境对象的对象变量--window对象中去找是否有fn2()
fn2();
fn1();
</script>
五、闭包
闭包:closure
概念:是一个局部函数。可以在局部作用域外面去访问局部作用域中的内容。
闭包的作用:
1:可以在函数的外部去访问函数内部的局变量。一种受限的访问。
2:可以让局部变量常驻内存,延长生命周期。
缺点:
1:对于局部变量的访问是受限的。
2:局部变量因为有函数的引用,所以常驻内存,堆内存是一种浪费。
需要删除闭包才能删除函数内访问的局部变量。
删除闭包。就是删除局部函数。将函数设置为null。
<script>
/*function test() {
var num = 10;
}
console.log (num);//num is not defined*/
//使用闭包来访问函数的局部变量
function fn() {
var num = 10;
//局部函数
function closure(val) {
num = val;
console.log (num);
}
//返回局部函数
return closure;
}
//定义变量接收返回的内部函数。
var closure = fn();
closure(15);
closure(100);
//删除闭包。
closure = null;
</script>
六、闭包练习
<ul>
<li>111</li>
<li>222</li>
<li>333</li>
<li>444</li>
<li>555</li>
</ul>
<script>
//一种错误的实现
var lis = document.querySelectorAll("li");
/*for (var i = 0; i <lis.length ; i++) {
lis[i].onclick = function () {
console.log (i);
}
}*/
//使用非闭包的实现 三种方式都可以
/*for (var i = 0; i <lis.length ; i++) {
//给每一个元素添加了一个属性,id属性。属性值为 0-4
lis[i].id = i;
// lis[i].onclick = function () {
// console.log (this.id);
// }
lis[i].onclick = function (e) {
e = e || window.event;
console.log (e.currentTarget.id);
console.log (e.target.id);
}
}*/
//闭包的实现
for (var i = 0; i <lis.length ; i++) {
//绑定的时候就执行函数函数,保存当前i的值。
//事件绑定的是函数的执行的结果,结果必须返回一个函数才可以。
lis[i].onclick = (function (index) {
console.log ("index == " + index);
var fun = function(){
console.log (index);
}
//点击每个li的时候,就执行每个li返回的函数 fun.
return fun;
})(i);
}
</script>
七、设计模式-工厂设计模式
设计模式:design patterns
概念:设计模式(Design pattern)代表了最佳的实践,通常被有经验的面向对象的软件开发人员所采用。设计模式是软件开发人员在软件开发过程中面临的一般问题的解决方案。这些解决方案是众多软件开发人员经过相当长的一段时间的试验和错误总结出来的。
1:工厂设计模式:解决的问题是批量生产对象。
<script>
//用于创建学生对象的工厂函数。
function studentFac(name,age,gender,score) {
var stu = {};
stu.name = name;
stu.age = age;
stu.gender = gender;
stu.score = score;
return stu;
}
var stu = studentFac("小刚",14,"男",100);
console.log (stu);
</script>
八、设计模式-单利设计模式
单例设计模式:singleton
单例设计模式解决的问题:对某种类型,只能创建该种类型的唯一的一个实例。
1:使用静态成员实现的单例模式。缺点:确保单例的静态属性很容易被覆盖掉。不安全。
2: 使用闭包实现。
<script>
var instace = {};
//使用静态成员实现单例模式
var Singleton = function (name, age) {
//静态成员是否存在。存在,直接返回。
if(Singleton.instance)
return Singleton.instance;
// 不存在,创建
Singleton.instance = this;
this.name = name;
this.age = age;
}
Singleton.prototype.setName = function (name) {
this.name = name;
}
Singleton.prototype.getName = function () {
return this.name;
}
var tom = new Singleton("TOM",3);
var jerry = new Singleton("JERRY",1);
var jerry1 = new Singleton("JERRY1",2);
jerry.setName("jerry");
console.log (Singleton.instance.getName());
console.log (tom === jerry);
//被暴露在外,很容易被修改。
Singleton.instance = null;
/
//具有唯一实例的类型。
var Single;
(function () {
//函数内的局部变量。它指向了惟一的类型的实例。
var instance;
Single = function (name) {
//已经创建。直接返回。
if(instance)
return instance;
//初始化instance
instance = this;
//绑定属性
this.name = name;
}
})();
var gang = new Single("小刚");
var ma = new Single("小马");
</script>
九、设计模式-观察者设计模式
观察者设计模式:observer
面对解决的是 1对多 的问题。
也称为订阅发布模式。
解决的问题:
1:实现多个对象之间的松耦合。
2:当某一个对象执行了某个操作,其他的多个对象都可以接收到通知。
3:被通知接收信息的对象的数量是开放的。
实例:HR 通知 若干个面试者的。
<script>
//隶属于某个公司的hr 。
// 属性:公司的名称,保存应聘者的信息的容器
// 功能:添加观察者、删除观察者、通知观察者。
function HR(name) {
this.name = name;
//保存应聘者的信息的容器
this.observers = [];
}
//HR的原型对象中添加上述的功能。
HR.prototype.addObserver = function (obs) {
this.observers.push(obs);
}
//删除观察者
HR.prototype.removeObserver = function (obs) {
var observers = this.observers;
//遍历所有的应聘者,相同的删除掉。
for (let i = 0; i < observers.length; i++) {
if(observers[i] === obs){
var removeObserver = observers.splice(i,1)[0];
removeObserver.update(removeObserver.name+"先生/女士:很遗憾,希望以后有合作的机会!");
}
}
}
//通知所有的观察者
HR.prototype.notify = function () {
//遍历所有的观察者,执行更新的方法
var observers = this.observers;
for (let i = 0; i < observers.length; i++) {
observers[i].update(observers[i].name + "\t恭喜先生/女士:下周来"+this.name + "上班");
}
}
//面试者,观察者。 功能就是接收信息。
function Observer(name) {
this.name = name;
}
/**
* //接收更新通知的方法
* @param msg 接收到的信息
*/
Observer.prototype.update = function (msg) {
console.log (msg);
}
var hr = new HR("JD");
var gang = new Observer("小刚");
var ma = new Observer("小马");
var bai = new Observer("小白");
hr.addObserver(gang);
hr.addObserver(ma);
hr.addObserver(bai);
//删除小马
hr.removeObserver(ma);
//通知其他人
hr.notify();
//前面学习的事件处理,就是观察者模式。
document.body.addEventListener("click",function () {
console.log ("body click")
},false);
document.addEventListener("click",function () {
console.log ("document click")
},false);
document.body.click();
</script>