Javascript基础回顾之(三) js面向对象(3)

也就是说他们内存堆中是存在多份拷贝的,而不是在栈中引用地址的拷贝。先不说这符不符合面向对象的思想,至少这对于内存来说也是一种浪费。而解决办法就是我们要讨论的原型。

什么是原型

  在Javascript中的每一个函数,都会有一个原型对象,这个原型对象和我们普通的对象没有区别。只不过默认会有一个constructor属性指向这个函数。 同时,所有这个函数的实例都会有一个引用指向这个原型对象。如果不太清楚,那就看看下面这张图吧:

Javascript基础回顾之(三) js面向对象

以上就是构造函数,构造函数原型,以及实例之间的关系。以我们的Person构造函数为例,所有Person的实例(p1,p2)都舒服一个prototype属性指向了Person构造函数prototype对象。如此一来,我们就可以把方法写在原型上,那么我们所有的实例就会访问同一个方法了。

function Person(name, age, job) { this.name = name; this.age = age; this.job = job; Person.prototype.sayName = function () { alert(this.name); } } var p1 = new Person('Jesse', 18, 'coder'); var p2 = new Person('Carol', 17, 'designer'); alert(p1.sayName == p2.sayName); // true

什么是原型链

  大家还记得作用域链么?如果不记得,请自觉到第二篇中去复习(作用域和作用域链)。简单的来说,我们在一个执行环境中访问某个变量的时候如果当前这个执行环境中不存在这个变量,那么会到这个执行环境的包含环境也就是它的外层去找这个变量,外层还找不到那就再外一层,一直找到全局执行环境为止,这就是作用域链。而原型链有点类型,只不过场景换到了我们的对象实例中,如果我在一个实例中找某一个属性,这个实例中没有,那就会到它的原型中去找。记住,我们上面说了,原型也是一个对象,它也有自己的原型对象,所以就行成了一个链,实例自己的原型中找不到,那就到原型的原型对象中去找,一直向上延伸到Object的原型对象,默认我们创建的函数的原型对象它自己的原型对象是指向Object的原型对象的,所以这就是为什么我们可以在我们的自定义构造函数的实例上调用Object的方法(toString, valueOf)。

Javascript基础回顾之(三) js面向对象

利用原型实现继承

  其实我们上面已经讲了继承在Javascript中的实现,主要就是依靠原型链来实现的。所有的实例是继承自object就是因为在默认情况下,我们所有创建函数的原型对象的原型都指向了object对象。同理,我们可以定义自己的继承关系。

function Person(name, age, job) { this.name = name; this.age = age; } Person.prototype.sayName = function () { alert(this.name); } function Coder(language){ this.language = language; } Coder.prototype = new Person(); //将 Coder 的原型指向一个Person实例实现继Person Coder.prototype.code = function () { alert('I am a '+ this.language +' developer, Hello World!'); } function Designer() { } Designer.prototype = new Person(); //将 Desiger 的原型指向一个Person实例实现继Person Designer.prototype.design = function () { alert('其实我只是一个抠图工而已。。。。'); } var coder = new Coder('C#'); coder.name = 'Jesse'; coder.sayName(); //Jesse coder.code(); // I am a C# developer, Hello World! var designer = new Designer(); designer.name = 'Carol'; designer.sayName(); // Carol designer.design(); // 其实我只是一个抠图工而已。。。。

原型链中的问题

  由于原型对象是以引用的方式保存的,所以我们在赋值的时候要特别注意,一不小心就有可能把之前赋的值给赋盖了。比如上面的代码中,我们先写原型方法,再实现继承,那我们的原型方法就没有了。

function Coder(language){ this.language = language; } Coder.prototype.code = function () { alert('I am a '+ this.language +' developer, Hello World!'); } Coder.prototype = new Person(); //这里会覆盖上面所有的原型属性和方法 var coder = new Coder('C#'); coder.name = 'Jesse'; coder.sayName(); coder.code(); // 这里会报错,找不到code方法。

这样三篇文章都完成了

您可能感兴趣的文章:

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wwgspz.html