您的位置 首页 java

js回忆录(4)——对象,构造函数

js是一门基于对象的语言,里边所有的数据类型都可以当对象使唤(当然null和undefined除外),当我们在v8引擎里声明一个对象时会发现每个对象属性里边都有这个东西:

js回忆录(4)——对象,构造函数

在说明这个属性之前需要先说明一点就是,声明一个对象和new Object 生成对象的结果是一样的,即,所有对象都是Object的实例,每一个实例都会继承它的构造函数上的 prototype 的属性,而上面的_proto_就是指向这个原型对象的,也就是说:

 实例._proto_ = 构造函数.prototype
  

每个对象上查找属性时要走的流程大体是,查查自己有没有,查查自己的构造函数的prototype上有没有,再查查 构造函数 的prototype的构造函数的prototype上有没有,依次查找,如此变成了原型链。普通对象上关于原型只有一个_proto_ 属性指向它的构造函数的原型(原型对象),而在一个函数对象上则多了一个prototype属性,这个属性就是用于继承,创建子类共有的属性,方法的比较重要的一个属性。

函数初始化之后原型对象上有constructor和_proto_两个属性,一个指向这个函数一个指向它自己的构造函数的prototype,一般来说是Object.prototype。

构造函数实在是js里边一个有趣的东西,一个函数是不是构造函数不是取决于它的定义,而是取决于它的调用方式。构造函数不需要return语句 ,甚至调用的时候都不需要(),这一点就比较像php了。生成的实例对象私有属性由构造函数定义,共有属性由构造函数的prototype定义。

2.关于JS里的继承

继承其实是一个面向对象的编程语言的概念,JS天生的短板,一般面试的时候回答继承时怎么做,就只是简单的 子类.prototype = 父类.prototype,好了合格了,但是从实际出发,事情远远没有这么简单,首先是 constructor 的属性得改,然后得考虑到JS引用类型的特性,然后得留下子类已经定义的属性,防止被父类覆盖,所以一个合理的做法是深拷贝,

 function inherit( sub,sup ){
    let temp = deepCopy(sup.prototype);//深拷贝父类prototype
    for( let key in temp  ){
        if( sub.prototype[key] !==null || sub.prototype[key] !== undefined){//子类中如果已经存在对应属性,则不作操作
        }else{
            sub.prototype[key] = temp[key]
        }
    }
    function deepCopy(obj){
        let result;
        if( JSON ){
            result = JSON.parse(JSON.stringify(obj))
        }else{
            for( let key in obj  ){
                result[key] = typeof( obj[key] ) !== 'object'? obj[key] : deepCopy(obj[key])
            }
        }
        return result
    }
}
  

如果已经确定子类中没有要保留的属性,可以用一下司徒正美大佬的继承方法,这是他的anu框架里边的源码的一个方法,很妙啊,我做了适当删减。

 function inherit(SubClass, SupClass) {
    function Bridge() {}
    Bridge.prototype = SupClass.prototype;
    
    var fn = SubClass.prototype = new Bridge();

    fn.constructor = SubClass;
}
  

—————————————-2018-5-15更新—————————————————————–

本来以为前面几个继承已经实现的差不多了,然而前几天和某位大佬讨论一番之后,却发现上边那个继承的实现方式并不是很完美,首先,js基于原型链的继承其一是出于性能考虑的,如果采用上面我深拷贝的那种方式实现的话,相当于是将父类的共有方法又拷贝了一份,不是很完美,然后这几天结合自己的思考和 es6 提供的一些方法,可以使用下面的方式更新,方法1:

 function parent(){}
function son(){}
Object.setPrototypeOf(son.prototype,parent.prototype);
  

Object.setPrototypeOf 方法可以设置一个对象的原型对象,进而通过这种方式实现继承。第二种方法是改变__proto__指向,即:

 son.prototype.__proto__ = parent.prototype;
  

然而,以上两种方式mdn都不是很推荐,具体原因可以看看上边setPrototypeOf的链接,这样做的后果就是牵涉到性能问题了,而比较推荐的方法是使用Object.create这个es5就有的方法:

 function parent(){}
function son(){}
son.prototype = Object.create( parent.prototype )
  

Object.create的第一个参数即为新创造的对象的原型对象。

因此通过这种方法实现继承,不光保证了性能,也可以动态的继承父类的公有属性。

文章来源:智云一二三科技

文章标题:js回忆录(4)——对象,构造函数

文章地址:https://www.zhihuclub.com/176508.shtml

关于作者: 智云科技

热门文章

评论已关闭

3条评论

  1. 51 The college students were adults, and so this factor of protecting the students, which was so important in the interscholastic cases, was of no importance here

网站地图