Vue.js 응답성 원칙에 대한 자세한 설명

小云云
풀어 주다: 2018-02-10 13:59:39
원래의
1858명이 탐색했습니다.
setters🎜🎜 . 시간이 지남에 따라 저는 Java의 대규모 🎜🎜getters🎜🎜 및 🎜🎜setter🎜🎜에 비해 코드가 더 간결해졌기 때문에 누락된 이 기능을 좋아하기 시작했습니다. 예를 들어 다음 Java 코드를 살펴보겠습니다. 🎜🎜🎜
<span style="font-size: 14px;">class Person{<br/>    String firstName;<br/>    String lastName;    // 这个Demo中省略了一些构造器代码 :)    public void setFirstName(firstName) {        this.firstName = firstName;<br/>    }    public String getFirstName() {        return firstName;<br/>    }    public void setLastName(lastName) {        this.lastName = lastName;<br/>    }    public String getLastName() {        return lastName;<br/>    }<br/>}// Create instancePerson bradPitt = new Person();<br/>bradPitt.setFirstName("Brad");<br/>bradPitt.setLastName("Pitt");<br/></span>
로그인 후 복사

JavaScript 개발자는 절대 이렇게 하지 않고 대신 이렇게 합니다.

<span style="font-size: 14px;">var Person = function () {};var bradPitt = new Person();<br/>bradPitt.firstName = &#39;Brad&#39;;<br/>bradPitt.lastName = &#39;Pitt&#39;;<br/></span>
로그인 후 복사

이것은 훨씬 간단합니다. 보통 단순함이 더 낫지 않나요?

맞습니다. 하지만 때로는 수정 가능한 속성을 얻고 싶지만 해당 속성이 무엇인지 알 필요는 없습니다. 예를 들어, Java 코드에서 새로운 메소드 <code><span style="font-size: 14px;">getFullName()</span>

<span style="font-size: 14px;">class Person{    private String firstName;    private String lastName;    // 这个Demo中省略了一些构造器代码 :)    public void setFirstName(firstName) {        this.firstName = firstName;<br/>    }    public String getFirstName() {        return firstName;<br/>    }    public void setLastName(lastName) {        this.lastName = lastName;<br/>    }    public String getLastName() {        return lastName;<br/>    }    public String getFullName() {        return firstName + " " + lastName;<br/>    }<br/>}<br/><br/>Person bradPitt = new Person();<br/>bradPitt.setFirstName("Brad");<br/>bradPitt.setLastName("Pitt");// Prints &#39;Brad Pitt&#39;System.out.println(bradPitt.getFullName());<br/></span>
로그인 후 복사

在上面例子中, <span style="font-size: 14px;">fullName</span> 是一个计算过的属性,它不是私有属性,但总能返回正确的结果。

C# 和隐式的 getter/setters

我们来看看 C# 特性之一:隐式的 <code><span style="font-size: 14px;">getters</span>/<span style="font-size: 14px;">setters</span>,我真的很喜欢它。在 C# 中,如果需要,你可以定义 <code><span style="font-size: 14px;">getters</span>/<span style="font-size: 14px;">setters</span>,但是并不用这样做,但是如果你决定要这么做,调用者就不必调用函数。调用者只需要直接访问属性,<span style="font-size: 14px;">getter</span>/<span style="font-size: 14px;">setter</span> 会自动在钩子函数中运行:

<span style="font-size: 14px;">public class Foo {    public string FirstName {get; set;}    public string LastName {get; set;}    public string FullName {get { return firstName + " " + lastName }; private set;}<br/>}<br/></span>
로그인 후 복사

我觉得这很酷...

现在,如果我想在JavaScript中实现类似的功能,我会浪费很多时间,比如:

<span style="font-size: 14px;">var person0 = {<br/>    firstName: &#39;Bruce&#39;,<br/>    lastName: &#39;Willis&#39;,<br/>    fullName: &#39;Bruce Willis&#39;,<br/>    setFirstName: function (firstName) {        this.firstName = firstName;        this.fullName = `${this.firstName} ${this.lastName}`;<br/>    },<br/>    setLastname: function (lastName) {        this.lastName = lastName;        this.fullName = `${this.firstName} ${this.lastName}`;<br/>    },<br/>};<br/>console.log(person0.fullName);<br/>person0.setFirstName(&#39;Peter&#39;);<br/>console.log(person0.fullName);<br/></span>
로그인 후 복사

它会打印出:

<span style="font-size: 14px;">"Bruce Willis"<br/>"Peter Willis"<br/></span>
로그인 후 복사

但使用 <span style="font-size: 14px;">setXXX(value)</span> 的方式并不够'JavaScripty'(是个玩笑啦)。

下面的方式可以解决这个问题:

<span style="font-size: 14px;">var person1 = {<br/>    firstName: &#39;Brad&#39;,<br/>    lastName: &#39;Pitt&#39;,<br/>    getFullName: function () {        return `${this.firstName} ${this.lastName}`;<br/>    },<br/>};<br/>console.log(person1.getFullName()); // 打印 "Brad Pitt"<br/></span>
로그인 후 복사

现在我们回到被计算过的 <span style="font-size: 14px;">getter</span>。你可以设置 <span style="font-size: 14px;">first</span><span style="font-size: 14px;">last name</span>,并简单的合并它们的值:

<span style="font-size: 14px;">person1.firstName = &#39;Peter&#39;person1.getFullName(); // 返回 "Peter Pitt"<br/></span>
로그인 후 복사

这的确更方便,但我还是不喜欢它,因为我们要定义一个叫<span style="font-size: 14px;">getxxx()</span>的方法,这也不够'JavaScripty'。许多年来,我一直在思考如何更好的使用 JavaScript。

然后 Vue 出现了

在我的Youtube频道,很多和Vue教程有关的视频都讲到,我习惯响应式开发,在更早的Angular1时代,我们叫它:数据绑定(Data Binding)。它看起来很简单。你只需要在Vue实例的 <span style="font-size: 14px;">data()</span> 块中定义一些数据,并绑定到HTML:

<span style="font-size: 14px;">var vm = new Vue({<br/>    data() {<br/>        return {<br/>        greeting: &#39;Hello world!&#39;,<br/>        };<br/>    }<br/>})<div>{greeting}</div><br/></span>
로그인 후 복사

显然它会在用户界面打印出 <span style="font-size: 14px;">“Hello world!”</span>

现在,如果你改变<span style="font-size: 14px;">greeting</span>的值,Vue引擎会对此作出反应并相应地更新视图。

<span style="font-size: 14px;">methods: {<br/>    onSomethingClicked() {        this.greeting = "What&#39;s up";<br/>    },<br/>}<br/></span>
로그인 후 복사

很长一段时间我都在想,它是如何工作的?当某个对象的属性发生变化时会触发某个事件?或者Vue不停的调用 <span style="font-size: 14px;">setInterval</span> 去检查是否更新?

通过阅读Vue官方文档,我才知道,改变一个对象属性将隐式调用<span style="font-size: 14px;">getter</span>/<span style="font-size: 14px;">setter</span>getFullName()을 확장합니다.

🎜
<span style="font-size: 14px;">/**<br/>* 给对象定义响应的属性<br/>*/export function defineReactive (<br/>    obj: Object,<br/>    key: string,<br/>    val: any,<br/>    customSetter?: ?Function,<br/>    shallow?: boolean<br/>) {    const dep = new Dep()    const property = Object.getOwnPropertyDescriptor(obj, key)    if (property && property.configurable === false) {        return<br/>    }    // 预定义getter/setters    const getter = property && property.get    const setter = property && property.set    let childOb = !shallow && observe(val)<br/>    Object.defineProperty(obj, key, {<br/>        enumerable: true,<br/>        configurable: true,        get: function reactiveGetter () {            const value = getter ? getter.call(obj) : val            if (Dep.target) {<br/>                dep.depend()                if (childOb) {<br/>                    childOb.dep.depend()<br/>                }                if (Array.isArray(value)) {<br/>                    dependArray(value)<br/>                }<br/>            }            return value<br/>        },        set: function reactiveSetter (newVal) {            const value = getter ? getter.call(obj) : val            /* 禁用eslint 不进行自我比较 */            if (newVal === value || (newVal !== newVal && value !== value)) {                return<br/>            }            /* 开启eslint 不进行自己比较 */            if (process.env.NODE_ENV !== &#39;production&#39; && customSetter) {<br/>                customSetter()<br/>            }            if (setter) {<br/>                setter.call(obj, newVal)<br/>            } else {<br/>                val = newVal<br/>            }<br/>            childOb = !shallow && observe(newVal)<br/>            dep.notify()<br/>        }<br/>    })<br/>}<br/></span>
로그인 후 복사
로그인 후 복사
🎜🎜위 예에서 🎜🎜fullName🎜🎜은 A입니다. 비공개는 아니지만 항상 올바른 결과를 반환하는 계산된 속성입니다. 🎜🎜

🎜C# 및 암시적 getters/setters🎜

🎜🎜C# 기능 중 하나를 살펴보겠습니다. 암시적 🎜🎜getters🎜🎜/🎜 🎜setters 🎜🎜 정말 마음에 듭니다. C#에서는 원할 경우 🎜🎜getters🎜🎜/🎜🎜setters🎜🎜을 정의할 수 있지만 반드시 그럴 필요는 없지만 결정한다면 호출자는 함수를 호출할 필요가 없습니다. 호출자는 속성에 직접 액세스하기만 하면 되며 🎜🎜getter🎜🎜/🎜🎜setter🎜🎜는 자동으로 후크 기능에서 실행됩니다. 🎜🎜
<span style="font-size: 14px;">var person2 = {<br/>    firstName: &#39;George&#39;,<br/>    lastName: &#39;Clooney&#39;,<br/>};<br/>Object.defineProperty(person2, &#39;fullName&#39;, {<br/>    get: function () {        return `${this.firstName} ${this.lastName}`;<br/>    },<br/>});<br/>console.log(person2.fullName); // 打印 "George Clooney"<br/></span>
로그인 후 복사
로그인 후 복사
🎜🎜 I 정말 멋지다고 생각합니다... 🎜🎜🎜🎜 이제 JavaScript에서 이와 같은 것을 구현하려면 다음과 같이 많은 시간을 낭비하게 됩니다. 🎜🎜rrreee🎜🎜 다음과 같이 인쇄됩니다. 🎜setXXX(value)🎜🎜는 'JavaScripty'가 충분하지 않습니다(농담입니다). 🎜🎜🎜🎜다음 방법으로 이 문제를 해결할 수 있습니다. 🎜🎜rrreee🎜🎜이제 계산된 🎜🎜getter🎜🎜으로 돌아갑니다. 🎜🎜first🎜🎜 또는 🎜🎜last name🎜🎜을 설정하고 간단히 해당 값을 병합할 수 있습니다. 🎜🎜rrreee🎜🎜이것이 실제로 더 편리하지만 여전히 그렇지 않습니다. 마음에 들지 않습니다. 🎜🎜getxxx()🎜🎜라는 메서드를 정의해야 하기 때문입니다. 이 메서드도 'JavaScripty'로는 충분하지 않습니다. 수년 동안 저는 JavaScript를 더 잘 사용하는 방법에 대해 생각해 왔습니다. 🎜🎜

🎜그리고 나서 Vue가 등장했습니다🎜

🎜🎜제 유튜브 채널에는 Vue 튜토리얼과 관련된 많은 영상이 언급되어 있습니다. 저는 초기 Angular1 시대에는 이를 :Data Binding이라고 불렀습니다. 간단해 보입니다. Vue 인스턴스의 🎜🎜data()🎜🎜 블록에서 일부 데이터를 정의하고 HTML에 바인딩하면 됩니다. 🎜🎜rrreee🎜🎜분명히 UI에 인쇄됩니다 🎜 🎜"안녕하세요!"🎜🎜. 🎜🎜🎜🎜이제 🎜🎜greeting🎜🎜 값을 변경하면 Vue 엔진이 이에 반응하고 그에 따라 뷰를 업데이트합니다. 🎜🎜rrreee🎜🎜 오랫동안 궁금했는데 어떻게 작동하나요? 객체의 속성이 변경되면 이벤트가 트리거됩니까? 아니면 Vue가 업데이트되었는지 확인하기 위해 🎜🎜setInterval🎜🎜을 계속 호출합니까? 🎜🎜🎜🎜공식 Vue 문서를 읽으면서 객체 속성을 변경하면 암시적으로 🎜🎜getter🎜🎜/🎜🎜setter🎜🎜가 호출된다는 사실을 알게 되었습니다. 저에게 알려주세요. 아래와 같이 Observer를 다시 실행한 다음 다시 렌더링을 트리거합니다. 이 예는 공식 Vue.js 문서에서 가져온 것입니다. 🎜🎜

Vue.js 응답성 원칙에 대한 자세한 설명

但我还想知道:

  • 怎么让数据自带<span style="font-size: 14px;">getter</span>/<span style="font-size: 14px;">setters</span>

  • 这些隐式调用内部是怎样的?

第一个问题很简单:Vue为我们准备好了一切。当你添加新数据,Vue将会通过其属性为其添加 <span style="font-size: 14px;">getter</span>/<span style="font-size: 14px;">setters</span>。但是我让 <span style="font-size: 14px;">foo.bar = 3</span>? 会发生什么?

这个问题的答案出现在我和SVG & Vue专家Sarah Drasner的Twitter对话中:

Vue.js 응답성 원칙에 대한 자세한 설명

Timo: <span style="font-size: 14px;">foo.bar=value;</span>是怎么做到实时响应的?

Sarah: 这个问题很难在Twitter说清楚,可以看这篇文章

Timo: 但这篇文章并没有解释上面提到的问题。

Timo: 它们就像:分配一个值->调用<span style="font-size: 14px;">setter</span>->通知观察者,不理解为什么在不使用<span style="font-size: 14px;">setInterval</span><span style="font-size: 14px;">Event</span>的情况下,<span style="font-size: 14px;">setter</span>/<span style="font-size: 14px;">getter</span>就存在了。

Sarah: 我的理解是:你获取的所有数据都在Vue实例<span style="font-size: 14px;">data{}</span>中被代理了。

显然,她也是参考的官方文档,之前我也读过,所以我开始阅读Vue源码,以便更好的理解发生了什么。过了一会我想起在官方文档看到一个叫 <span style="font-size: 14px;">Object.defineProperty()</span> 的方法,我找到它,如下:

<span style="font-size: 14px;">/**<br/>* 给对象定义响应的属性<br/>*/export function defineReactive (<br/>    obj: Object,<br/>    key: string,<br/>    val: any,<br/>    customSetter?: ?Function,<br/>    shallow?: boolean<br/>) {    const dep = new Dep()    const property = Object.getOwnPropertyDescriptor(obj, key)    if (property && property.configurable === false) {        return<br/>    }    // 预定义getter/setters    const getter = property && property.get    const setter = property && property.set    let childOb = !shallow && observe(val)<br/>    Object.defineProperty(obj, key, {<br/>        enumerable: true,<br/>        configurable: true,        get: function reactiveGetter () {            const value = getter ? getter.call(obj) : val            if (Dep.target) {<br/>                dep.depend()                if (childOb) {<br/>                    childOb.dep.depend()<br/>                }                if (Array.isArray(value)) {<br/>                    dependArray(value)<br/>                }<br/>            }            return value<br/>        },        set: function reactiveSetter (newVal) {            const value = getter ? getter.call(obj) : val            /* 禁用eslint 不进行自我比较 */            if (newVal === value || (newVal !== newVal && value !== value)) {                return<br/>            }            /* 开启eslint 不进行自己比较 */            if (process.env.NODE_ENV !== &#39;production&#39; && customSetter) {<br/>                customSetter()<br/>            }            if (setter) {<br/>                setter.call(obj, newVal)<br/>            } else {<br/>                val = newVal<br/>            }<br/>            childOb = !shallow && observe(newVal)<br/>            dep.notify()<br/>        }<br/>    })<br/>}<br/></span>
로그인 후 복사
로그인 후 복사

所以答案一直存在于文档中:

把一个普通 JavaScript 对象传给 Vue 实例的 <span style="font-size: 14px;">data</span> 选项,Vue 将遍历此对象所有的属性,并使用 <span style="font-size: 14px;">Object.defineProperty</span> 把这些属性全部转为 <span style="font-size: 14px;">getter</span>/<span style="font-size: 14px;">setter</span><span style="font-size: 14px;">Object.defineProperty</span> 是仅 ES5 支持,且无法 <span style="font-size: 14px;">shim</span> 的特性,这也就是为什么 Vue 不支持 IE8 以及更低版本浏览器的原因。

我只想简单的了解 <span style="font-size: 14px;">Object.defineProperty()</span> 做了什么,所以我用一个例子简单的给你讲解一下:

<span style="font-size: 14px;">var person2 = {<br/>    firstName: &#39;George&#39;,<br/>    lastName: &#39;Clooney&#39;,<br/>};<br/>Object.defineProperty(person2, &#39;fullName&#39;, {<br/>    get: function () {        return `${this.firstName} ${this.lastName}`;<br/>    },<br/>});<br/>console.log(person2.fullName); // 打印 "George Clooney"<br/></span>
로그인 후 복사
로그인 후 복사

还记得文章开头C#的隐式 <span style="font-size: 14px;">getter</span> 吗?它们看起来很类似,但ES5才开始支持。你需要做的是使用 <span style="font-size: 14px;">Object.defineProperty()</span> 定义现有对象,以及何时获取这个属性,这个<span style="font-size: 14px;">getter</span>被称为响应式——这实际上就是Vue在你添加新数据时背后所做的事。

<span style="font-size: 14px;">Object.defineProperty()</span>能让Vue变的更简化吗?

学完这一切,我一直在想,<span style="font-size: 14px;">Object.defineProperty()</span> 是否能让Vue变的更简化?现今越来越多的新术语,是不是真的有必要把事情变得过于复杂,变的让初学者难以理解(Redux也是同样):

  • <span style="font-size: 14px;">Mutator</span>:或许你在说(隐式)<span style="font-size: 14px;">setter</span>

  • <span style="font-size: 14px;">Getters</span>:为什么不用 <span style="font-size: 14px;">Object.defineProperty()</span> 替换成(隐式)<span style="font-size: 14px;">getter</span>

  • <span style="font-size: 14px;">store.commit()</span>:为什么不简化成 <span style="font-size: 14px;">foo = bar</span>,而是 <span style="font-size: 14px;">store.commit("setFoo", bar);</span>

你是怎么认为的?Vuex必须是复杂的还是可以像 <span style="font-size: 14px;">Object.defineProperty()</span> 그렇게 쉽나요?

관련 권장 사항:

반응형 개발 예제 공유를 위해 rem을 사용하는 javascript

프런트 엔드 반응형 레이아웃, 반응형 이미지 및 직접 만든 그리드 시스템에 대한 자세한 설명

res 폰세 뭐 수식과 적응의 차이입니다

위 내용은 Vue.js 응답성 원칙에 대한 자세한 설명의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

관련 라벨:
원천:php.cn
본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
인기 튜토리얼
더>
최신 다운로드
더>
웹 효과
웹사이트 소스 코드
웹사이트 자료
프론트엔드 템플릿