首页 > 作文

JS:构造函数继承原型链

更新时间:2023-04-03 12:50:32 阅读: 评论:0

js:构造函数 继承 原型链

创建构造函数

//1.定义一个构造函数

function obj(a) {

this.a = a || ‘a’;

}

console.dir(obj.prototype.constructor);// obj(函数自身)

/*——-构造函数的prototype.constructor应指向函数自身——-*/

//2.在该构造函数的原型中 定义该构造函数创建的所有对象都会继承的公共方法

obj.prototype.geta = function() {

return this.a;

}

var o1 = new obj(‘1’);

console.log(o1.geta()) // ‘1’

继承内部属性和方法

function obj(a, b) {

//通过改变父类构造函数的执行上下文,继承父类构造函数中定义的属性

obj.call(this, a);

this.b = b;

}

var o2 = new obj(‘2’, [‘a’,’b’]);

console.log(o2.geta()); // 报错

由于geta方法被定义在obj.prototype中,call方法只能使obj调用obj内部定义的方法,故obj.prototype中定义的方法没有被obj继承。要解决此问题可以将geta定义在obj对象内部,但是这样会在每一个实例中创建一个geta方法,对于公用函数来说这样做显然会造成资源浪费,将公共方法定义在构造函数的原型中来继承则更加适合。

构造函数结合原型继承

继承prototype中属性和方法

//通过将prototyp三个代表e指向父级创建的实例,继承父类构造函数prototype中定义的方法

obj.prototype = new obj(); //此时obj.prototype.constructor 为 obj

obj.prototype.constructor = obj; //修正constructor指向为obj函数自身,避免修改原型链时造成的constructor丢失

var o3 = new obj(‘3’, [‘a’,’b’]);

console.log(o2.geta()); //’3′

注意 obj.prototype = new obj()与obj.prototype = obj.prototype的区别:

前者将obj的prototype指向了obj创建的一个实例,该实例的__proto__指向obj.prototype(通过new创建的对象,其__proto__总是指向其构造函数的prototype)

后者将obj和obj的prototype指向同一个原型对象,如果定义子构造函数的prototype中的属性或方法将影响到父级。

构造函数在实例化对象时,每一个子类都将调用一次父类构造函数。

上面代码中

obj.prototype = new obj();

可写作

obj.prototype = (function() {

function o() {}

o.prototype = obj.prototype;

return new o();

})();

封装成继承函数

//继承函数

function extend(son, father) {

function f() {}

f.prototype = father.prototype;

son.prototype = 栀子花的养殖方法和注意事项new f();

son.prototype.constructor = son;

}

这样在创建obj实例时,减少了对父类的构造函数的调用次数,在继承层级较多时,可以减少内存占用。

使用这种继承方式时要尽量减少继承层级,参考下面例子,创建一个e对象实例共调用5次父级构造函数。

//a类

function a() {

console.log(‘a()’);

}

a.prototype.print = function() {

console.log(‘msg’);

}

//b类

function b() {

a.call(this);

console.log(‘b()’);

}

extend(b, a);

//c类

function c() {

b.call(this);

console.log(‘c()’);

}

extend(c, b);

//d类

function d() {

c.call(this);

console.log(‘d()’);

}

extend(d, c);

//e类

function e() {

d.call(this);

console.log(‘e()’);

}

extend(e, d);

//创建一个e的实例

var e = new e(); //a() b() c() d() e()

e.print(); //msg.

构造函数继承对象

在前面的继承中,是将子构造函数的prototype指向父构造函数的实例,下面的代码会将一个构造函数的prototype指向一个对象,并用该构造函数创建实例。

//继承函数

function clone(object) {

function f() {}

f.prototype = object;//指定一个对象

return new f();

}

//父级

var obj1 = {

a: ‘a’,

geta: function() {

return this.a;

}

}

//子级

var obj2 = clone(obj1);

obj2.b = [‘b’];

obj2.getb = function() {

return this.b.join(‘,’);

}

//创建实例1

var obj1 = clone盖茨比为什么了不起(obj2);

obj1.b.push(‘b1’);

//创建实例2

var obj2 = clone(obj2);

obj2.b.push(‘b2’);

console.log(obj1);//b,b1,b2

console.log(obj2);//b,b1,b2

console.log(obj2);//b,b1,b2

使用这种继承方式时,创建的所有实例虽然会返回一个新对象,但其引用和父级指向同一个内存地址,只有重新赋值时才会分配新的内存地址,如果直接操作其修改会影响到父级。

//创建实例1

var obj1 = clone(obj2);

obj1.b = [];

obj1.b.push(‘b1’);

//创建实例2

var obj2 = clone(obj2);

obj2.b = [];

obj2.b.push(‘b2’);

console.log(obj2);//b

console.log(obj1);//b1

console.log(obj2);//b2

原型继承和原型链

new关键字只能对(构造)函数使用,如果要继承的目标是一个对象需要通过设置prototype来实现,而且在存在操作实例时影响父级的风险。使用object.create()方法可以以一个对象为目标来创建一个新对象,并实现继承。

var obj = {

name:’name’,

printname:function(){

console.log(this.name)

}

}

//var obj2 = new obj1();//报错,

//new关键字只能用function(构造函数)来new对象,不能直接用对象来new对象

var obj1 = object.create(obj);

obj1.考研政治满分多少name1 = ‘name1’;

console.dir(obj1);//{name1:’name1′},obj1内部没有name属性,只有name1属性

obj1.printname();//name,obj继承并能够调用printname方法和读取name属性

console.dir(obj2.prototype);//undefined

//所有索引对象(array object function)都有__proto__,只有function对象才有prototype

console.dir(obj2.__proto__);//obj对象{name:’name’,printname:function(){console.log(this.name)}}

//object.create()方法创建的对象其原型指向创建的目标对象

使用object.create()方法可以实现多重继承。

var obj = {

name:’name’,

print:function(key){

console.log(this[key])

}

}

var obj1 = object.create(obj);

obj1.name1 = ‘name1’;

var obj2 = object.create(obj1);

obj2.name2 = ‘name2’;

obj2.print(‘name’);//name

obj2.print(‘name1’);//name1

ob2018放假安排j2.print(‘name2’);//name2

console.dir(obj2);//{name2:’name2′}

//obj2内部没有name属性,只有name2属性,但继承了obj1和obj的属性和方法

console.dir(obj2.__proto__);//obj1对象

console.dir(obj2.__proto__.__proto__);//obj对象

console.dir(obj2.__proto__.__proto__.__proto__);//object对象

console.dir(obj2.__proto__.__proto__.__proto__.__proto__);//null

//所有对象的原型最终都会指向object对象,object对象原型为null

由于object.create()创建的对象原型直接指向父级,所以父对象修改会影响子对象,而子对象修改无法影响父对象。

注意object.create方法不管参数是对象还是构造函数,都只能创建出对象。

如果创建的目标是函数,则创建结果是__proto__指向目标函数的空对象({ } ,不会报错)

在前面已经多次涉及原型链知识,再提一下

var func0 = function(){

this.name0 = ‘func0’;

}

func0.prototype.print0 = function(){

console.log(this.name0);

}

console.dir(func0.prototype); //{print0:function(){console.log(this.name0)}}原型对象

console.dir(func0.prototype.constructor);//func0

//函数的prototype.constructor默认指向该函数自身

var func1 = function (){

this.name1 = ‘func1’

func0.call(this);

}

func1.prototype = new func0();

func1.prototype.print1 = function(){

console.log(this.name1);

}

console.dir(func1.prototype); //func0实例对象

console.dir(func1.prototype.constructor);//func0 由于将原型指向了func0实例,导致构造器指向func0

func1.prototype.constructor = func1;

//手动将构造器指向修正回函数自身,可以确保由fun1创建的实例instanceof为fun1,避免造成instanceof失真

console.dir(func1.prototype.__proto__);//{print0:function(){console.log(this.name0)}}原型对象

//由于func1.prototype为func0实例,故func1.prototype.__proto__指向func0.prototype

//通过new创建的对象,其__proto__总是指向其构造函数的prototype

console.dir(func1.__proto__);//function对象

//func1是通过new function()创建实例,function构造函数对象的prototype是function对象

console.dir(func1.__proto__.__proto__);//object对象

//所有引用类型数据原型都是原自object对象

//function对象的构造函数的prototype是object对象

console.dir(func1.__proto__.__proto__.__proto__);//null

//已经查找到原型链终点,即object对象的__proto__为null

本文发布于:2023-04-03 12:50:31,感谢您对本站的认可!

本文链接:https://www.wtabcd.cn/fanwen/zuowen/ccbe30ca6938e427cb2a0e54c9ae87a3.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

本文word下载地址:JS:构造函数继承原型链.doc

本文 PDF 下载地址:JS:构造函数继承原型链.pdf

标签:对象   函数   原型   实例
相关文章
留言与评论(共有 0 条评论)
   
验证码:
Copyright ©2019-2022 Comsenz Inc.Powered by © 专利检索| 网站地图