前端,js原型链(一)
HTML
-
html元素嵌套问题:
- 元素嵌套:块元素可以包含内联元素或某些块元素,但内联元素却不能包含块级元素,只能包含其他的内联元素。
- P元素嵌套问题 :
实际结果:<p> <div></div> </p>
通过查询,发现原来p元素内无法包裹块级元素。因为我们使用的DTD规定了块级元素是不能放在里面的。
- 内联元素:其实再内联元素中,还是可以区分一下的,有几个元素<img>、<input>比较特别,它们可以定义宽高。虽然在IE浏览器里,所有元素都可以定义宽高,但是IE自己的标准,并非所有浏览器都支持。W3C称他们为replaced元素,其实就是行内块,虽然这些元素属于Inline,但却具体有一定的block(可以设置宽高),因此我们可以赋予任何元素css属性
display:inline-block
。本身具有inline-block的元素应该没有
-
html的行级标签和块级标签
- 块级标签(独占一行,不和其他元素同一行)
- 常见块级标签:form、div、p、ul、li、h1~h6、dl、dd
- 行级标签(和其他元素同一行,不能设置宽高)
- 常见块级标签:a、span、strong、u、em
- 块级标签(独占一行,不和其他元素同一行)
-
HTML语义化
- 理解:用正确的标签做正确的事
- 例如:段落用p标签,标题用h系列标签,边栏用aside标签,主要内容用main标签
- 为什么要关注语义化:
- 便于团队的开发与维护
- 在没有加载CSS的情况下也能呈现较好的内容结构与代码结构,易于阅读。
- 有利于SEO,利于搜索引擎的爬虫依赖来确定上下文的各关键字的权重
CSS
- 子元素浮动,如何消除父元素坍塌情况
- 在父元素设置overflow:hidden
- 为父元素设置高度撑开(height)
- 在浮动元素中最后一个兄弟元素设置clear:both(需块级元素)
JS
- 继承,封装
- js继承共分为5种:构造函数式继承、原型链链式继承、组合式继承、寄生式继承和寄生组合式继承
-
构造函数式继承:
function Flower() //构造函数 { this.colors = ['黄色', '红色']; this.print = function () { console.log(this.colors) } } function Rose() { Flower.call(this); } var r1 = new Rose(); var r2 = new Rose(); console.log(r1.print()); // [ '黄色', '红色' ] console.log(r2.print()); // [ '黄色', '红色' ]
我们现在有一个基类Flower,它有一个属性colors,现在我们把某一个实例的colors值改一下:
r1.colors.push('紫色'); onsole.log(r1.print()); // [ '黄色', '红色', '紫色' ] console.log(r2.print()); // [ '黄色', '红色' ]
结果如上,显然,改变的只有r1的值,因为通过构造函数创造出来的实例对象中,所有的属性和方法都是实例内部独立的,并不会跟其他实例共享。
- 总结一下构造函数的优缺点:
- 优点:所有的基本属性独立,不会被其他实例所影响;
- 缺点:所有希望共享的方法和属性也独立了,没有办法通过修改父类某一处来达到所有子实例同时更新的效果;同时,每次创建子类都会调用父类构造函数一次,所以每个子实例都拷贝了一份父类函数的内容,如果父类很大的话会影响性能;
- 总结一下构造函数的优缺点:
-
原型链链式继承:
function Parent() {//列子 this.color = 'red'; this.print = function() { console.log(this.color); } } function Son() { }
我们有一个父类和一个空的子类;
Son.prototype = new Parent(); Son.prototype.constructor = Son;
接着我们把子函数的原型属性赋值给了父函数的实例;
var son1 = new Son(); son1.print(); // red
最后新建子类实例,调用父类的方法,成功拿到父类的color和print属性方法;
我们重点来分析一下下面两行代码:
Son.prototype = new Parent(); Son.prototype.constructor = Son;
这段代码中,子函数的原型赋给了父函数的实例,我们知道prototype是函数中的一个属性,js的一个特性就是:如果一个对象某个属性找不到,会沿着它的原型往上去寻找,直到原型链的最后才会停止寻找。
我们看到最后实例son成功调用了Print方法,输出了color属性,这是因为son从函数Son的prototype属性上面去找到的,也就是从new Parent这个对象里面找到的;这种方式也不是真正的继承,因为所有的子实例的属性和方法,都在父类同一个实例上了,所以一旦某一个子实例修改了其中的方法,其他所有的子实例都会被影响,来看下代码:function Flower() { this.colors = ['黄色', '红色']; this.print = function () { console.log(this.colors) } } function Rose() {} Rose.prototype = new Flower(); Rose.prototype.constructor = Rose; var r1 = new Rose(); var r2 = new Rose(); console.log(r1.print()); // [ '黄色', '红色' ] console.log(r1.print()); // [ '黄色', '红色' ] r1.colors.push('紫色'); console.log(r1.print()); // [ '黄色', '红色', '紫色' ] console.log(r2.print()); // [ '黄色', '红色', '紫色' ]
还是刚才的例子,这次Rose子类选择了原型链继承,所以,子实例r1修改了colors之后,r2实例的colors也被改动了,这就是原型链继承不好的地方。
- 总结下原型链继承的优缺点:
- 优点:很好的实现了方法的共享;
- 缺点:正是因为什么都共享了,所以导致一切的属性都是共享的,只要某一个实例进行修改,那么所有的属性都会变化;
- 总结下原型链继承的优缺点:
-
- js继承共分为5种:构造函数式继承、原型链链式继承、组合式继承、寄生式继承和寄生组合式继承