• JavaScript内置一些方法的实现原理--Object.freeze()、instanceof


    const定义的常量,一般是不能修改的。

    比如:

    1 const TIME_OUT = 10000;

    但是当值为引用类型值时,还是可以操作对象,扩展或修改对象属性、方法等等。

    以下演示代码的操作是不会报错,且行之有效的。。

    1 const person = {
    2   name: 'xm'
    3 }
    4 person.age = 18;
    5 person.name = 'xh';

    ES6(?)在Object上添加了一个静态方法freeze() ,可以禁止修改、扩展引用类型值。

    用法就是把person作为参数传入该方法中。如:

    1 const person = {
    2   name: 'xm'
    3 }
    4 console.log(person);// {name: 'xm'};
    5 Object.freeze(person);
    6 person.age = 18;
    7 person.name = 'xh';
    8 console.log(person);// {name: 'xm'};

    好厉害,这下子就成了名副其实的常量了。emm....

    freeze方法实现原理的简单模拟

    要使用的到方法包括Object.definedProperty()、Object.seal()

    Object.definedProperty()方法可以定义对象的属性的特性。如可不可以删除、可不可以修改、访问这个属性的时候添油加醋等等。。

    用法(详见高级程序设计P139):

    1 Object.defineProperty(person, 'name', {
    2   configurable: false,// 表示能否通过delete删除属性,能否修改属性的特性...
    3   enumerable: false,// 表示是否可以枚举。直接在对象上定义的属性,基本默认true
    4   writable: false,// 表示能否修改属性的值。直接在对象上定义的属性,基本默认true
    5   value: 'xm'// 表示属性的值。访问属性时从这里读取,修改属性时,也保存在这里。
    6 })

    通过以上代码的设置,name属性就变成了不能删除、不可重新修改特性、不可枚举、不能修改的属性值的属性了。

    测试结果:

    非常重要的一个方法。以上就是它的简单用法以及实现效果。

    Object.seal()方法可以让对象不能被扩展、删除属性等等。用法:Object.seal(person);

    有了这两个方法,就可以实现一个简单的freeze()方法了。代码演示:

     1 function myFreeze(obj) {
     2   if (obj instanceof Object) {
     3     Object.seal(obj);
     4     let p;
     5     for (p in obj) {
     6       if (obj.hasOwnProperty(p)) {
     7         Object.defineProperty(obj, p, {
     8           writable: false
     9         });
    10         myFreeze(obj[p]);// 递归,实现更深层次的冻结
    11       }
    12     }
    13   }
    14 }

    以上函数先判断传入参数是否为Object类型。为真,接着封闭对象。for in 循环遍历对象。

    剔除原型属性,设置属性的writable特性为false。递归调用该函数,传入属性值。

    测试结果:

    学习完一个。再接再厉。

    来实现一下instanceof 操作符吧

    instanceof的大致效果是:当左边是基本类型值时,一律返回false。 当左边是引用类型值时,如果右边的原型对象,在左边的原型链上存在,返回真,否则假。

    有了大概的使用效果,加上一些方法。就可以实现一个简单的instanceof操作符了。代码演示:

    1 function myInstanceof(leftVal, rightFunc) {
    2   if (typeof rightFunc !== 'function') throw new Error('第二个参数请传入构造函数名');
    3   return rightFunc.prototype.isPrototypeOf(leftVal);
    // F.prototype.isPrototypeOf(obj)判断obj的原型指针是否指向传入构造函数的原型对象,这个过程会往上层层判断。
    // 比如,以下验证myInstanceof(xm, Object);xm的原型指针指向Person.prototype,
    Person.prototype的原型指针指向Object.prototype。所以返回true。

    4 }

    验证结果:

    其他一些实现方法:

    1 function myInstanceof(leftVal, rightFunc) {
    2   if (typeof rightFunc !== 'function') throw new Error('第二个参数请传入构造函数名');
    3   if (typeof leftVal !== 'object' || leftVal === null) return false;
    4   if (leftVal.__proto__ === rightFunc.prototype) {// __proto__原型指针
    5     return true;
    6   } else {
    7     return myInstanceof(leftVal.__proto__, rightFunc);
    8   }
    9 }

    以上利用浏览器在对象上布置的__proto__属性、加递归调用实现判断。

     1 function myInstanceof(leftVal, rightFunc) {
     2   if (typeof rightFunc !== 'function') throw new Error('第二个参数请传入构造函数名');
     3   if (typeof leftVal !== 'object' || leftVal === null) return false;
     4   let _proto = Object.getPrototypeOf(leftVal);
     5   while (_proto) {
     6     if (_proto === rightFunc.prototype) {
     7       return true;
     8     }
     9     _proto = Object.getPrototypeOf(_proto);
    10   }
    11   return false;
    12 }

    以上利用Object.getPrototypeOf()方法获取对象的原型,利用while循环层层递进。都没有,最后Object.getPrototypeOf()值为null。

  • 相关阅读:
    bootstrap中的动态加载出来的图片轮播中的li标签中的class="active"的动态添加移除
    细碎的小定义的记录
    jQuery动态添加的元素中处理字符串溢出后在指定字符数后添加省略号
    ASP.NET中扩展FileUpload的上传文件的容量
    SVN错误:Attempted to lock an already-locked dir
    Eclipse中jsp、js文件编辑时,卡死现象解决汇总(转)
    修改weblogic端口的方法
    oracle 使用触发器实现id自增
    nui UI 具有右键属性的菜单树
    eclipse中 将java项目转换为web项目
  • 原文地址:https://www.cnblogs.com/caimuguodexiaohongmao/p/11173436.html
Copyright © 2020-2023  润新知