首页 > IT职业 > IT图书 > 面试中聊到的javascript中的继承
面向对象编程是每次面试必问的知识点,而前端js如何实现继承每次命中率高达80%
这不,近两天我们面试时候,同事就问道面试者此问题,但是,不论之前自己做的回答,还是面试者的回答,基本都不太令人满意
很大的原因是多数时候前端并不需要实现继承,就jquery来说也基本上是一码到底,没有实现继承,据我所知,也就prototype与ext实现过继承
所以继承对前端来说似乎不太适用
近两年来情况有所变化,SPA的兴起以及前端逻辑的复杂化,让前端代码愈发的多,愈发的重,所以继承慢慢的进入了一些初级一点的前端视野
所以,好好的了解如何实现继承,继承的几个用法,是非常有意义的,就算只是为面试都是很有用的
当一个函数被创建时,Function构造函数产生的函数会隐式的被赋予一个prototype属性,prototype包含一个constructor对象
而constructor便是该新函数对象(constructor意义不大,但是可以帮我们找到继承关系)
每个函数都会有一个prototype属性,该属性指向另一对象,这个对象包含可以由特定类型的所有实例共享的属性和方法
每次实例化后,实例内部都会包含一个[[prototype]](__proto__)的内部属性,这个属性指向prototype
① 我们通过isPrototypeOf来确定某个对象是不是我的原型 ② hasOwnPrototype 可以检测一个属性是存在实例中还是原型中,该属性不是原型属性才返回true
var Person = function (name, age) {
this.name = name;
this.age = age;
};
Person.prototype.getName = function () {
return this.name;
};
var y = new Person('叶小钗', 30);

通俗一点来说,prototype是一模板,新创建对象就是对他一个拷贝,里面的属性或者方法都会赋值给实例
这里说是模板赋值其实不太合理,反正由类产生的所有实例的__proto__都会共享一个prototype,这里我做一个例子
我们在断点情况下是没有name2属性的,但是我们如果在断点下加上这个代码的话,a.name2,就有值了
Klass.prototype.name2 = '222';


所以,这里说模板,不如说是指针指向,都是共享一个对象;继承的情况的话就是这样
(function () {
var Person = function (name) {
this.name = name;
};
//Person.prototype = {};//这句将影响十分具有constructor属性
Person.prototype.getName = function () {
return this.name;
};
var Student = function (name, sex, id) {
this.name = name || '无名氏';
this.sex = sex || '不明';
this.id = id || '未填'; //学号
};
//相当于将其prototype复制了一次,若是包含constructor的话将指向Person
Student.prototype = new Person();
Student.prototype.getId = function () {
return this.id;
}
var y = new Person();
var s = new Student;
var s1 = y instanceof Person;
var s2 = s instanceof Student;
var s3 = s instanceof Person;
var s4 = Student.prototype.constructor === Person;
var s5 = Student.constructor === Person;
var s6 = Student.constructor === Function;
var s = '';
})();
我们在具体项目中,真正复杂一点的项目可能就会对继承进行封装,让自己更好的使用,我们下面就来看看prototype怎么干的
PS:我这里做了一点小的修改:
1 var Class = (function () {
2 function subclass() { };
3
4 //我们构建一个类可以传两个参数,第一个为需要继承的类,
5 //如果没有的话就一定会有第二个对象,就是其原型属性以及方法,其中initialize为构造函数的入口
6 function create() {
7
8 //此处两个属性一个是被继承的类,一个为原型方法
9 var parent = null;
10 var properties = $A(arguments);
11
12 if (Object.isFunction(properties[0]))
13 parent = properties.shift();
14
15 //新建类,这个类最好会被返回,构造函数入口为initialize原型方法
16 function klass() {
17 this.initialize.apply(this, arguments);
18 }
19
20 //扩展klass类的“实例”对象(非原型),为其增加addMethods方法
21 Object.extend(klass, Class.Methods);
22
23 //为其指定父类,没有就为空
24 klass.superclass = parent;
25
26 //其子类集合(require情况下不一定准确)
27 klass.subclasses = [];
28
29 //如果存在父类就需要继承
30 if (parent) {
31 //新建一个空类用以继承,其存在的意义是不希望构造函数被执行
32 //比如 klass.prototype = new parent;就会执行其initialize方法
33 subclass.prototype = parent.prototype;
34 klass.prototype = new subclass;
35 parent.subclasses.push(klass);
36 }
37
38 //遍历对象(其实此处这样做意义不大,我们可以强制最多给两个参数)
39 //注意,此处为一个难点,需要谨慎,进入addMethods
40 for (var i = 0, length = properties.length; i 下面来一个简单的例子:
1 var Person = Class.create({
2 initialize: function (name) {
3 this.name = name;
4 },
5 getName: function () {
6 console.log('我是父类');
7 return this.name;
8 },
9 getAge: function () {
10 return this.age;
11 }
12 });
13
14 var Employee = Class.create(Person, {
15 initialize: function ($super, name, age) {
16 $super(name);
17 this.age = age;
18 },
19 getName: function ($super) {
20 return '我是子类:' + $super();
21 }
22 });
23
24 var C = Class.create(Employee, {
25 getAge: function ($super) {
26 return $super();
27 }
28 });
29
30 var y = new C("叶小钗", 25);
31 console.log(y.getName() + ': ' + y.getAge());这里,我们根据自己的需求重写写了下继承相关代码,表现基本与上述一致,各位可以自己试试
PS:当然如果有问题请指出
简化prototype继承
1 var arr = [];
2 var slice = arr.slice;
3
4 function create() {
5 if (arguments.length == 0 || arguments.length > 2) throw '参数错误';
6
7 var parent = null;
8 //将参数转换为数组
9 var properties = slice.call(arguments);
10
11 //如果第一个参数为类(function),那么就将之取出
12 if (typeof properties[0] === 'function')
13 parent = properties.shift();
14 properties = properties[0];
15
16 function klass() {
17 this.initialize.apply(this, arguments);
18 }
19
20 klass.superclass = parent;
21 klass.subclasses = [];
22
23 if (parent) {
24 var subclass = function () { };
25 subclass.prototype = parent.prototype;
26 klass.prototype = new subclass;
27 parent.subclasses.push(klass);
28 }
29
30 var ancestor = klass.superclass && klass.superclass.prototype;
31 for (var k in properties) {
32 var value = properties[k];
33
34 //满足条件就重写
35 if (ancestor && typeof value == 'function') {
36 var argslist = /^s*functions*(([^()]*?))s*?{/i.exec(value.toString())[1].replace(/s/i, '').split(',');
37 //只有在第一个参数为$super情况下才需要处理(是否具有重复方法需要用户自己决定)
38 if (argslist[0] === '$super' && ancestor[k]) {
39 value = (function (methodName, fn) {
40 return function () {
41 var scope = this;
42 var args = [function () {
43 return ancestor[methodName].apply(scope, arguments);
44 } ];
45 return fn.apply(this, args.concat(slice.call(arguments)));
46 };
47 })(k, value);
48 }
49 }
50
51 klass.prototype[k] = value;
52 }
53
54 if (!klass.prototype.initialize)
55 klass.prototype.initialize = function () { };
56
57 klass.prototype.constructor = klass;
58
59 return klass;
60 }如此,我们就完成了自己的继承了
实战继承
知道原型可以实现继承是皮毛,知道各个库是怎样干的也只是入门
因为,要在项目中用到才能算真正掌握继承,这里我们便来点实战的小例子
这里我写一个简单的view用于下面各种继承
1 var AbstractView = create({
2 initialize: function (opts) {
3 opts = opts || {};
4 this.wrapper = opts.wrapper || $('body');
5
6 //事件集合
7 this.events = {};
8
9 this.isCreate = false;
10
11 },
12 on: function (type, fn) {
13 if (!this.events[type]) this.events[type] = [];
14 this.events[type].push(fn);
15 },
16 trigger: function (type) {
17 if (!this.events[type]) return;
18 for (var i = 0, len = this.events[type].length; i 这里是alert框
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/4479/viewspace-2800757/ ,如需转载,请注明出处,否则将追究法律责任。