[フロントエンドインタビューの質問]Vueレスポンシブ原則(defineProperty、defineReactive、Observer)-オブジェクトオブジェクト

1.ガイダンス

1.MVVMパターン

Vueがモデル、ビュー-モデル、ビューを含むMVVMパターンであることは誰もが知っています。
模板:

<div>年龄:{
   
   {age}}</div>

数据变化:

this.age ++;

データが変化すると、それに伴ってビューも変化します。ここで、ビューモデルが機能します。
ここに画像の説明を挿入

2.侵入型および非侵入型

侵入型とは、関数を呼び出さずにデータを直接変更することでビューを変更できることを意味します。
邪魔にならないのは、データを変更する関数を呼び出してビューを変更することです。
ここに画像の説明を挿入
那为什么Vue可以实现非侵入式的效果的——如何实现数据响应式?

第二に、Object.defineProperty()の理解-応答性の中核

Object.defineProperty()メソッドは、オブジェクトに直接新しいプロパティを定義するか、オブジェクトの既存のプロパティを変更して、オブジェクトを返します。
可以检测对象属性变化,实现数据劫持和数据代理

1、値、書き込み可能、​​列挙可能

var obj = {
    
    };
Object.defineProperty(obj, 'a', {
    
    
    //给a属性定义值
    value: 6,
    //是否可写
    writable: false,
    //是否可以被枚举
    enumerable: true
})
Object.defineProperty(obj, 'b', {
    
    
    //给a属性定义值
    value: 10,
    //是否可以被枚举
    enumerable: false
})
console.log('obj.a', obj.a);//6
obj.a = 10
console.log('obj.a', obj.a);//6:因为设置了不可写
for (const key in obj) {
    
    
    console.log('可枚举', key);//只会输出a,因为b设置了不可被枚举
}

ここに画像の説明を挿入

2、get、set

var obj = {
    
    };
Object.defineProperty(obj, 'c', {
    
    
    //getter:数据劫持
    get() {
    
    
        console.log("正在访问c属性")
    },
    //setter
    set() {
    
    
        console.log('正在改变c属性')
    }
})
obj.c++;//自增有访问也有改变
obj.c = 10;//赋值只有改变
console.log(obj.c);//undefined

ここに画像の説明を挿入

3、defineReactive関数(カスタム関数)

obj.cが未定義であるという問題を解決します

因为getter函数(get)需要有一个返回值,这个返回值就是属性的值(get和value不能共存)

var obj = {
    
    };
Object.defineProperty(obj, 'c', {
    
    
    //getter:数据劫持
    get() {
    
    
        console.log("正在访问c属性");
        return 7
    },
    //setter
    set() {
    
    
        console.log('正在改变c属性')
    }
})
obj.c++;//自增有访问也有改变
obj.c = 10;//赋值只有改变
console.log(obj.c);//7

ここに画像の説明を挿入
当属性值被修改时,会调用此函数。该方法接受一个参数(也就是被赋予的新值),会传入赋值时的 this 对象。

var obj = {
    
    };
Object.defineProperty(obj, 'c', {
    
    
    //getter:数据劫持
    get() {
    
    
        console.log("正在访问c属性");
        return 7
    },
    //setter
    set(newValue) {
    
    
        console.log('正在改变c属性', newValue)
    }
})
obj.c++;//自增有访问也有改变
obj.c = 10;//赋值只有改变
console.log(obj.c);//7 因为get返回的依旧是7

ここに画像の説明を挿入
最终解决方案:

var obj = {
    
    };
var temp;
Object.defineProperty(obj, 'c', {
    
    
    //getter:数据劫持
    get() {
    
    
        console.log("正在访问c属性");
        return temp;
    },
    //setter
    set(newValue) {
    
    
        console.log('正在改变c属性', newValue)
        temp = newValue
    }
})
obj.c++;//自增有访问也有改变
obj.c = 10;//赋值只有改变
console.log(obj.c);//10

ここに画像の説明を挿入
成功修改!!!

自定义defineReactive函数

//自定义defineReactive函数
function defineReactive(data, key, val) {
    
    
    Object.defineProperty(data, key, {
    
    
        //可枚举
        enumerable: true,
        //可以被delete
        configurable: true,
        //getter:数据劫持
        get() {
    
    
            console.log("正在访问" + key + "属性");
            return val;
        },
        //setter
        set(newValue) {
    
    
            console.log("正在改变" + key + "属性", newValue)
            if (val !== newValue) {
    
    
               val = newValue
            }
        }
    })
}
var obj = {
    
    };
defineReactive(obj, 'c', 10)
console.log(obj.c);//10

ここに画像の説明を挿入

3.オブジェクトのすべてのプロパティの再帰的検出(Observer、observe、defineReactiveはループと再帰的な関係です)

マルチレイヤーオブジェクトのハイジャックは、上記で定義したdefineReactive関数を使用して実行することはできません。

//自定义defineReactive函数(data->要访问的对象,key->对象中的属性,val->要修改的属性值【闭包】)
function defineReactive(data, key, val) {
    
    
    console.log("defineReactive", key);
    //可以传两个参数
    if (arguments.length === 2) {
    
    
        val = data[key]
    }
    observe(val);
    Object.defineProperty(data, key, {
    
    
        //可枚举
        enumerable: true,
        //可以被delete
        configurable: true,
        //getter:数据劫持
        get() {
    
    
            console.log("正在访问" + key + "属性");
            return val;
        },
        //setter
        set(newValue) {
    
    
            console.log("正在改变" + key + "属性", newValue)
            if (val !== newValue) {
    
    
                val = newValue
                observe(newValue);
            }
        }
    })
}
//设置属性能否被枚举
function def(data, key, value, enumerable) {
    
    
    Object.defineProperty(obj, key, {
    
    
        value,
        enumerable,
        writable: true,
        configurable: true
    })
}
//能将object转化为每个层级的属性都是响应式的——可以被侦测的object
class Observer {
    
    
    constructor(value) {
    
    
        //给实例添加__ob__属性,不可以被枚举,value为实例
        def(value, '__ob__', this, false);
        console.log("构造器", value)
        this.walk(value)
    }
    //遍历
    walk(value) {
    
    
        for (const key in value) {
    
    
            defineReactive(value, key)
        }
    }
}
//创建observe函数,首先判断
function observe(val) {
    
    
    if (typeof val !== 'object') return;
    var ob;
    if (typeof val.__ob__ !== 'undefined') {
    
    
        ob = val.__ob__;
    } else {
    
    
        ob = new Observer(val);
    }
    return ob

}
var obj = {
    
    
    a: {
    
    
        m: {
    
    
            n: 5
        }
    },
    b: 10
}
observe(obj);
console.log(obj.a.m.n);

ここに画像の説明を挿入

ここに画像の説明を挿入

上記はVueリアクティブの原則(defineProperty、defineReactive、Observer)です。オブジェクトオブジェクトのコンテンツです。「フロントエンドインタビューの質問」列に注目してください。
の通常のプロジェクトに共通する問題筆記試験の知識を共有し、CSDNであなたと面接し、一緒に進歩します。さあ。

おすすめ

転載: blog.csdn.net/weixin_46318413/article/details/122763712