继承
- 传统形式:原型链的模式。缺点:没用的属性和方法都继承下来。
- 借用构造函数:不能继承构造函数的原型。并且需要执行一次构造函数。
- 共享原型:一个构造函数的原型设置成想要继承的构造函数的原型。这样就实现了继承,但这不能随便改动自己的原型。
- 圣杯模式:完善共享原型模式,中间添加个对象。
<script type = "text/javascript">
//圣杯模式实现继承
Father.prototype.lastName = "lin";
function Father(){};
function Son(){};
function inherit(Target, Origin){
//Target.prototype = Origin.prototype;
function F(){};
F.prototype = Origin.prototype;
Target.prototype = new F();
Target.prototype.constuctor = Target;
Target.prototype.uber = Origin.prototype;
}
inherit(Son,Father);
var son = new Son();
console.log(son.__proto__);
</script>
命名空间
为了不让全局变量混淆,采用了定义一个全局对象,全局对象里包含多个对象,这些对象中存储每个功能的变量,这样就能区分开各功能模块的变量。这是个比较早期采用的方法。还可采用闭包的模式开发。
<script type = "text/javascript">
var org ={
department_one:{
zhangsan:{
name:"abc",
age:123
}
},
department_two:{
lisi:{
name:"efg",
age:345
}
}
}
var zs = org.department_one.zhangsan;
var ls = org.department_two.lisi;
console.log(zs.name);
console.log(ls.name);
//使用 with 操作命名空间中的变量。
with(org.department_one.zhangsan){
console.log(name);
}
with(org.department_two.lisi){
console.log(name);
}
</script>
实现链式调用
<script type = "text/javascript">
var person = {
smoke : function(){
console.log("Smoking....cool!");
return this;
},
drink : function(){
console.log("Drinking...cool too !");
return this;
},
perm : function(){
console.log("Perming...cool cool cool !");
return this;
}
}
person.drink().perm().smoke().drink().smoke().perm().perm().smoke().smoke().drink().smoke();
</script>
对象属性的访问方式
person.card1 和 person['card1'] 都是访问 person 对象的 card1 属性。
引擎会把 person.card1 转成 person['card1'] 来访问属性。
<script type = "text/javascript">
var person = {
card1:{name:"中国银行"},
card2:{name:"中国工商银行"},
card3:{name:"中国建设银行"},
card4:{name:"中国交通银行"},
card5:{name:"汇丰银行"},
card6:{name:"华夏银行"},
card7:{name:"渤海银行"},
card8:{name:"网商银行"},
card9:function(){
console.log("花呗");
},
__proto__:{number:"6200000000000"}
}
Object.prototype.abc = "123";
console.log(person.card1);
console.log(person.card7);
for (const key in person) {
//是否对象本身的属性,而不是继承来的。
console.log(person.hasOwnProperty(key));
if(typeof(person[key]) == "function"){
person[key]();
}
else{
console.log(person[key]);
}
}
// in 操作符。对象 person 是否有card1 属性,包括原型链。
console.log('card1' in person);
function Demo(){}
var demo = new Demo();
// instanceof 操作符。对象 demo 的原型链上是否有 Demo 原型。
console.log(demo instanceof Demo);
console.log(demo instanceof Object);
console.log([] instanceof Array);
console.log([] instanceof Object);
console.log(1 instanceof Object);
console.log("abc" instanceof Object);
</script>
对象的深度复制
<script type = "text/javascript">
var person = {
card1:{name:"中国银行"},
card2:{name:"中国工商银行"},
card1Name:function(){
return this.card1.name
},
cards:["中国银行","中国工商银行"],
card2Name:null
}
console.log(person.card2Name != null);
function clone(obj1,obj2){
obj2 = obj2 || {};
for (const key in obj1) {
if(obj1.hasOwnProperty(key)){
if(typeof(person[key]) == "object" && person[key] != null){
obj2[key] = (new Object().toString.call(person[key]) == "[object Array]") ? [] : {};
clone(obj1[key],obj2[key]);
}else{
obj2[key] = obj1[key];
}
}
}
return obj2;
}
var obj = {}
var obj0 = clone(person,obj);
console.log('obj.card1.name = ',obj.card1.name,'person.card1.name = ',person.card1.name);//修改前与person相同。
obj.card1.name = "消除";//修改obj。
console.log('obj.card1.name = ',obj.card1.name,'person.card1.name = ',person.card1.name);//修改obj后。
console.log('obj.card1Name() = ',obj.card1Name(),'person.card1Name() = ' ,person.card1Name());//修改obj后。
console.log('obj.cards = ',obj.cards,'person.cards = ' ,person.cards);
console.log('person object = ',person);
console.log('obj object = ',obj);
console.log('obj0 object = ',obj0,obj0===obj);
</script>
练习题:
console 输出结果是什么?
<script type = "text/javascript">
var f = (
function f(){
return "1";
},
function g(){
return 1;
}
)();
console.log(typeof(f));
</script>
<script type = "text/javascript">
var x = 1;
if(function f(){}){
//(function f(){}) 这个表达式判断完就销毁了。
x += typeof f;//此时 f 没有定义 undefined
}
console.log(x);
</script>
<script type = "text/javascript">
console.log(undefined == null);
console.log(undefined === null);
console.log(undefined == undefined);
console.log(null == null);
console.log(undefined === undefined);
console.log(null === null);
console.log(undefined == NaN);
console.log(null == NaN);
console.log(null === NaN);
console.log(undefined === NaN);
console.log(NaN === NaN);
console.log(isNaN(100));
console.log(parseInt("1a")==1);
function myIsNaN(num){
var ret = Number(num);
ret += "";
if(ret == "NaN"){
return true;
}else{
return false;
}
}
console.log(myIsNaN("123"));
console.log({} == {});
console.log([] == []);
</script>
this 指针
- 函数预编译过程 this --> window。
- 全局作用域里 this --> window。
- call/apply 可以改变函数运行时 this 指向。
- obj.func();func()里面的this指向obj。
this指针指向调用函数的对象,new 构造函数时使用闭包的特性产生新对象。
练习题
写出输出结果:
<script type = "text/javascript">
//控制台输出结果是:?????????
var name = "222";
var a = {
name : "111",
say : function(){
console.log(this.name);
}
}
var fun = a.say;
fun();
a.say();
var b = {
name : "333",
say : function(fun){
fun();
}
}
b.say(a.say);
b.say = a.say;
b.say();
</script>
<script type = "text/javascript">
var a = 5;
function Test(){
// new 的时候系统添加 this 局部变量。
// this = {
// __proto__:test.prototype
// }
a = 0;
console.log(a);//先找到局部变量 a ,输出。
console.log(this.a);//找调用者里变量 a , 输出。
var a;
console.log(a);//先找到局部变量 a , 输出。
}
Test(); // 0,5,0
new Test();// 0,undefined,0
</script>
<script type = "text/javascript">
function print(){
var marty = {
name : "marty",
printName : function(){console.log(this.name);}
}
var test1 = {name : "test1"};
var test2 = {name : "test2"};
var test3 = {name : "test3"};
test3.printName = marty.printName;
var printName2 = marty.printName.bind({name : 123});
//bind方法作用是给函数 printName 设置 this 指向定义的{name:123}对象。
marty.printName.call(test1);
marty.printName.apply(test2);
marty.printName();
printName2();
test3.pringName();
}
print();
</script>
<script type = "text/javascript">
var bar = {a:"002"};
function print(){
bar.a = 'a';
Object.prototype.b = 'b';
return function inner(){
console.log(bar.a);
console.log(bar.b);
}
}
print()();
</script>