美文网首页
原型原型链,属性的扩展

原型原型链,属性的扩展

作者: 悲欢自饮丶 | 来源:发表于2017-10-26 17:18 被阅读0次

    原型和原型链

    原型

    • 所有的变量都有一个隐式原型proto属性(错)
    • 所有的对象都有一个隐式原型proto属性(对)
    • 所有的函数都有一个显式原型prototype属性(错)
    • 所有的构造函数都有一个显式原型prototype属性(对)
    • 属性值:原型对象
    • 构造函数prototype指向一个空的Object对象(错)
    • 所有构造函数prototype__proto__指向Object的prototype(对)

    将伪数组转化为真数组&怎么判断一个变量是不是数组

    • 它从 Array.prototype 中继承了一些它的专属方法,如 push() , pop() , sort() , slice() , splice() 等,这些方法在伪数组和Object对象中是没有的。
    • slice方法返回一个从开始到结束(不包括结束)选择的数组的一部分浅拷贝到一个新数组对象。原始数组不会被修改。
    • obj instanceof Array可以判断是否为数组
        var arr = {length:3,0:"a",1:"b",2:"c"};
            arr.push('d');//报错 伪数组不能使用数组的方法
            var arr2 = Array.prototype.slice.call(arr);
            arr2.push("d")
            console.log(arr2)
    

    默认值

    • Array.prototype指向一个空数组
    • Function.prototype指向一个空的Function
    • map() 方法创建一个新数组,其结果是该数组中的每个元素都调用一个提供的函数后返回的结果。
    • join() 方法将数组(或一个类数组对象)的所有元素连接到一个字符串中。
        function test(arr,fn){
                arr =arr||Array.prototype;
                fn =fn||Function.prototype;
    
                return arr.map(fn).join(" ");
            }
            console.log(test());
    

    ==的使用规则

    • 引用数据类型进行比较时:
      • 先调用本身的valueof(),如果valueof方法返回的基本数据类型则直接做比较
      • 如果valueof()返回的不是基本数据类型,则调用比较对象本身的tostring()
    • 基本数据进行比较时:
      • 先通过number()转化成一个number类型后再做比较
      //正常情况下[""]的valueof方法返回原数组[""]
        再调用[""].tostring()返回""
        再调用number()返回0
      console.log([""]==false)//true
    
      //方法的重写
      Array.prototype.valueof = function(){
        return 1;
      }
      console.log([""]==flase)//false
    

    原型链的继承

    • 模拟jQuery中的html() on()
    • 体现出jQuery的链式调用 读写二合一
      //构造函数   new Element()--->返回一个真实的dom节点
      function Element(id){
           this.ele = document.getElementById(id);
        }
    
        Element.prototype.innerText= function(val){
           var ele = this.ele;
           if(val){
             ele.innerText = val;
             return this;//链式调用
           }else{
             return ele.innerText;
           }
         }
    
       Element.prototype.on = function(val,fn){
                var ele = this.ele;
                if(ele.addEventListener){
                    ele.addEventListener(val,fn);
                    return this
                }
            }
    
         var textNode = new Element("test");
         textNode.innerText("text")//写
         textNode.innerText("text").innerText()//链式调用
         console.log(textNode.innerText("text").innerText())//读
    
         textNode.on("click",function(){
                alert(1);
            }).innerText('text')
    

    综合面试题

        //运算符的优先级
            //左右查询
            //原型链
            //this
            //属性的查找
            //提升
    
            function getName() {
                alert (5);
            }
            function Foo() {
                getName = function () { alert (1); };
                return this;
            }
    
            Foo.getName = function () {
                alert (2);
            };
            Foo.prototype.getName = function () {
                alert (3);
            };
            var getName = function () {
                alert (4);
            };
    
            Foo.getName(); //2
            getName();//4
            Foo().getName(); //1
            getName(); //1
            new Foo.getName(); //2
            new Foo().getName()//3
    

    原型&原型链

    • 原型对象:它不是一个空的Object对象,但是它的proto永远指向Object的prototype
    • 原型链的头
        Object.prototype.__proto__===>null
            Function.__proto__ === Function.prototype
            Object.__proto__  === Function.prototype
            Function.prototype.__proto__ === Object.prototype
            Object.prototype.__proto__=== null
    

    javascript中的属性

    变量的查找

    • 左查询,右查询

    属性描述符(元属性)

    • 修饰属性的属性(元属性)
    • 获取对应属性的描述符
      • Object.getOwnPropertyDescriptor(obj,"name")

        第一个参数:对应的对象;第二个参数:对应对象的属性
    • writable决定是否可以修改属性的值
      • 一般和value绑定在一起
      • 当writable为false时,对应的属性的值是无法修改的。

        在默认情况下:继续修改的话会静默失败

        在严格模式下:会报错
    • configurable来决定属性是否可以配置
      • 是否可以被delete
      • 删除

        configurable:true 可以删

        configurable:false 不可以删
      • 重新配置

        能不能重新定义属性的描述符

        configurable:true 可以重新配置

        configurable:false

        writable可以从true变为false

        其他两个属性不可以动
        var damu={};
            Object.defineProperty(damu,"age",{
                value:18,
                writable:true
            })
    
            Object.defineProperty(damu,"age",{
                value:19,
                configurable:true//报错
            })
        console.log(damu)//age:19
    
        var a=3;
            b=4;
    
            console.log(Object.getOwnPropertyDescriptor(window,"a"))
            console.log(Object.getOwnPropertyDescriptor(window,"b"))
    
            delete a;//a configurable:false不能删除
            delete b;//b configurable:true可以被删除
    
            console.log(a)//3
            console.log(b)//报错
    
    • enumerable可枚举:能否出现在对象的for in循环
      • 判断属性是否可枚举(不会遍历原型链)obj.propertyIsEnumerable("a")
      • 获取可枚举属性列表(不会遍历原型链)Object.keys(obj)
      • 获取所有属性的列表(不会遍历原型链)Object.getOwnPropertyNames(obj)
        var damu={};
            Object.defineProperty(damu,"a",{
                enumerable:false
            })
            Object.defineProperty(damu,"b",{
                enumerable:true
            })
            Object.defineProperty(damu,"c",{
                enumerable:true
            })
            Object.defineProperty(damu,"d",{
                enumerable:true
            })
            Object.defineProperty(damu,"e",{
                enumerable:false
            })
            Object.defineProperty(damu,"f",{
                enumerable:false
            })
    
        for(item in damu){
                console.log(item);//输出b,c,d
            }
    
            for(item in damu){
                if(damu.hasOwnProperty(item)){
                    console.log(item);
                }
            }
    
        Object.defineProperty(Object.prototype,"text",{
          value:"text"
            enumerable:true
        })
        console.log(damu.text)//text可以找到
    
        console.log(damu.propertyIsEnumerable("f"))//false
        console.log(damu.propertyIsEnumerable("text"))//false不会在原型链上找
        console.log(Object.keys(damu));//可枚举类型(不会在原型链上找)
        console.log(Object.getOwnPropertyNames)//所有属性列表(不会在原型链上找)
    

    定义对象属性的两种方法

    • 语法糖(让定义对象更简单)
      • 默认属性描述符都为true
        var damu={
                wife:"zdy"
            }
            damu.wife="fbb";
        console.log(damu);
    
    • 普通定义
      • 默认属性描述符都为false
        var damu={}
            Object.defineProperty(damu,"age",{
                value:18
            })
            console.log(damu);
    

    对象的不变性

    对象的常量属性

    • 将属性的writableconfigurable设置为false

    禁止对象扩展

    • Object.preventExtensions(obj)传入一个对象

    密封对象

    • 在禁止对象扩展Object.preventExtensions(obj)的基础上把现有属性的configurable都调整为false
    • 调用Object.seal(obj)密封一个对象
    • 密封之后禁止了对象去扩展属性,原有的属性不可以进行重新定义或者删除,但属性值是可以修改的

    冰封对象

    • 在密封对象(Object.seal(obj))的基础上把现有属性的writable都调整为false
    • 调用Object.freeze(obj)密封一个对象
    • 冻结之后禁止了对象去扩展属性,原有的属性不可以进行重新定义或者删除,属性值不可以进行修改

    深度冻结对象

    • 在js中!!!所有方法的创建都是浅不变形的,他们只会影响目标对象和他的直接属性
    • 一般项目中不会深度冻结对象(如果需要使用,考虑是不是设计错误)
    • 如果使用深度冻结对象时需要使用for in一直循环
        var obj={
                hoddy:{
                    hoddy1:"a",
                    hoddy2:"b",
                    hoddy3:"c",
                    hoddy4:"d",
                    hoddy5:"e"
                }
            };
    
            Object.freeze(obj);
            obj.hoddy.hoddy1 = "g"//hoddy1会发生改变
            console.log(obj)
    
        for(item in obj){
          Object.freeze(obj[item]);
        }
    

    存在性检查

    • in(会遍历原型链)"a" in obj
    • hasOwnProperty(不会遍历原型链,只在对象中查找)obj.hasOwnProperty("a")

    访问描述符

    • 当你给一个属性定义set或者get,或者两者都有时,这个属性会被定义为访问描述符
    • 对于访问描述符来说,Javascript会忽略他们的value和writable特性。取而代之的是set和get函数。
    • value writableset get只能有一组
    • 访问描述符可以使我们在对属性进行取赋值操作时预先变规定逻辑(比如if else)
    • 访问描述符可以使我们的属性变的更加安全!!!!封装

    总结

    • 属性描述符

      用来修饰属性的属性(元属性) 5个
    • 数据描述符

      具有writable和value属性描述符的属性 我们称之为数据描述符
    • 访问描述符

      具有set和get属性描述符的属性 我们称之为访问描述符
    • writable为true的数据描述符
      • 属性的查找:在实例对象的直接属性没有找到对应的属性则上原型链,如果整条原型链都没有该属性,返回undefined
      • 属性的设置:不管什么情况,设置操作只会影响对象的直接属性

    属性的查找

    • 在对象中查找是否具有相同名称的属性,如果找到,就会返回这个属性的值。
    • 如果没有找到,则遍历原型链
    • 无论·如何都没找到,返回undefined

    属性的设置

    • 如果属性直接存在于对象中 不在原型链上(或者属性直接存在于对象中 也在原型链上) 找到直接存在于对象中的属性
      • 数据描述符(没有setter/getter):直接修改对象中的属性的值(注意writbale的值)
      • 访问描述符:直接调用set方法
    • 如果属性不直接存在于对象中 在原型链上
      • 该属性是数据描述符(没有setter/getter)
        • writbale为true

          直接在对象中添加一个属性,我们称之为屏蔽属性
        • writbale为false

          报错,不会生成屏蔽属性
      • 该属性是访问描述符

        调用set,不会生成屏蔽属性
    • 如果属性不直接存在于对象中 也不在原型链上 在对象的直接属性中添加一个属性(数据描述符)

    相关文章

      网友评论

          本文标题:原型原型链,属性的扩展

          本文链接:https://www.haomeiwen.com/subject/flbkpxtx.html