JavaScript继承指迷

2016-10-28  本文已影响47人  Airsola

以下是 廖雪峰老师 JavaScript 教程的笔记 ,这个章节有点大雾,这里记录一下

先硬广 安利一下

小A和小B都是应届毕业生,一起进入了一家互联网公司做前端。半年过去了,小A进步神速,他写的JavaScript代码在组里挑剔的的老员工看来都挺不错:

可读性好,模块化程度高,而且有大量的测试。反观小B,他的代码总是一团糟,还经常搞出莫名其妙的bug。每次做code review时,大家对小B的代码都特别头疼。

年底考核的时候,组长让小A分享一下他入职以来是怎么学习前端并快速成长的,小A不好意思地给大家分享了自己的一点学习心得:

首先,前端工程师必须得熟练掌握HTML、CSS和JavaScript。只懂其中一个或两个不行,必须对这三个都很熟悉,尤其是JS。

很多前端工程师还把对JS的认识停留在用jQuery做网页动画的时代,这个认识早就落后了,现在JS不仅负责前端的所有页面逻辑,还能利用Node开发后端服务。

而JS并没有看上去那么简单,它入门容易精通难,尤其是自己摸索,或者在网上随便搜索一些代码片断,很容易被带进沟里。学JavaScript应该学到精髓,还应该知道JS不好的设计,并且有意识地只用JS优秀的设计。

由于JS最近随着HTML5的兴起有了很大的更新,网上很多教程或者资料都过时了,现在应该用ES 6标准来写代码。即使不做后端,也要对Node非常熟悉,因为前端的自动化也是基于Node和npm实现的。

小A说了这么多,组长觉得很惊讶,说,“我看你平时也没怎么与老员工探讨前端技术问题,怎么懂得这么多?知识体系还挺丰富!”

小A不好意思地说,“其实我刚进公司的时候也是啥也不会,纯小白一个,偶然听一个朋友推荐看到了廖雪峰老师的网站,里面有非常系统的JavaScript全栈教程,讲的重点都是JS的精髓,还特别指出容易出错的坑。廖老师的教程更新很快,我每天都花半个小时上去学一点,几个月下来也积累了不少。”

组长用自己的笔记本搜索了小A说的廖雪峰老师的网站,看了几页,说:“小A啊,这么好的JS教程,你怎么藏着掖着,不早点分享给大家呢?你这个做法不厚道,今晚团队聚餐的费用必须你出。”

小A一脸懵逼……

友情提示:小A提到的神奇的JavaScript全栈教程哪里找?猛戳这里**有惊喜!

创建对象

构造函数

为了区分普通函数和构造函数,按照约定,构造函数首字母应当大写,而普通函数首字母应当小写

function Student(name) {
    this.name = name;
    this.hello = function () {
        alert('Hello, ' + this.name + '!');
    }
}

搭配 new 使用默认 自动返回 this

var xiaoming = new Student('小明');
xiaoming.name; // '小明'
xiaoming.hello(); // Hello, 小明!

var xiaohong = new Student('小红');
xiaohong.name; // '小明'
xiaohong.hello(); // Hello, 小明!

比较两个Student

这里new 出来的 Student 的 Hello 方法不是复用! 用其他语言的角度来看同一个类new出来的对象居然各自持有方法,真的是 泥垢了

xiaoming.hello === xiaohong.hello;//false

重写Student的构造函数

function Student(name) {
    this.name = name;
}

Student.prototype.bioName = "智人";

Student.prototype.hello = function () {
    alert('Hello, ' + this.name + '!');
};

var xiaoming = new Student('小明');
var xiaohong = new Student('小红');

//这里可以看出复用方法了 公用的东西应该放到 prototype 里面
xiaoming.hello === xiaohong.hello;// true  
xiaoming.bioName === xiaohong.bioName; //true



xiaoming.bioName; //"智人"
xiaohong.bioName; //"智人"

xiaoming.bioName = "尼安德特人"
xiaoming.bioName; //"尼安德特人"
xiaohong.bioName; //"智人"  震惊了 这个bioName 不是共享的 按照道理来说应该是共用 prototype 的一个属性的那?

xiaoming.bioName === xiaohong.bioName; //false 这里居然显示出来结果

xiaoming.hasOwnProperty("name")// true
xiaoming.hasOwnProperty("bioName")// true  !!! 看来是 小名赋值之后给自己天降了个 bioName  

xiaoming;
Student.prototype;
//果然可以看出 prototype 里面的 bioName 依然是"智人",而xiaoming是新增bioName属性

原型继承


function Student(props) {
    this.name = props.name || 'Unnamed';
}

Student.prototype.hello = function () {
    alert('Hello, ' + this.name + '!');
}

//首先在构造函数中相互调用
function PrimaryStudent(props) {
    // 调用Student构造函数,绑定this变量:
    Student.call(this, props);
    this.grade = props.grade || 1;
}

这个时候对于PrimaryStudent 原型链条是,看上去和Student没啥关系

var Reimu = new PrimaryStudent({name :"Reimu"});
QQ20161028-0.png

new PrimaryStudent() ----> PrimaryStudent.prototype ----> Object.prototype ----> null

 Student.prototype
QQ20161028-4.png
PrimaryStudent.prototype
QQ20161028-5.png

这个两个家伙各自指向自家


接下来就像是链表插值这类东西的

QQ20161028-6.png

来一个空函数F 桥接用 我们最终想实现下面这样的效果

大象塞冰箱分三步 我们狸猫换太子 也走三步 搭四根线

function F() {
}
QQ20161028-1.png
// 把F的原型指向Student.prototype:  这里看上去是一步实际上搭上了两根线
// F ->  原型对象
// F ->  原型对象
F.prototype = Student.prototype;

QQ20161028-2.png
// 把PrimaryStudent的原型指向一个新的F对象,F对象的原型正好指向Student.prototype:
搭一根线   PrimaryStudent -> new F()
PrimaryStudent.prototype = new F();
QQ20161028-3.png
// 把PrimaryStudent原型的构造函数修复为PrimaryStudent:
搭上最后一根线
new F() -> PrimaryStudent
PrimaryStudent.prototype.constructor = PrimaryStudent;

四根线搭上 原来 PrimaryStudent.prototype 指向的 无名原型对象已经被彻底的抛弃了 new F() 已经上位了,取代了无名 原型对象

function inherits(Child, Parent) {
    var F = function () {};
    F.prototype = Parent.prototype;
    Child.prototype = new F();
    Child.prototype.constructor = Child;
}

就这样JavaScript终于打肿脸充胖子一样的实现了继承

上一篇下一篇

猜你喜欢

热点阅读