9.5 面向对象-原型和原型链
什么是原型对象
function Student(name,adderss){// 构造属性this.name = name;this.age = age;this.address = address;// 构造方法this.say = function(){console.log('我是',this.name,'我来自'+this.address);}
}
var one = new Student('Jack',19,'郑州');
var two = new Student('Rose',15,'郑州');
总结:new一个实例话对象经历的四个阶段:
-
创建一个空的实例化对象
-
让构造函数中的this指向空的实例化对象
-
执行(调用)构造函数,从而创建实例化对象自身的属性和方法
-
返回实例化对象
原型对象prototype(理解)
function Person(name,age){this.name=name;this.age=age;this.say=function(){alert('我偷偷告诉你:'+this.name+"今年"+this.age+'岁了');}
}
var p1 = new Person('jack',20); // 作为构造函数调用
p1.say();
var p2 = new Person('Rose',26); // 作为构造函数调用
p1.say();
![[1280X1280 (6).PNG]]
总结:
原型对象:所有的构造函数在初始化时,都会自动生成一个特殊的实例话对象,构造函数的prototype属性指向该对象,该对象称为原型对象,或prototype对象
proto__对象:所有构造函数new出来的实例话对象,都有一个__proto__属性,该属性指向构造函数的原型对象,原型对象也有自己的__proto__属性,指向上一级构造函数的原型对象,proto__会一直找到Object的原型对象,object原型对象的__proto__指向null
原型链:由一系列__proto__属性,串联起来的原型对象,称为原型链
原型链的意义:实例化对象在访问属性和方法时,会先访问自身的属性和方法,如果自身不存在对应的属性和方法,则会自动通过__proto__属性在整个原型链上查找,只要找到对应的属性和方法,就能正确执行,如果原型链上没找到,则报错
__proto__会一直找到Object
注意:构造函数本身是Function对象new出来的实例话对象,所以构造函数Studnet也有 proto ,指向Function的原型对象(Function.protytype); 而Function.protytype的 proto **指向Object.prototype **但是:**student这个构造函数new出来的实例话对象的原型链上并没有Function.prototype
面试题:什么是原型对象?什么是原型链?
原型对象:所有的构造函数在初始化的时候,会自动生成一个特殊的实例化对象,构造函数的prototype属性会指向该对象,该对象就被称为原型对象,或者prototype对象
什么是原型链:由一些列__proto__对象,串联起来的原型对象,称为原型链
![[ad19e6ab-274f-4874-8f84-985f3634ad82.png]]
原型链案例
给数组对象添加一个新的方法,实现去重
1)构建一个新的数组存放结果
2)for循环中每次从原数组中取出一个元素,用这个元素循环与结果数组对比
3)若结果数组中没有该元素,则存到结果数组中
Array.prototype.unique1 = function () {var res = [this[0]]; // 结果数组for (var i = 1; i < this.length; i++) {var repeat = false;for (var j = 0; j < res.length; j++) {if (this[i] == res[j]) {repeat = true;break;}}if (!repeat) {res.push(this[i]);}}return res;
}
var arr = [1, 'a', 'a', 'b', 'd', 'e', 'e', 1, 0];
alert(arr.unique1());
程序题
for(var i = 0; i < 10; i++){//回调函数: 做为参数传入的函数称为回调函数setTimeout(function(){ //异步/延时操作console.log(i,'inner');},0);
}
console.log(i,'outer');
程序题
var x = 1234;
function test(){var x = 4567;console.log(this.x);
}
test();
var testObj = new test();
var o = {};
o.x = 5678;
o.m = test;
o.m();
程序题
// 函数声明优先: 如果普通变量和函数名冲突,最终变量中存储的是函数
function Foo() {getName = function () {console.log(1);};return this;
}
Foo.a=0; //静态变量
Foo.getName = function () { // 静态方法//在构造函数上添加一个属性(因为函数也是对象)console.log(2);
};
Foo.prototype.getName = function () { console.log(3); };
var getName = function () { console.log(4); };
function getName() {console.log(5);
}
Foo.getName();
getName();
Foo().getName();
getName();
new Foo().getName();
解析:静态属性不能被实例对象调用,即通过以new 操作符实例化后的对象调用,如上例中的a调用,只能通过类名调用,即Foo调用.也就是挂载在函数自身上的方法 本质上静态方法是定义在类上的,可以通过类名来访问,在静态方法中 this 是指向类本身,类实际上就是一个函数,一个构造器。
程序分析题
// 自定义对象的实例化对象,原型链上没有Function.prototype
// 而所有的函数实例化对象,_proto_属性指向Function.prototype, 而Function.prototype的_proto_属性指向Object.prototype
var F = function(){};
Object.prototype.a = function(){ console.log("hello")};
Function.prototype.b = function(){console.log("word")};
var f = new F();
var f1 = f.a;
f1();
var f2 = f.b;
// f2();
var f3 = F.a;
f3();
var f4 = F.b;
f4();
程序分析题
function A(){};
function B(a){ this.a = a};
function C(a){ if(a){this.a = a;}}
A.prototype.a = 1;
B.prototype.a = 1;
C.prototype.a = 1;
console.log( new A().a);
console.log( new B().a);
console.log( new C(2).a);
程序分析题
function Cat(name,color){this.name = name;this.color = color;
}
Cat.say = function(){console.log(this.name1);
}
Cat.name1 = "kmf";
var cat1 = new Cat('cat1','white');
cat1.say();
Cat.say();
// 1. 执行new的时候this指什么
// 2.cat1.say()输出什么?
// 3.Cat.say() 输出什么?
案例:使用构造函数+原型实现气泡效果
![[a401d4a9-04ce-4106-a8ae-8e3a9a799a07.png]]
JS的垃圾回收(GC)机制
程序运行过程中会产生垃圾,这些垃圾积攒过多以后,会导致程序运行的速度过慢。所以我们需要一个垃圾回收的机制,来处理程序运行过程中产生垃圾。 当一个对象没有任何的变量或属性对它进行引用时,此时我们将永远无法操作该对象,此时这种对象就是一个垃圾,这种对象过多会占用大量的内存空间,导致程序运行变慢,所以这种垃圾必须进行清理。 上面这句话,也可以这样理解:如果堆内存中的对象,没有任何变量指向它时,这个堆内存里的对象就会成为垃圾。 JS拥有自动的垃圾回收机制,会自动将这些垃圾对象从内存中销毁。我们不需要也不能进行垃圾回收的操作。我们仅仅需要做的是:如果你不再使用该对象,那么,将改对象的引用设置为 null 即可。
一道题理解原型和原型链
Object.prototype是一个对象,用于表示Object的原型对象 几乎所有的JS对象都是Object的实例
-
prototype原型对象:是函数才有的属性
-
函数的__proto__都指向Function.prototype
-
__proto__内部原型,是对象才有的属性
-
对象由函数(构造器)生成
实例对象的__proto__属性
指向构造函数的prototype属性 即:__proto__表示的是,实例与(构造函数的原型)之间的关系
var fn = function(){this.f = "fn"
}
Object.prototype.a = function(){console.log('aaa')
}
Function.prototype.b = function(){console.log('bbb')
}
var f = new fn();
f.a() // 有没有a()
fn.a() // 有没有a()
fn.b() // 有没有a()
// console.log(f); 实例对象
// console.log(f.__proto__);
// console.log(f.__proto__.__proto__);
// console.log(Object.prototype);
// console.log(Object.prototype == f.__proto__.__proto__);
// console.log(f.__proto__.__proto__.a);
![[83689ba9-6c5d-4edf-a187-48872a0fcb55.png]]