- smm的笔记:
- 构造函数和原型对象和 实例对象之间的关系
function F(){
document.write(F.prototype.constructor===F)
}
f()// true
// 构造函数function(.prototype)-> 原型对象(.constructor)->构造函数
// 构造函数(new)-> 实例object (.__proto__)-> 原型对象(.constructor)->构造函数
-
proto属性是一个内部属性, 应该尽量少用,而是用Object.getPrototypeof和Object.setPrototypeOf,进行原型对象的读写操作。
- 实例的 _proto_ ----> 构造函数的原型对象 ----> Object的原型对象 ----> null
-
原型链
function F1(){
this.name = "nameF1";
}
F1.prototype.getf1name = function(){
return this.name;
}
function F2() {
this.name = "nameF2";
}
F2.prototype = new F1();
F2.prototype.getf2name = function(){
return this.name;
}
F2.prototype.getf1name = function(){
return "newname";
}
var f2instance = new F2();
document.write(f2instance.getf1name());// newname; 重新定义继承自祖辈的方法, 会覆盖原方法
var f1instance = new F1();
document.write(f1instance.getf1name()); //nameF1;重新定义继承自祖辈的方法,不会改变祖辈自己的调用
通过原型链实现继承时,不能使用对象字面量创建原型方法。因为这样做就会重写原型链;
原型链的问题1:.引用类型值的原型属性会被所有实例共享;
function F1(){
this.colors = ["red", "blue", "green"];
}
function F2(){}
F2.prototype = new F1();
var instance1 = new F2();
instance1.colors.push("black");
document.write(instance1.colors); //"red,blue,green,black"
var instance2 = new F2();
document.write(instance2.colors); //"red,blue,green,black"
- 解决办法:借用构造函数;
function F1(){
this.colors = ["red", "blue", "green"];
}
function F2(){
F1.call(this);
}
var instance1 = new F2();
instance1.colors.push("black");
document.write(instance1.colors); //"red,blue,green,black"
var instance2 = new F2();
document.write(instance2.colors); //"red,blue,green"
- 原型链的问题2:创建子类型的实例时,不能向超类型的构造函数中传递参数。
- 组合继承:最常用的继承方式
p186 10-16 - 原型式继承:Object.create(o, [描述符]), 传入一个要copy的类型, 返回一个指向这个类型的其它类型的实例, 描述符同Object.defineProperties()的第二个参数。
-缺点:同原型继承, 共享引用类型值
var person = {
name: "Nicholas",
friends: ["Shelby", "Court", "Van"]
};
var anotherPerson = Object.create(person, {
name: {
value: "Greg"
}
});
alert(anotherPerson.name); //"Greg"
- 寄生式继承
function createAnother(original){
var clone = object(original); //通过调用函数创建一个新对象
clone.sayHi = function(){ //以某种方式来增强这个对象
alert("hi");
};
return clone; //返回这个对象
}
- 寄生组合式继承(推荐)?????
function inheritPrototype(subType, superType){
var prototype = Object.create(superType.prototype); //创建对象
prototype.constructor = subType; //增强对象
subType.prototype = prototype; //指定对象
};
function F1(name){
this.name = name;
this.colors = ["red", "blue", "green"];
};
F1.prototype.sayName = function(){
alert(this.name);
};
function F2(name, age){
F1.call(this, name);
this.age = age;
}
inheritPrototype(F2, F1);
F2.prototype.sayAge = function(){
alert(this.age);
};
document.write(F2)
page 190/206/208
对于元素节点, nodeName 中保存的始终都是元素的标签名,而 nodeValue 的值则始终为 null。
每个节点都有一个 childNodes 属性,其中保存着一个 NodeList 对象, 使用 Array.prototype.slice()方法可以将其转换为数组。
hasChildNodes()
appendChild()
insertBefore()
replaceChild()
removeChild()
cloneNode()
parentNode
childNodes
firstChild 和 lastChild
nextSibling 和 previousSibling
ownerDocument
- NamedNodeMap中保存的是一组无序的属性节点的集合。
- NodeList对象是由childNodes属性,querySelectorAll方法返回的一组节点的集合,它保存着一组有序的节点。注意区别的是,由childNodes属性返回的NodeList对象是一个动态的集合(live collection), 而由querySelectorAll方法返回的则是一个静态的集合(static collection)。querySelectorAll() 方法返回文档中匹配指定 CSS 选择器的所有元素.
-HTMLCollection 是一个接口,表示 HTML 元素的集合,它提供了可以遍历列表的方法和属性。- HTMLCollection 对象是只读的,不能给它添加新元素,即使采用 JavaScript 数组语法也是如此。
- HTMLCollection 对象和 NodeList 对象很相似,但前者可能既能用名称索引也能用数字索引。
2. outerHTML 属性
- innerHTML:
从对象的起始位置到终止位置的全部内容,不包括Html标签。 - outerHTML:
除了包含innerHTML的全部内容外, 还包含对象标签本身。
<div id="testinner">
<p>This is a <strong>paragraph</strong> with a list following it.</p>
<ul>
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
</ul>
</div>
<div id="testouter">
<p>This is a <strong>paragraph</strong> with a list following it.</p>
<ul>
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
</ul>
</div>
<script>
div = document.getElementById("testinner")
div.innerHTML = "<p>This is another paragraph.</p>";
alert("this is inner>"+div.innerHTML) // this is inner><p>This is another paragraph.</p>
div = document.getElementById("testouter")
div.outerHTML = "<p>This is another paragraph.</p>";
alert("this is outer>"+div.outerHTML)
// this is outer><div id="testouter">
// <p>This is a <strong>paragraph</strong> with a list following it.</p>
// <ul>
// <li>Item 1</li>
// <li>Item 2</li>
// <li>Item 3</li>
// </ul>
// </div>
</script>
- 虽然元素将在文档中被替换,但其outerHTML属性已设置的变量仍将保留对原始元素的引用:
// <div id="container"><div id="d">This is a div.</div></div>
container = document.getElementById("container");
d = document.getElementById("d");
alert(container.firstChild.nodeName); // logs "DIV"
d.outerHTML = "<p>This paragraph replaced the original div.</p>";
alert(container.firstChild.nodeName); // logs "P"
alert(d.nodeName); // logs "P"
- 如果元素没有父元素,则设置其outerHTML属性不会更改它或其后代。许多浏览器也会抛出异常
var div = document.createElement("div");
div.outerHTML = "<div class=\"test\">test</div>";
console.log(div.outerHTML); // output: "<div></div>"
4. 内存与性能问题
- 每次循环都设置一次 innerHTML 的做法效率很低。而且,每次循环还要从 innerHTML 中读
取一次信息,就意味着每次循环要访问两次 innerHTML。最好的做法是单独构建字符串,然后再一次
性地将结果字符串赋值给 innerHTML
myul = document.getElementById("myul")
for (var i=0, len=5; i < len; i++){
myul.innerHTML += "<li>" + i + "</li>"; //要避免这种频繁操作!!
}
var itemsHtml = "";
for (var i=0, len=5; i < len; i++){
itemsHtml += "<li>" + i + "</li>";
}
myul.innerHTML = itemsHtml; //这个例子的效率要高得多,因为它只对 innerHTML 执行了一次赋值操作。