zoukankan      html  css  js  c++  java
  • 编写高质量JS代码的68个有效方法(七)

    [20141220]编写高质量JS代码的68个有效方法(七)

    No.30、理解prototype、getPrototypeOf和proto之间的不同

    Tips:

    1. C.prototype属性是new C() 创建的对象的原型
    2. Object.getPrototypeOf(obj)是ES5中检索对象原型的标准函数
    3. obj.__ proto__是检索对象原型的非标准方法
    4. 类是由一个构造函数和一个关联的原型组成的一种设计模式

    简单点说,就是prototype属性直接是创建的对象的原型;getPrototypeOf()是一个标准函数,来获取对象原型;而__ proto__则是不标准的原型属性。

    //定义一个类型
    function User(name, age){
        this.name = name;
        this.age = age;
    }
    //实例化类型
    var user = new User('Jay', 23);
    
    //原型属性prototype作用在类对象上
    User.prototype
    //非标准__proto__作用在对象实例上
    user.__proto__
    //getPrototypeOf则是Object的一个方法,参数为实例对象
    Object.getPrototypeOf(user)
    
    Object.getPrototypeOf(user) === User.prototype; // true
    User.prototype === user.__proto__; // true
    

    No.31、使用Object.getPrototypeOf()函数而不要使用__ proto__属性

    Tips:

    1. 使用符合标准的Object.getPrototypeOf()函数而不要使用非标准的__ proto__属性
    2. 在支持__ proto__属性的非ES5环境中实现Object.getPrototypeOf()函数

    由于非标准属性不具有完全兼容性,所以容易出一些奇奇怪怪的问题,不建议使用。 在支持__ proto__的非ES5标准环境下,使用下面代码来实现Object.getPrototypeOf()函数:

    if(typeof Object.getPrototypeOf === 'undefined'){
        Object.getPrototypeOf = function(obj){
            var t = typeof obj;
            if(!obj || (t !== 'object' && t !== 'function')){
                throw new TypeError('Not an object.');
            }
            return obj.__proto__;
        }
    }
    

    No.32、始终不要修改__ proto__属性

    Tips:

    1. 始终不要修改__ proto__属性
    2. 使用Object.create函数给对象设置自定义原型

    __ proto很特殊,具有修改对象原型链的能力。修改了 proto__属性可能会造成以下几个问题:

    1. 可移植性问题。并不是所有平台都支持改变对象原型的特性
    2. 性能问题。会使得引擎对JS代码的优化失效
    3. 行为不可预测。修改了__ proto__可能会破坏原有的继承体系

    No.33、使构造函数和new操作符无关

    Tips:

    1. 通过使用new操作符或Object.create方法在构造函数中调用自身使得该构造函数与调用语法无关
    2. 当一个函数期望使用new操作符调用时,清晰地文档化该函数

    同31,我们来看一下User对象:

    function User(name, age){
        this.name = name;
        this.age = age;
    }
    //如果使用new,那么会创建全新对象
    var user = new User('Jay', 23);
    
    //如果忘记使用new呢?
    var user = User('Jay', 23)
    //这个时候,该句代码,相当于调用函数,此时this在一般情况下是window,在ES5严格模式下是undefined。
    //当是window的时候,则会污染全局变量name和age,造成无法预期的问题。
    //当是undefined的时候,则会直接导致一个即时错误。
    //由于User没有显式return,导致等号左边的user的值为undefined。
    

    为了避免以上问题,可能使用以下两种方式:

    //方式一:
    //通过在函数体判断,然后调用自身的方式来实现,一定会使用new。缺点是它需要额外的函数调用,对性能有影响。
    function User(name, age){
        if(!(this instanceof User)){
            return new User(name, age);
        }
        this.name = name;
        this.age = age;
    }
    
    //方式二:
    //通过判断this,将正确的接收者赋值给self,其他函数体内需要用this的地方,全部用self代替。缺点是使用了再ES5环境中有效的Object.create()。
    function User(name, age){
        var self = this instaceof User ? this : Object.create(User.prototype);
        self.name = name;
        self.age  =age; 
    }
    
    //方式二补充,由于Object.create()只在ES5中生效,为了在旧环境中使用的话,可以使用以下方式扩充Object.create()。
    if(typeof Object.create === 'undefined'){
        Object.create = function(prototype){
            function C(){}
            C.prototype = prototype;
            return new C();
        }
    }
    

    No.34、在原型中存储方法

    Tips:

    1. 将方法存储在实例对象中将创建该函数的多个副本,因为每个实例都有一份副本
    2. 将方法存储于原型中优于存储在实例对象中

    将方法存储在原型上,那么多个实例对象会共享该原型方法。如果存储在实例上的,每创建一个实例则会创建一个函数副本,会占用更多的内存。

    No.35、使用闭包存储私有数据

    Tips:

    1. 闭包变量是私有的,只能通过局部引用获取
    2. 将局部变量作为私有数据从而通过方法实现信息隐藏

    不多说,直接上代码:

    function User(name, age){
        // 私有对象
        var privateObj = {
            name: name,
            age: age,
            sex: '男'
        }
        // 公开属性
        return {
            name: privateObj.name,
            age: privateObj.age,
            setAge: function(age){
                privateObj.age = age;
            }
        }
    }
    
    var user = new User('Jay', 23);
    console.log(user.name); // 'Jay'
    console.log(user.age);  // 23
    console.log(user.sex);  // undefined
    user.setAge(25);        
    console.log(user.age);  // 23
    

    思考:为什么最后一个user.age 是 23???

    修改如下呢:

    function User(name, age){
        // 私有对象
        var privateObj = {
            name: name,
            age: age,
            sex: '男'
        }
        // 公开属性
        return {
            name: privateObj.name,
            age: function(){
                return privateObj.age;
            }
            setAge: function(age){
                privateObj.age = age;
            }
        }
    }
    
  • 相关阅读:
    java基础部分的一些有意思的东西。
    antdvue按需加载插件babelpluginimport报错
    阿超的烦恼 javaScript篇
    .NET E F(Entity Framework)框架 DataBase First 和 Code First 简单用法。
    JQuery获得input ID相同但是type不同的方法
    gridview的删除,修改,数据绑定处理
    jgGrid数据格式
    Cannot read configuration file due to insufficient permissions
    Invoke action which type of result is JsonResult on controller from view using Ajax or geJSon
    Entity model数据库连接
  • 原文地址:https://www.cnblogs.com/humin/p/4175314.html
Copyright © 2011-2022 走看看