前端getPrototypeOf 、setPrototypeOf、defineProperty用法

368 阅读2分钟

本文已参与「 新人创作礼 」活动,一起开启掘金创作之路

关于如何进行图片优化 - 适合的才是最好的

昨天关于实现一个intanceof 是通过链式查找prototype的比对。

其中一个非常重要的方法就是。Object.getPrototypeOf

当然这个方法目前几乎我们不用去考虑兼容性,ie9 以上都对这个方法进行了支持。

chrome就不用说了,其他暂时忽略。

Object.setPrototypeOf()是ECMAScript 6最新草案中的方法,相对于Object.prototype.__proto__

如果这么理解起来是不是很难在实际工作中应用起来。

关于前端JS继承的方式那是提多了,有class方式,组合  prototype的方式,Object.create。但是今天的主角是 setPrototypeOf。

simple Demo:

function fn(name) {
  this.name = name;
}
fn.prototype.sayName = function () {
  return  this.name;
}

let obj = {}
Object.setPrototypeOf(obj,fn.prototype);
fn.call(obj , 'cc');

console.log (obj.name);
console.log (obj.sayName());

这样组合起来不是更加觉得亲切。

chrome 版本字2014年的版本就支持了setPrototypeOf

如果在这个之前我们改如何使用呢, 我这里并不是让大家去造轮子,只是借用这个方法,让大家更深刻了解setPrototypeOf 的真正实现而已。

if (!Object.setPrototypeOf) {
    // 仅适用于Chrome和FireFox,在IE中不工作:
     Object.prototype.setPrototypeOf = function(obj, proto) {
         if(obj.__proto__) {
             obj.__proto__ = proto;
             return obj;
         } else {
             // 如果你想返回 prototype of Object.create(null):
             var Fn = function() {
                 for (var key in obj) {
                     Object.defineProperty(this, key, {
                         value: obj[key],
                     });
                 }
             };
             Fn.prototype = proto;
             return new Fn();
         }
     }
}

这段代码来自 : 查看mozilla 

主要还是通过__proto__的肤质操作。

如果发现obj部位构造,那就在自定义的function ,然后通过defineProperty进行属性绑定。defineProperty属性其实功能超级超大,例如数据监听等。最早期的MVVM MV框架有些就是依赖这些底层方法实现的。

还有一些继承的最后经过babel转译也是通过defineProperty。

"use strict";

var _createClass = function () {
    function defineProperties(target, props) {
        for (var i = 0; i < props.length; i++) {
            var descriptor = props[i];
            descriptor.enumerable = descriptor.enumerable || false;
            descriptor.configurable = true;
            if ("value" in descriptor) descriptor.writable = true;
            Object.defineProperty(target, descriptor.key, descriptor);
        }
    }

    return function (Constructor, protoProps, staticProps) {
        if (protoProps) defineProperties(Constructor.prototype, protoProps);
        if (staticProps) defineProperties(Constructor, staticProps);
        return Constructor;
    };
}();

function _classCallCheck(instance, Constructor) {
    if (!(instance instanceof Constructor)) {
        throw new TypeError("Cannot call a class as a function");
    }
}

var Parent = function () {
    function Parent(name, age) {
        _classCallCheck(this, Parent);

        this.name = name;
        this.age = age;
    }

    _createClass(Parent, [{
        key: "speakSomething",
        value: function speakSomething() {
            console.log("I can speek chinese");
        }
    }]);

    return Parent;
}();

这个一个类构造通过babel转译后的代码。

仔细看这个代码还是非常的有意思,其实通过es6的类构造的代码非常之少。

class Parent {
    constructor(name,age){
        this.name = name;
        this.age = age;
    }
    speakSomething(){
        console.log("I can speek chinese");
    }
}

这就是前端babel转译的魅力了。

今天先到这里,困了,明天继续分享。