js ECMAscript原型,继承,this,bind,闭包,浅/深拷贝,正则表达式

Posted 木心

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了js ECMAscript原型,继承,this,bind,闭包,浅/深拷贝,正则表达式相关的知识,希望对你有一定的参考价值。

目录:

 

1.原型的引入
  代码一

function Person(name, age){
    this.name = name;
    this.age = age;
    this.eat = function() {
        console.log("eat...");
    };
}
var per1 = new Person("小白", 10);
var per2 = new Person("小黑", 10);
console.log(per1.eat == per2.eat);//false


  如何实现函数共享, 代码二:

function myEat(){
    console.log("今天吃红烧土豆");
};
function Person(name, age){
    this.name = name;
    this.age = age;
    this.eat = myEat;
}
var per1 = new Person("小白", 10);
var per2 = new Person("小黑", 10);
console.log(per1.eat == per2.eat);//true

  但是代码二不好,因为外面可能定义变量var myEat = 10;造成命名冲突。    
        
2.原型添加方法解决数据共享
  代码:

function Person(name, age){
    this.name = name;
    this.age = age;
}
//通过原型来添加方法
Person.prototype.eat = function() {
    console.log("eat...");
};
var per1 = new Person("zs1", 10);
var per2 = new Person("zs2", 20);
console.log(per1.eat == per2.eat);//true    
    
console.dir(per1);    //通过浏览器查看,发现实例对象中没有eat()方法
console.dir(per2);    
console.dir(Person);

       
  之前的写法

Student.prototype.height="";
Student.prototype.weight="";
Student.prototype.study=function(){};
Student.prototype.eat=function(){};

   
    * 简单的原型语法

Student.prototype={
    constructor:Student,
    height:"",
    weight:"",
    study:function(){},
    eat:function(){}
};


3.实例对象使用的属性和方法层层的搜索
  实例对象使用的属性或方法,先在实例中查找,找到了直接使用,找不到,去对应的构造函数的原型对象prototype中查找,找不到,则报错。
        
4.为内置对象的原型对象中添加方法
  我们能否为系统的内置对象的原型中添加方法(相当于改变源码)?  可以

String.prototype.myReverse=function(){
    for(var i=this.length-1;i>=0;i--){
        console.log(this[i]);
    }
};
var str = "abcdefg";    
str.myReverse();

 

5.原型及原型链

function Person(name, age){
    this.name = name;
    this.age = age;
}
//通过原型来添加方法
Person.prototype.eat = function() {
    console.log("eat...");
};

var per1 = new Person("zs1", 10);
var per2 = new Person("zs2", 20);
console.log(per1.eat == per2.eat); // true
console.log(per1.__proto__ == Person.prototype); // true

  * 原型链: 是一种关系,实例对象和原型对象之间的关系,这个关系是通过原型(__proto__)来联系的
  * 实例对象与原型对象是通过原型__proto__联系的,这个联系就是原型链
  * 原型链最终的指向是Object的prototype中的__proto__是null

 

6.原型指向可以改变

  代码1

function Student() {};
Student.prototype.study = function(){
    console.log("我爱学习");
};

//Student的原型指向改变了,原型中原来的study()方法没有了
Student.prototype = {
    eat: function(){
        console.log("我要吃饭");
    }
};

var stu = new Student();
console.dir(stu);
stu.eat();//我要吃饭
//stu.study();//TypeError: stu.study is not a function

  代码2

function Person() {};
Person.prototype.eat = function(){
    console.log("我爱吃饭");
};

function Student() {};
Student.prototype.study = function(){
    console.log("我爱学习");
};

//Student的原型指向改变了,指向了一个实例对象,原型中原来的study()方法没有了
Student.prototype = new Person();

var stu = new Student();
console.dir(stu);

  结果一:Student.prototype = new Person();注释掉后

{}
  __proto__: {…}
    constructor: function Student()
    study: function study()
    __proto__: Object { … }


  结果二:Student.prototype=new Person();没有注释

{}
  __proto__: {}
    __proto__: {…}
      constructor: function Person()
      eat: function eat()
      __proto__: Object { … }

 

7.原型指向改变如何添加原型方法

function Person(age) {
    this.age = age;
};
Person.prototype.eat=function(){
    console.log("我爱吃饭");
};

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

//Student的原型指向改变了,原型中原来的study()方法没有了
Student.prototype = new Person(10);
//原型指向改变后,再添加方法
Student.prototype.study = function(){
    console.log("我爱学习");
};
var stu = new Student("男");
stu.study();
console.dir(stu);

 

8.实例对象和原型对象属性重名问题

    * 先在实例对象中找,找不到再到原型中找,再找不到,就返回undefined
    * 如果是方法,如果实例对象和原型对象中都没有,报错TypeError: stu.XXXX is not a function
    * 通过实例对象是否可以改变原型对象中的属性值,不能。
    * 通过Student.prototype.sex="改变原型中sex的属性值";来改变原型的属性值

function Person(age,sex) {
    this.age=age;
    this.sex=sex;
};
Person.prototype.eat=function(){
    console.log("我爱吃饭");
};

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

//Student的原型指向改变了,原型中原来的study()方法没有了
Student.prototype=new Person(10,"女");
//原型指向改变后,再添加方法
Student.prototype.study=function(){
    console.log("我爱学习");
};
var stu = new Student("男");
console.log(stu.sex);
Student.prototype.sex="改变原型中sex的属性值";
console.dir(stu);

 

9.通过原型实现继承

    * 面向对象的编程思想:根据需求,分析对象,找到对象有什么特征和行为,通过代码的方式来实现需求,
        要想实现这个需求,就要创建对象,要想创建对象,就应该有构造函数,然后通过构造函数来创建对象,
        通过对象调用属性和方法来实现相应的功能及需求。
    * js不是一门面向对象的语言,js是一门基于对象的语言,那么为什么学习js还要学习面向对象。
        - 因为面向对象的思想适合人的想法,编程起来会更加方便,以及后期的维护。
    * 面向对象的编程语言中有类class的概念,但是js没有类的概念。但是js可以模拟面向对象的思想编程。
        js通过构造函数来模拟类的概念。
        
    * 面向对象的特性:封装、继承、多态
    
    * 封装:就是包装
        - 一个值存储在一个变量中--封装
        - 一些重复代码放在一个函数中--封装
        - 一系列的属性放在一个对象中--封装
        - 一些功能类似的函数(方法)放在一个js文件中--封装
        
    * 继承:首先继承是一种关系,类与类之间的关系。js中没有类,但是可以通过构造函数模拟类,
        然后通过原型类实现继承。继承是为了数据共享,js中的继承也是为了数据共享。
        
    * 原型作用一:实现数据共享,节省内存空间
      原型作用二:实现继承
    
    * 多态:一个对象有不同的行为


    * js通过原型实现继承的代码:

function Person(name,age,sex) {
    this.name=name;
    this.age=age;
    this.sex=sex;
};
Person.prototype.eat=function(){
    console.log("我爱吃饭");
};

function Student(score) {
    this.score=score;
};
//Student的原型指向改变了,原型中原来的study()方法没有了
Student.prototype=new Person("张三",20,"男");
//原型指向改变后,再添加方法
Student.prototype.study=function(){
    console.log("我爱学习");
};

var stu = new Student(100);
console.log(stu.name);//张三
console.log(stu.age);//20
console.log(stu.sex);//
console.log(stu.score);//100
stu.eat();//我爱吃饭
stu.study();//我爱学习

 

10.借用构造函数实现继承

function Person(name,age,sex) {
    this.name=name;
    this.age=age;
    this.sex=sex;
};
function Student(name,age,sex,score) {
    Person.call(this,name,age,sex);//借用构造函数实现继承
    this.score=score;
};

var stu = new Student("张三",20,"男",100);
console.log(stu.name);//张三
console.log(stu.age);//20
console.log(stu.sex);//
console.log(stu.score);//100

 

11.组合继承

function Person(name,age,sex) {
    this.name=name;
    this.age=age;
    this.sex=sex;
};
Person.prototype.eat = function() {
    console.log("吃饭饭");
};
function Student(name,age,sex,score) {
    Person.call(this,name,age,sex);//借用构造函数实现继承
    this.score=score;
};
Student.prototype=new Person();
var stu = new Student("张三",20,"男",100);
console.log(stu.name+"===="+stu.age+"===="+stu.sex+"===="+stu.score);//张三
stu.eat();
console.log(stu);

 

12.拷贝继承

    * 拷贝继承:把一个对象中的属性或方法直接复制到另一个对象中。
    * 代码一:

var obj1={
    name="zs";
    age:20,
    eat:function(){
        console.log("吃土");
    }
};
var obj2=obj1;//改变obj2的指向
console.log(obj2.name,obj2.age);
obj2.eat();

       
    *代码二:

var obj1={
    name="zs";
    age:20,
    eat:function(){
        console.log("吃土");
    }
};
var obj2={};
for(var key in obj1){
    obj2[key]=obj1[key];
};


    * 代码三:

function Person(){};
Person.prototype.name="zs";
Person.prototype.eat=function(){
    console.log("吃饭");
};

var obj2={};
for(var key in Person.prototype){
    obj2[key]=Person.prototype[key];
}

 

13.函数的角色及函数声明和函数表达式的区别
    * 函数的角色:函数声明和函数表达式
    * 函数声明
        function f1(){
            console.log("函数f1");
        };
    
    * 函数表达式
        var f2=function(){
            console.log("函数f2");
        };

    * 下面代码在IE8中输出"呵呵"。因为函数声明提前了,else里面的代码将前面的覆盖了。
        - 火狐中还是输出"哈哈"
        if(true){
            function f1(){
                console.log("哈哈");
            };
        }else{
            function f1(){
                console.log("呵呵");
            };
        }
        f1();

    * 以后尽量使用函数表达式

 

14.函数的this的指向问题
    * 普通函数中的this
        function f1(){
            console.log(this);
        };
        window.f1();//函数调用,window可以省略不写,结果:this是window
    
    * 定时器中的this
        window.setTimeout(function(  //window可以省略不写
            console.log(this);   //this是window
        ),1000);
    
    * 构造函数或原型方法中的this----当前的实例对象
    
    * 事件绑定方法的this-->指向绑定事件的对象

 

15.严格模式

"use strict";//严格模式
function f1(){
    console.log(this);
};
f1();//打印undefined
window.f1();//打印window

 

16.函数是对象,对象不一定是函数
    * 对象中有__proto__,函数中有prototype
    * function f1(){};
    console.dir(f1);//有prototype说明是函数,有__proto__说明又是对象
    console.dir(Math);//有__proto__说明是对象,没有prototype说明不是函数
    
    * 所有的函数实际上都是Func的构造函数创建出来的实例对象
        var f1=new Function("num1","num2","return num1+num2");
        console.log(f1(10,20));
    
    等价于<==>
        function f1(num1,num2){
            return num1+num2
        };
        console.log(f1(10,20));

 

17.数组中函数的调用

// 函数的类型function
function f1(){};
console.log(typeof f1);//类型是function

// 数组可以储存任意类型
var arr=[
    function(){
        console.log(1);
    },
    function(){
        console.log(2);
    },
    function(){
        console.log(3);
    }
];
    
//数组中函数的调用
arr.forEach(function(ele){
    ele();
});

 

-------------- 函数进阶apply、call、bind、闭包、沙箱、递归 --------------

1.apply()和call()方法
    * 作用:可以改变this的指向
        //"use strict";
        function f1(x,y){
            console.log("结果是"+(x+y)+"==="+this);
        };
        f1(10,20);//调用函数
    * 上面代码的结果
        结果是30===[object Window]
        采用严格模式时,结果是30===undefined
            
    * 代码一:

function f1(x,y){
    console.log("结果是"+(x+y)+"==="+this);
};
f1(10,20);//结果是30===[object Window]


f1.apply(null,[10,20]);//结果是30===[object Window]
f1.call(null,10,20);//结果是30===[object Window]

f1.apply(this,[10,20]);//结果是30===[object Window]
f1.call(this,10,20);//结果是30===[object Window]

var obj={
    name:"zs",
    age:20
};
f1.apply(obj,[10,20]);//结果是30===[object Object]
f1.call(obj,10,20);//结果是30===[object Object]


    * 代码二:

function Person(name,age){
    this.name=name;
    this.age=age;
};
Person.prototype.sayHi=function(){
    console.log("hello,"+this.name);
};

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

var per=new Person("张三",20);
per.sayHi();//hello,张三
var stu=new Student("李四");
per.sayHi.apply(stu);//hello,李四
per.sayHi.call(stu);//hello,李四


2.bind()方法
    * bind(thisArg,参数)是复制一份,并且改变this的指向

function f1(x,y){
    console.log("结果是"+(x+y)+"==="+this);
};
var ff = f1.bind(null,10,20);
ff();//结果是30===[object Window]

var obj={
    name:"zs",
    age:20
};
//先复制,后调用,复制时赋值
var fff=f1.bind(obj,10,20);
fff();//结果是30===[object Object]

//先复制,后调用,调用时赋值
var f2=f1.bind(obj);
f2(20,30);//结果是50===[object Object]


3.函数中几个成员介绍
    * 函数中有一个name属性--函数的名字,name属性是只读的,不能修改
    * 函数中有一个arguments属性--实参的个数
    * 函数中有一个length属性--形参的个数
    * 函数中有一个caller属性--调用(f1函数在f2函数中调用)
        
    * 代码:

function f1(x,y){
    console.log(f1.name);
    console.log(f1.arguments.length);
    console.log(f1.length);
    console.log(fl.caller);
}
f1(10,20,30,40);//调用f1函数
funct f2(){
    f1(1,2);
};
f2();

           
4.函数作为参数
    * 代码一:命名函数作为参数

function f1(fn){
    console.log("函数f1");
    fn();
}
var f2=function (){
    console.log("函数f2");
};
f1(f2);

   
    * 代码二:匿名函数作为参数

function f1(fn){
    console.log("函数f1");
    fn();
}
f1(function(){
    console.log("匿名函数");
});

       
5.函数作为返回值
    * 代码一:

function f1(){
    return function(){
        console.log("我是函数,是作为返回值使用");
    };
}
var ff = f1();//调用f1()函数,返回一个函数
ff();

   
    * typeof和instanceof

var n=10;
console.log(typeof n);//number
console.log(typeof(n));//number

var obj={};
console.log(typeof obj);//object
console.log(typeof(obj));//object
console.log(obj instanceof Object);//true

function Person(){};
var per=new Person();
console.log(typeof per);//object
console.log(typeof(per));//object
console.log(per instanceof Object);//true
console.log(per instanceof Person);//true

       
    * Object.prototype.toString(对象) 获取对象的类型

console.log(Object.prototype.toString());//[object Object]
console.log(Object.prototype.toString.call([]));//[object Array]
console.log(Object.prototype.toString.call(Date));//[object Function]
console.log(Object.prototype.toString.call(new Date()));//[object Date]

       
    * Object.prototype.toString(对象)用来判断某对象的类型

function f1(a){
    if(Object.prototype.toString.call(a)=="[object Array]"){
        console.log("参数是一个数组");
    }
};
f1([]);//参数是一个数组

           
6.案例:电影排序

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
</head>
<body>
<script type="text/javascript">
    function File(name,size,time){
        this.name=name;
        this.size=size;
        this.time=time;
    };
    var f1= new File("jack.avi","400M","1997-12-10");
    var f2= new File("xiaoy.avi","200M","2007-10-10");
    var f3= new File("tom.avi","800M","1996-02-10");
    arr=[f1,f2,f3];

    function fn(attr){
        return function getSort(obj1,obj2){
            if(obj1[attr]>obj2[attr]){
                return 1;
            }else if(obj1[attr]==obj2[attr]){
                return 0;
            }else{
                return -1;
            }

        };
    };

    var ff = fn(prompt("输入name或size或time"));
    arr.sort(ff);
    for(var i=0;i<arr.length;i++){
        console.log(arr[i].name+"--"+arr[i].size+"--"+arr[i].time);
    }
</script>
</body>
</html>


7.闭包
    * 闭包的概念:函数A中,有一个函数B,函数B可以访问函数A定义的变量
    
    * 闭包的模式:函数模式的闭包,对象模式的闭包
    
    * 闭包的作用:缓存事件,延长作用域链
    
    * 闭包的优缺点:优点:缓存数据 缺点:变量占用的内存没有及时释放
    
    * 闭包的应用
   
    * 函数模式的闭包
        (function A(){
            var num=10;
            function B(){
                console.log(num);
            }
            B();
        })();
      或另一种函数自调用写法
        (function A(){
            var num=10;
            function B(){
                console.log(num);
            }
            B();
        }());
    
    * 对象模式的闭包
        function f3(){
            var num=20;
            return{
                age:num
            };
        }
        var obj=f3();
        console.log(obj.age);
        
8.闭包的案例

function f1(){
    var num = 10;
    return function (){
        num++;
        return num;
    }
}
var ff = f1();
console.log(ff());//11
console.log(ff());//12
console.log(ff());//13

  
9.案例:闭包实现点赞

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
</head>
<body>
    <ul>
        <li style="list-style-type: none"><img src="uu.jpg" style="width: 300px"><br/>
            <input type="button" value="点赞(0)" style="font-size: 25px"></li>
        <li style="list-style-type: none"><img src="uu.jpg" style="width: 300px"><br/>
            <input type="button" value="点赞(0)" style="font-size: 25px"></li>
    </ul>
<script type="text/javascript">
    var eles = document.getElementsByTagName("input");
    function getValue(){
        var value=0;
        return function (){
            value++;
            this.value="点赞("+value+")";
        };
    };

    for(var i=0;i<eles.length;i++){
        eles[i].onclick=getValue();
    }
</script>
</body>
</html>


10.沙箱
    * 沙箱:模拟小环境
        var num=10;
        (function(){
            var num=20;
            console.log(num);
        }());
        
11.递归

 

-------------- 内置的方法(深拷贝、浅拷贝、遍历DOM树)、正则表达式 --------------

1.浅拷贝

var obj1={
    name:"张三",
    age:10
};
var obj2={};
function extend(a,b){
    for(var key in a){
        b[key]=a[key];
    }
}
extend(obj1,obj2);
console.dir(obj2);

       
2.深拷贝

var obj1={
    name:"张三",
    age:10,
    car:["宝马","奔驰"],
    dog:{
        name:"大黄",
        age:5,
        cat:{
            name:"阿才",
            age:2,
            color:["yellow","white"]
        }
    }
};
var obj2={};
function extend(a,b){
    for(var key in a){
        var item=a[key];
        if(item instanceof Array){
            console.log("复制数组");
            b[key]=[];
            extend(item,b[key]);
        }else if(item instanceof Object){
            console.log("复制对象");
            b[key]={};
            extend(item,b[key]);
        }else{
            console.log("复制属性");
            b[key]=item;
        }
    }
}
extend(obj1,obj2);
console.dir(obj1);
console.dir(obj2);


3.遍历DOM树

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
</head>
<body>
<div>
    <ul>
        <li><a href=""><img src="uu-small.jpg"></a></li>
        <li><a href=""><img src="uu-small.jpg"></a></li>
    </ul>
</div>
<div><a href="">百度</a></div>
<p><a href="">谷歌</a></p>
    
<script type="text/javascript">

    var htmlObj=document.getElementsByTagName("html")[0];
    function fn(obj){
        for(var i=0;i<obj.children.length;i++){
            console.log(obj.children[i].localName);//输出标签名字
            if(obj.children[i].children){
                fn(obj.children[i]);
            }
        }
    };
    fn(htmlObj);
</script>
</body>
</html>


4.正则表达式

以上是关于js ECMAscript原型,继承,this,bind,闭包,浅/深拷贝,正则表达式的主要内容,如果未能解决你的问题,请参考以下文章

js 原型链继承

关于js中的原型问题

js 继承方式

JS- 继承

JS继承之原型继承

JS继承之原型继承