继承

1.传统模式--- >原型链 过多的继承了没用的属性。

2.借用构造函数 不能继承借用构造函数的原型。 每次构造函数都要多走一个函数。

3.共享原型 不能随便修改自己的原型

4.圣杯模式

不只是构造函数才有原型,只要是函数都有原型。原型是在构造函数之上的对象

# 传统模式

    Grand.prototype.lastName = "ji";
    function Grand() {
    }
    var grand = new Grand();
    
    Father.prototype = grand;
    function Father() {
        this.name = 'hehe';
    }
    var father = new Father();
    
    Son.prototype = father;
    function Son() {
    }
    var son = new Son();
//son能继承自己原型属性,father原型的属性,grand原型的属性
//这样从头继承到尾就会发生一个矛盾,不想继承来的都继承了。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

# 借用构造函数

function Person(name,age,sex) {
    this.name = name;
    this.age = age;
    this.sex = sex;
}
function Student(name,age,sex,grade){
    Person.call(this,name,age,sex);
    this.grade = grade;
}
var student = new Student();
//用call将Person自身的属性全部传到Student里面
//Student就可以完全借用Person的属性和方法。
//一定要写构造函数,要不然此类写法无意义。
1
2
3
4
5
6
7
8
9
10
11
12
13

# 共享原型

function.prototype.lastName = "Deng";
    function Father() {
    //son.prototype = Father
    }
    function Son() {
    }
var son = new Son();
var father = new Father();
//想让son生产出的对象 继承自Father的prototype
//让son的原型等于father的原型
Son.prototype = Father.prototype
1
2
3
4
5
6
7
8
9
10
11

# 共享原型弊端

function.prototype.lastName = "Deng";
    function Father() {
    }
    function Son() {
    }
    function inherit(Target,Origin) {
        Target.prototype = Origin.prototype;
    }
    inherit(Son,Father);
    var son = new Son();
    var father = new Father();
// inherit(Son,Father);写到这里,那son和 father 的原型都为 undefined
1
2
3
4
5
6
7
8
9
10
11
12

弊端

封装一个函数inherit里面传入的参数是继承人,继承者。

此类写法的弊端是son如果有一天想要一个别的属性,Son.prototype.sex = "male",那么Father就也会有father.sex。

# 圣杯模式

# 基本写法

    function F() {}
    F.prototype = Father.prototype
    Son.prototype = new F()
1
2
3

# 原理

通过原型链来实现继承

F 的 prototype 就是 Father 的 prototype

Son的 prototype 等于构造函数 F

Son 的 prototype 等于 Father 的 prototype

改变son的属性和方法不会改变Father的属性和方法

# 完整圣杯模式

function inherit(Target,Origin) {
        function F(){ };
        F.prototype = Origin.prototype;
        Target.prototype = new F();
        Target.prototype.constuctor = Target;
        //son的constuctor让他指向他自己
        Target.prototype.uber = Origin.prototype;
        //son的超类(真正继承自father的prototype)
    }
    function.prototype.lastName = "Deng";
    function Father() {
        }
    function Son() {
        }
    inherit(Son,Father);
    var son = new son();
    var father = new Father();  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

此刻son.lastName=deng,father.lastName=deng

给Son加上.prototype.sex = "male" son.sex. = sex。 fater.sex = undefined。

原型上的construtor默认指向它的构造函数,son的constructor理应指向Son,现在就成为了father。 son.proto -- > new F().proto -- >Father.prototype

# 命名空间

# 作用 管理变量,防止污染全局,适用于模块化开发

 var org = {
    department1 : {
                jicheng : {
                name : "abc";
                age : 123;
            }
    xuming : {
        }
    },
    
    department2 :   {
            zhangsan : {
            },
            lisi : {
            }
       }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

把属性都写到对象里面,让变量命名不冲突。 使用的话 可以这样写

org.department1.jicheng.name//调用
var jicheng = org.department1.jicheng;//简化写法
jicheng.name,jicheng.age //调用
1
2
3

# 闭包私有化功能

闭包的第三四个功能

闭包可以实现封装,属性私有化功能。

管理变量 防止污染全局,适用于模块化开发。

var name = 'bcd';
var init = (function () {
        var name = 'abc';
        function callName() {
            console.log(name);
            }
        return function () {
            callName();
        }
}());
        init();
//写一个返回的接口函数,调用里面的其他方法
//当整体大函数运行的时候,会运行此函数
//打印 abc,不会污染全局变量name的bcd,实现私有化变量
var initdeng = (function () {
        var name = 'laodeng';
        function callName() {
            console.log(name);
            }
        return function () {
            callName();
        }
}());
     initdeng() //打印 laodeng
//两个立即执行函数就实现了自己功能的封装,也没有污染全局变量
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

# 模拟jq连续调用

var deng = {
            smoke: function () {
                console.log('Smoking,... xuan cool!');
                // return undefined;
                return this;
            },
            drink: function () {
                console.log('drinking...,ye cool!');
                return this;
            },
            perm: function () {
                console.log('perming...,cool!');
                return this;
            }
    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

deng.smoke().drink()会报错,因为smoke方法调用之后somke下面会隐式的返回undefinedundefined.drink()一定报错。 如果想实现一个方法的连续调用, 给方法后面写一个return this,相当于deng.下一个方法,就可以完成连续调用。

# 属性的表示方法

# 两种表示方法

1.obj.prop

2.obj["prop"]

var obj = {
            name: "abc";
        }
//想要访问name 有两种方式。第一种obj.name
//第二种obj['name']  
//obj后面跟一个[] 里面写字符串的属性名
1
2
3
4
5
6

# obj['name']可以延伸以下写法

例子(属性拼接)

        var deng = {
            wife1: { name: "xiaoliu" },
            wifi2: { name: "xiaozhang" },
            wife3: { name: "xiaomeng" },
            sayWife: function (num) {
                return this['wife' + num];
            }
        }
1
2
3
4
5
6
7
8

原理

return this指第一人称自己,deng.[wife+传进来的数字]。

因为字符串可以进行拼接成另一个字符串,使用传参方式输出。

deng.sayWife(1);打印xiaoliu,以此类推

# 对象枚举

# 数组遍历

var arr = [1, 2, 3, 4, 5, 6, 7, 8, 9];
        // 遍历 枚举
        for (var i < 0; i < arr.length; i++) {
            console.log(arr[i]);
        }
1
2
3
4
5

# 对象遍历

已知一个对象,遍历里面的属性和属性值。

var obj = {
            name: '13',
            age: 123,
            sex: "male",
            height: 180,
            weight: 75
        }
        for (var prop in obj) {
           //console.log(prop)打印所有属性名
           console.log(obj.prop) 
           // var prop的prop可以自定义改成其他的单词
           //但是打印必须是 obj.自定义单词
  }
1
2
3
4
5
6
7
8
9
10
11
12
13

# for in 循环

遍历对象功能。对象有多少个属性,就会循环多少圈。 上面代码会打印出5个undefined,因为输出obj.prop系统隐式转换obj['prop'],结果obj里面没有['prop'],所以会打印undefined。

console.log(obj[prop]) 只有这么写才会把对象里面的属性值遍历出来。

一般情况下用到 for in 循环,会写 hasOwnProperty,判断属性属不属于对象,不会取到原型链上的属性。(后面章节深度克隆会写到)。

# hasOwnProperty

任何对象都有hasOwnProperty这个属性。

for (var prop in obj) {
    if(obj.hasOwnProperty(prop)) {
           console.log(obj.[prop]);
        }
   }
1
2
3
4
5

写法:obj.hansOwnProperty( )里面传属性判断。但凡是自己手动写的属性都可以判断出来在对象里,也都能打印。如果不是自己手动设置的,是原型链上的,不会打印系统自带的属性。

功能:判断属性属不属于对象,返回布尔值。

# in

功能:只能判断对象上能不能访问属性,包括原型。

'lastname' in obj   //true
//属性名要加字符串,要不然会当成变量 lastname 未定义
//in 和 hasOwnProperty相似,区别就是in 能访问原型,hanOwnProperty 不能
1
2
3

# instanceof

function Person() {

        }
var person = new Person();

person instanceof Person //打印true
person instanceof Object //打印true
[] instanceof Array     //打印true
[] instanceof Object    //打印true
1
2
3
4
5
6
7
8
9

``

A instanceof B

A对象 是不是 B构造函数构造出来的。

A对象的原型链上 有没有B的原型。

# 区分 Array Object

var obj = { };
var arr = [ ];
1
2

第一种区别方式(construtor)

第二种区别方式(instanceof)

第三种区别方式(toString)

Object.prototype.toString = function () {
//识别 this
//返回相应的结果
//this = obj;谁调用的方法 this 就指向谁
     }
        obj.toString();
        
Object.prototype.toString.call([]);
//用 call 把数组传进去此时 this 指向数组
// 从而识别数组,对象等
1
2
3
4
5
6
7
8
9
10