• 面向对象


    面向对象

    JavaScript对每个创建的对象都会设置一个原型,指向它的原型对象。

    当我们用obj.xxx访问一个对象的属性时,JavaScript引擎先在当前对象上查找该属性,如果没有找到,就到其原型对象上找,如果还没有找到,就一直上溯到Object.prototype对象,最后,如果还没有找到,就只能返回undefined

    例如,创建Array一个对象

        let arr = [1,2,3]
    

    那么,arr的原型链就是

        arr ----> Array.prototype ----> Object.prototype ----> null
    

    Array.prototype定义了indexOf()shift()等方法,因此你可以在所有的Array对象上直接调用这些方法。

    而当我们创建一个函数的时候

        function fun(){
            return 1;
        }
    

    那么,函数fun的原型链就是

        fun ----> Function.prototype ----> Object.prototype ----> null
    

    由于Function.prototype定义了apply()等方法,因此,所有函数都可以调用apply()方法。

    构造函数

    除了直接用{ ... }创建一个对象外,JavaScript还可以用一种构造函数的方法来创建对象。它的用法是,先定义一个构造函数:

        function Student(name){
            this.name = name
            this.say = function(){
                console.log('Hello' + ',' + this.name)
            }
        }
    

    看到这个函数,你可能会想,这不就是一个普通的函数吗?
    这确实是一个普通函数,如果调用它是得这样的

        function Student(name){
            this.name = name
            this.say = function(){
                console.log('Hello' + ',' + this.name)
            }
            return this
        }
        let xiaoming = Student('小明')
        console.log(xiaoming)//小明
        xiaoming.say()//Hello,小明
    

    普通函数的调用一定要return this,因为此时Student里的this环境变量指向的是window,于是无意间创建了全局变量name,并且返回undefined

    而构造函数就是用new字符(关键字)来调用函数Student,并返回一个对象,如下:

        function Student(name){
            this.name = name
            this.say = function(){
                console.log('Hello' + ',' + this.name)
            }
        }
        let xiaohong = new Student('小红')
        console.log(xiaohong)//小红
        xiaohong.say()//Hello,小红
    

    所以,如果不写new,Student就是一个普通函数,如果不return this的话就会抛出undefined;如果写了new,它就变成了一个构造函数,它绑定的this指向新创建的对象,并默认返回this,也就省了return this.

    新创建的xiaohong的原型链就是

        xiaohong ----> Student.prototype ----> Object.prototype ----> null
    

    也就是说,xiaohong的原型指向的是函数Student的原型。同理,如果你创建又new出了xiaojun xiaopeng结果也都是一样的

        xiaojun ----> Student.prototype ----> Object.prototype ----> null
        xiaopeng ----> Student.prototype ----> Object.prototype ----> null
    

    new Student()创建的对象还从函数原型上或得了一个constructor的属性,它指向函数Student本身

        xiaohong.portotype.constructor == Student.portotype.constructor //true
        xiaohong.prototype.constructor == Student //true
        Object.getgetPrototypeOf(xiaohong) == Student.prototype //true
        xiaohong instanceof Student //true
    

    Student.prototype指向的就是xiaojun xiaopeng的原型对象,这个对象有个属性constructor指向函数Student本身;函数Student也有自己的一个属性prototype指向xiaojun xiaopeng这些对象的原型,但是xiaojun xiaopeng可没有属性直接指向函数Student本身,不过可以用__proto__这个非标准用法来查看. 所以我们就可以认为xiaojun xiaopeng是继承于Student

    new的好处

        xiaoming.name; // '小明'
        xiaohong.name; // '小红'
        xiaoming.say; // function: Student.say()
        xiaohong.say; // function: Student.say()
        xiaoming.say === xiaohong.say; // false
    

    为了我们区别,xiaomingxiaohong有着各自的name
    xiaomingxiaohong也有着各自的say()方法,虽然有着同一个方法,函数名称和代码都是相同的,但它们是两个不同的函数
    所以,如果我们通过new Student()创建了很多对象,这些对象的say()函数实际上只需要共享同一个函数就可以了,这样可以节省很多内存

    要让创建对象共享一个say()函数,根据对象属性的查找原则,我们只需要把say()移动到xiaomingxiaohong对象的原型上就可以,也就是Student.prototype
    修改代码如下:

        function Student(name){
            this.name = name
        }
        Student.prototype.say = function() {
            console.log('Hello' + ',' + this.name)
        }
    

    new创建基于原型的JavaScript的对象就是这么简单!

    忘记写new怎么办

    关于new的重要性上述已经说过了
    我们还可以编写一个CreateStudent()函数,在内部封装所有的new,代码如下:

        function Student(data){
            this.name = data.name || '匿名'
            this.age = data.age || 22
        }
        Student.prototype.say = function () {
            console.log('Hello' + ' ' + this.name + '!')
        }
        function CreateStudent(data){
            return new Student(data || {})
        }
    

    这个CreateStudent()函数有几个巨大的优点:一是不需要new来调用,二是参数非常灵活,可以不传,也可以这么传:

        let xiaoming = CreateStudent({
            name:'小明'
        })
        console.log(xiaoming.age)//22
        xiaoming.say()//Hello 小明!
    

    如果创建的对象有很多属性,我们只需要传递需要的某些属性,剩下的属性可以用默认值。由于参数是一个Object,我们无需记忆参数的顺序。如果恰好从JSON拿到了一个对象,就可以直接创建出xiaoming

    本文链接:https://www.liaoxuefeng.com/wiki/1022910821149312/1023022043494624

  • 相关阅读:
    P2704 [NOI2001]炮兵阵地[状压dp]
    【CRT】中国剩余定理简介
    乘法逆元
    P2921 [USACO08DEC]在农场万圣节[SCC缩点]
    P1967 货车运输[生成树+LCA]
    P2746 P2812 [USACO5.3]校园网Network of Schools[SCC缩点]
    Debian初始化配置
    Linux网桥配置
    Jenkins与Gitlab集成
    Gitlab搭建
  • 原文地址:https://www.cnblogs.com/kaizhadiyishuai/p/11926658.html
Copyright © 2020-2023  润新知