├── .eslintrc
├── .gitignore
├── .travis.yml
├── LICENSE
├── README.en.md
├── README.md
├── bower.json
├── dev
├── index.html
├── index.js
└── webpack.config.js
├── dist
├── smart-observe.js
├── smart-observe.js.map
├── smart-observe.min.js
└── smart-observe.min.js.map
├── package.json
├── rollup.config.js
├── src
├── array.js
├── batcher.js
├── constants.js
├── dep.js
├── expression.js
├── index.js
├── observe.js
├── util.js
└── watcher.js
└── test
└── test.js
/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "root": true,
3 | "parser": "babel-eslint",
4 | "extends": "standard",
5 | "rules": {
6 | "comma-dangle": [
7 | "error",
8 | "only-multiline"
9 | ],
10 | "indent": [
11 | "error",
12 | 2,
13 | {
14 | "SwitchCase": 1
15 | }
16 | ],
17 | "no-multiple-empty-lines": [
18 | "error",
19 | {
20 | "max": 2
21 | }
22 | ],
23 | "operator-linebreak": [
24 | "error",
25 | "before",
26 | {
27 | "overrides": {
28 | "=": "after"
29 | }
30 | }
31 | ]
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 |
3 | node_modules
4 | npm-debug.log
5 |
6 | jsconfig.json
7 | .vscode
8 |
9 | dev
10 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | node_js:
3 | - "4"
4 | - "5"
5 | - "6"
6 | - "7"
7 | - "8"
8 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2016 lon
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.en.md:
--------------------------------------------------------------------------------
1 | [中文](https://github.com/cnlon/smart-observe/blob/master/README.md) | English
2 |
3 | # smart-observe
4 |
5 | [](https://travis-ci.org/cnlon/smart-observe)
6 | [](https://badge.fury.io/js/smart-observe)
7 | [](http://standardjs.com)
8 |
9 |
10 | **smart-observe** comes from [**Vue.js**](https://github.com/vuejs/vue) and is a small, efficient library for observing changes of javascript Object, Array and Class.
11 |
12 | ## Installation
13 |
14 | ``` bash
15 | npm install --save smart-observe
16 | ```
17 |
18 | or
19 |
20 | ``` bash
21 | bower install --save smart-observe
22 | ```
23 |
24 | ## Usage
25 |
26 | #### To watch expression. `observe.watch(target, expression, callback)` or `observe(target, expression, callback)`
27 |
28 | Try it on:
29 | [codepen](http://codepen.io/lon/pen/rrqLLk?editors=0010#0)
30 | [jsfiddle](https://jsfiddle.net/lon/x4n2yjLn/)
31 |
32 | ``` javascript
33 | const target = {a: 1}
34 | observe(target, 'a', function (newValue, oldValue) {
35 | console.log(newValue, oldValue)
36 | })
37 | target.a = 3
38 | // 3 1
39 | ```
40 |
41 | #### To add computed property. `observe.compute(target, name, getter)`
42 |
43 | Try it on:
44 | [codepen](http://codepen.io/lon/pen/dpgXLN?editors=0010#0)
45 | [jsfiddle](https://jsfiddle.net/lon/q402v3jd/)
46 |
47 | ``` javascript
48 | const target = {a: 1}
49 | observe.compute(target, 'b', function () {
50 | return this.a * 2
51 | })
52 | console.log(target.b)
53 | // 2
54 | target.a = 3
55 | console.log(target.b)
56 | // 6
57 | ```
58 |
59 | #### To watch expressions and computed properties. `observe.react(options)`
60 |
61 | Try it on:
62 | [codepen](http://codepen.io/lon/pen/zKmKqA?editors=0010#0)
63 | [jsfiddle](https://jsfiddle.net/lon/ufth8xpe/)
64 |
65 | ``` javascript
66 | const options = {
67 | data: {
68 | PI: Math.PI,
69 | radius: 1,
70 | },
71 | computed: {
72 | 'area': function () {
73 | return this.PI * this.square(this.radius) // πr²
74 | },
75 | },
76 | watchers: {
77 | 'area': function (newValue, oldValue) {
78 | console.log(`area: ${newValue}`)
79 | },
80 | },
81 | methods: {
82 | square (num) {
83 | return num * num
84 | },
85 | },
86 | }
87 | const target = observe.react(options)
88 | target.radius = 3
89 | // area: 28.274333882308138
90 | ```
91 |
92 | ## API
93 |
94 | #### properties
95 |
96 | | name | type | value | detail |
97 | | --- | --- | --- | --- |
98 | | `observe.deep` | `boolean` | The default is `false` | If `true`, `observe.watch(target, expression, callback)` will observe `target` deeply |
99 | | `observe.sync` | `boolean` | The default is `false` | If `true`, `observe.watch(target, expression, callback)` will invoke callback immediately when a property change is detected |
100 | | `observe.default` | `function` | Could only be one of `observe.react`, `observe.watch` and `observe.compute`. The default is `observe.watch` | Set actual method to `observe.default` for `observe(...)` |
101 |
102 | #### methods
103 |
104 | **`observe(...)`**
105 |
106 | - It's syntactic sugar of `observe.default`. See 'properties' for details
107 |
108 | **`observe.watch(target, expression, callback)`**
109 |
110 | - `target`: Any object
111 | - `expression`: `string` or `function`
112 | - `callback`: `function`
113 | - Returns `Watcher`. And calling `watcher.teardown()` could unwatch expression
114 |
115 | **`observe.compute(target, name, accessor, cache)`**
116 |
117 | - `target`: Any object
118 | - `name`: `string`
119 | - `accessor`:
120 | - `function`: It will be the `get` of accessor
121 | - `Object`: Contains: (at least `get` or `set`)
122 | - `get`: `function`
123 | - `set`: `function`
124 | - `cache`: `boolean`. Optional. The default is `true`. If `false`, the `get` will be evaluated whenever reading computed properties
125 | - `cache`: `boolean`. Same as `accessor.cache`
126 |
127 | **`observe.react(options, target)`**
128 |
129 | - `options`: `Object`. Contains:
130 | - `data`: It's the properties to add
131 | - `computed`: It's the computed properties to add
132 | - `watchers`: It's the watchers to watch properties or computed properties
133 | - `methods`: The methods to add. And these will bind to `target`
134 | - `target`: Any object. Optional. The default is empty object. It will be attached with the fields of `options`
135 | - returns `target`
136 |
137 | ## License
138 |
139 | [MIT](https://github.com/cnlon/smart-observe/blob/master/LICENSE)
140 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | 中文 | [English](https://github.com/cnlon/smart-observe/blob/master/README.en.md)
2 |
3 | # smart-observe
4 |
5 | [](https://travis-ci.org/cnlon/smart-observe)
6 | [](https://badge.fury.io/js/smart-observe)
7 | [](http://standardjs.com)
8 |
9 | **smart-observe** 来自 [**Vue.js**](https://github.com/vuejs/vue),是一个小巧、高效,用于监测 javascript 对象、数组、类 变化的库
10 |
11 | ## 安装
12 |
13 | ``` bash
14 | npm install --save smart-observe
15 | ```
16 |
17 | 或
18 |
19 | ```
20 | bower install --save smart-observe
21 | ```
22 |
23 | ## 使用
24 |
25 | #### 监测属性 `observe.watch(target, expression, callback)` 或 `observe(target, expression, callback)`
26 |
27 | 试一试:
28 | [codepen](http://codepen.io/lon/pen/rrqLLk?editors=0010#0)
29 | [jsfiddle](https://jsfiddle.net/lon/x4n2yjLn/)
30 |
31 | ``` javascript
32 | const target = {a: 1}
33 | observe(target, 'a', function (newValue, oldValue) {
34 | console.log(newValue, oldValue)
35 | })
36 | target.a = 3
37 | // 3 1
38 | ```
39 |
40 | #### 添加计算属性 `observe.compute(target, name, getter)`
41 |
42 | 试一试:
43 | [codepen](http://codepen.io/lon/pen/dpgXLN?editors=0010#0)
44 | [jsfiddle](https://jsfiddle.net/lon/q402v3jd/)
45 |
46 | ``` javascript
47 | const target = {a: 1}
48 | observe.compute(target, 'b', function () {
49 | return this.a * 2
50 | })
51 | console.log(target.b)
52 | // 2
53 | target.a = 3
54 | console.log(target.b)
55 | // 6
56 | ```
57 |
58 | #### 监测属性并添加计算属性 `observe.react(options)`
59 |
60 | 试一试:
61 | [codepen](http://codepen.io/lon/pen/zKmKqA?editors=0010#0)
62 | [jsfiddle](https://jsfiddle.net/lon/ufth8xpe/)
63 |
64 | ``` javascript
65 | const options = {
66 | data: {
67 | PI: Math.PI,
68 | radius: 1,
69 | },
70 | computed: {
71 | 'area': function () {
72 | return this.PI * this.square(this.radius) // πr²
73 | },
74 | },
75 | watchers: {
76 | 'area': function (newValue, oldValue) {
77 | console.log(`area: ${newValue}`)
78 | },
79 | },
80 | methods: {
81 | square (num) {
82 | return num * num
83 | },
84 | },
85 | }
86 | const target = observe.react(options)
87 | target.radius = 3
88 | // area: 28.274333882308138
89 | ```
90 |
91 | ## API
92 |
93 | #### 属性
94 |
95 | | 名称 | 类型 | 值 | 说明 |
96 | | --- | --- | --- | --- |
97 | | `observe.deep` | `boolean` | 默认为 `false` | 如果为 `true`,`observe.watch(target, expression, callback)` 将会对 `target` 深度监测 |
98 | | `observe.sync` | `boolean` | 默认为 `false` | 如果为 `true`,`observe.watch(target, expression, callback)` 监测到属性变化时,立即调用回调函数 |
99 | | `observe.default` | `function` | 只能为 `observe.react`,`observe.watch` 或 `observe.compute`, 默认为 `observe.watch` | 设置 `observe(...)` 实际调用的方法,写起来简洁一些 |
100 |
101 | #### 方法
102 |
103 | **`observe(...)`**
104 |
105 | - 为方法 `observe.default` 的语法糖,`observe.default` 参见属性
106 |
107 | **`observe.watch(target, expression, callback)`**
108 |
109 | - `target`: 任意对象
110 | - `expression`: `string` 或 `function`
111 | - `callback`: `function`
112 | - 返回 `Watcher`,调用 `watcher.teardown()` 可以取消监测
113 |
114 | **`observe.compute(target, name, accessor, cache)`**
115 |
116 | - `target`: 任意对象
117 | - `name`: `string`
118 | - `accessor`:
119 | - `function`: 会作为 `getter`,等同传入 {get: accessor}
120 | - `Object`: 可以包含:(其中,至少包含 `get` 或 `set`)
121 | - `get`: `function`
122 | - `set`: `function`
123 | - `cache`: `boolean`,可选,默认为 `true`,如果设为 `false`,每次读取计算属性都要重新计算
124 | - `cache`: `boolean`,可选,默认为 `true`,仅当 `accessor` 为 `function` 时有效。
125 |
126 | **`observe.react(options, target)`**
127 |
128 | - `options`: `Object`,要配置的参数集合,可以包含:
129 | - `data`: 要附加的字段
130 | - `computed`: 要附加的计算属性
131 | - `watchers`: 要监测的属性和计算属性
132 | - `methods`: 要附加的方法,这些方法将会自动绑定 `target`
133 | - `target`: 任意对象,可选,默认为空对象,`options` 的参数将附加到此对象上
134 | - 返回 `target`
135 |
136 | ## License
137 |
138 | [MIT](https://github.com/cnlon/smart-observe/blob/master/LICENSE)
139 |
--------------------------------------------------------------------------------
/bower.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "smart-observe",
3 | "description": "smart-observe comes from Vue.js and is a small, efficient library for observing changes of javascript Object, Array and Class.",
4 | "main": "dist/smart-observe.js",
5 | "keywords": [
6 | "observe",
7 | "observer",
8 | "watch",
9 | "watcher",
10 | "computed",
11 | "vue",
12 | "vue.js",
13 | "ob.js",
14 | "ob"
15 | ],
16 | "authors": [
17 | "lon (http://lon.im)"
18 | ],
19 | "license": "MIT",
20 | "homepage": "https://github.com/cnlon/smart-observe",
21 | "ignore": [
22 | "**/.*",
23 | "node_modules",
24 | "bower_components",
25 | "test",
26 | "dev"
27 | ]
28 | }
29 |
--------------------------------------------------------------------------------
/dev/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/dev/index.js:
--------------------------------------------------------------------------------
1 | import observe from 'smart-observe'
2 |
3 | window.onload = function () {
4 | const target = window.d = observe.react({
5 | data: {
6 | PI: Math.PI,
7 | radius: 2,
8 | },
9 | computed: {
10 | 'area': function () {
11 | return this.PI * this.square(this.radius)
12 | },
13 | },
14 | watchers: {
15 | 'area': function (newValue, oldValue) {
16 | console.log(newValue)
17 | },
18 | },
19 | methods: {
20 | square (num) {
21 | return num * num
22 | },
23 | },
24 | })
25 | target.radius = 3
26 | console.dir(target)
27 | }
28 |
--------------------------------------------------------------------------------
/dev/webpack.config.js:
--------------------------------------------------------------------------------
1 | const path = require('path')
2 |
3 | const config = {
4 | entry: {
5 | app: './dev/index.js',
6 | },
7 | output: {
8 | path: path.resolve(__dirname, './build'),
9 | filename: 'dev.js',
10 | },
11 | module: {
12 | loaders: [
13 | {
14 | test: /\.js$/,
15 | exclude: /node_modules/,
16 | loader: 'babel',
17 | },
18 | ],
19 | },
20 | babel: {
21 | presets: ['es2015'],
22 | plugins: ['transform-class-properties'],
23 | },
24 | devtool: 'eval',
25 | resolve: {
26 | alias: {
27 | 'smart-observe': path.resolve(__dirname, '../src/index.js'),
28 | },
29 | },
30 | }
31 |
32 | module.exports = config
33 |
--------------------------------------------------------------------------------
/dist/smart-observe.js:
--------------------------------------------------------------------------------
1 | /**
2 | * smart-observe --- By lon
3 | * https://github.com/cnlon/smart-observe
4 | */
5 | (function (global, factory) {
6 | typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
7 | typeof define === 'function' && define.amd ? define('observe', factory) :
8 | (global.observe = factory());
9 | }(this, (function () { 'use strict';
10 |
11 | var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) {
12 | return typeof obj;
13 | } : function (obj) {
14 | return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
15 | };
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 | var classCallCheck = function (instance, Constructor) {
28 | if (!(instance instanceof Constructor)) {
29 | throw new TypeError("Cannot call a class as a function");
30 | }
31 | };
32 |
33 | var createClass = function () {
34 | function defineProperties(target, props) {
35 | for (var i = 0; i < props.length; i++) {
36 | var descriptor = props[i];
37 | descriptor.enumerable = descriptor.enumerable || false;
38 | descriptor.configurable = true;
39 | if ("value" in descriptor) descriptor.writable = true;
40 | Object.defineProperty(target, descriptor.key, descriptor);
41 | }
42 | }
43 |
44 | return function (Constructor, protoProps, staticProps) {
45 | if (protoProps) defineProperties(Constructor.prototype, protoProps);
46 | if (staticProps) defineProperties(Constructor, staticProps);
47 | return Constructor;
48 | };
49 | }();
50 |
51 | var uid = 0;
52 |
53 | /**
54 | * A dep is an observable that can have multiple
55 | * watcher subscribing to it.
56 | */
57 |
58 | var Dep = function () {
59 | function Dep() {
60 | classCallCheck(this, Dep);
61 |
62 | this.id = uid++;
63 | this.subs = [];
64 | }
65 |
66 | /**
67 | * Add a subscriber.
68 | *
69 | * @param {Watcher} sub
70 | */
71 |
72 | // the current target watcher being evaluated.
73 | // this is globally unique because there could be only one
74 | // watcher being evaluated at any time.
75 |
76 |
77 | createClass(Dep, [{
78 | key: "addSub",
79 | value: function addSub(sub) {
80 | this.subs.push(sub);
81 | }
82 |
83 | /**
84 | * Remove a subscriber.
85 | *
86 | * @param {Watcher} sub
87 | */
88 |
89 | }, {
90 | key: "removeSub",
91 | value: function removeSub(sub) {
92 | this.subs.$remove(sub);
93 | }
94 |
95 | /**
96 | * Add self as a dependency to the target watcher.
97 | */
98 |
99 | }, {
100 | key: "depend",
101 | value: function depend() {
102 | Dep.target.addDep(this);
103 | }
104 |
105 | /**
106 | * Notify all subscribers of a new value.
107 | */
108 |
109 | }, {
110 | key: "notify",
111 | value: function notify() {
112 | var subs = this.subs;
113 | for (var i = 0, l = subs.length; i < l; i++) {
114 | subs[i].update();
115 | }
116 | }
117 | }]);
118 | return Dep;
119 | }();
120 |
121 | Dep.target = null;
122 |
123 | var OBSERVE_NAME = '__s_o__';
124 | var WATCHERS_PROPERTY_NAME = '__watchers__';
125 | var DATA_PROPTERTY_NAME = '__data__';
126 |
127 | var DEBUGGING = typeof process !== 'undefined' && process.env.NODE_ENV !== 'production';
128 |
129 | /**
130 | * Define property with value.
131 | *
132 | * @param {Object} object
133 | * @param {String} property
134 | * @param {*} value
135 | * @param {Boolean} [enumerable]
136 | */
137 |
138 | function defineValue(object, property, value, enumerable) {
139 | Object.defineProperty(object, property, {
140 | value: value,
141 | enumerable: !!enumerable,
142 | writable: true,
143 | configurable: true
144 | });
145 | }
146 |
147 | /**
148 | * Define property with getter and setter.
149 | *
150 | * @param {Object} object
151 | * @param {String} property
152 | * @param {Function} getter
153 | * @param {Function} setter
154 | */
155 |
156 | function defineAccessor(object, property, getter, setter) {
157 | Object.defineProperty(object, property, {
158 | get: getter,
159 | set: setter,
160 | enumerable: true,
161 | configurable: true
162 | });
163 | }
164 |
165 | /**
166 | * Array type check.
167 | *
168 | * @return {Boolean}
169 | */
170 |
171 | var isArray = Array.isArray;
172 |
173 | /**
174 | * Strict object type check. Only returns true
175 | * for plain JavaScript objects.
176 | *
177 | * @param {*} object
178 | * @return {Boolean}
179 | */
180 |
181 | var toString = Object.prototype.toString;
182 | var OBJECT_STRING = '[object Object]';
183 | function isPlainObject(object) {
184 | return toString.call(object) === OBJECT_STRING;
185 | }
186 |
187 | /**
188 | * Quick object check - this is primarily used to tell
189 | * Objects from primitive values when we know the value
190 | * is a JSON-compliant type.
191 | *
192 | * @param {*} object
193 | * @return {Boolean}
194 | */
195 |
196 | function isObject(object) {
197 | return object !== null && (typeof object === 'undefined' ? 'undefined' : _typeof(object)) === 'object';
198 | }
199 |
200 | /**
201 | * Function type check
202 | *
203 | * @param {*} func
204 | * @param {Boolean}
205 | */
206 |
207 | function isFunction(func) {
208 | return typeof func === 'function';
209 | }
210 |
211 | /**
212 | * Iterate object
213 | *
214 | * @param {Object} object
215 | * @param {Function} callback
216 | */
217 |
218 | function everyEntries(object, callback) {
219 | var keys = Object.keys(object);
220 | for (var i = 0, l = keys.length; i < l; i++) {
221 | callback(keys[i], object[keys[i]]);
222 | }
223 | }
224 |
225 | /**
226 | * noop is function which is nothing to do.
227 | */
228 |
229 | function noop() {}
230 |
231 | /**
232 | * @param {String} string
233 | */
234 |
235 | var warn = typeof DEBUGGING !== 'undefined' && DEBUGGING && typeof console !== 'undefined' && console && isFunction(console.warn) ? console.warn : noop;
236 |
237 | var _Set = void 0;
238 | if (typeof Set !== 'undefined' && Set.toString().match(/native code/)) {
239 | // use native Set when available.
240 | _Set = Set;
241 | } else {
242 | // a non-standard Set polyfill that only works with primitive keys.
243 | _Set = function _Set() {
244 | this.set = Object.create(null);
245 | };
246 | _Set.prototype.has = function (key) {
247 | return this.set[key] !== undefined;
248 | };
249 | _Set.prototype.add = function (key) {
250 | this.set[key] = 1;
251 | };
252 | _Set.prototype.clear = function () {
253 | this.set = Object.create(null);
254 | };
255 | }
256 |
257 | var arrayPrototype = Array.prototype;
258 | var arrayMethods = Object.create(arrayPrototype);
259 | var arrayMutativeMethods = ['push', 'pop', 'shift', 'unshift', 'splice', 'sort', 'reverse'];
260 |
261 | /**
262 | * Augment an target Array with arrayMethods
263 | *
264 | * @param {Array} array
265 | */
266 |
267 | function amend(array) {
268 | Object.setPrototypeOf(array, arrayMethods);
269 | }
270 |
271 | /**
272 | * Intercept mutating methods and emit events
273 | */
274 |
275 | var _loop = function _loop(i, l) {
276 | var method = arrayMutativeMethods[i];
277 | // cache original method
278 | var original = arrayPrototype[method];
279 | defineValue(arrayMethods, method, function mutator() {
280 | for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
281 | args[_key] = arguments[_key];
282 | }
283 |
284 | var result = original.apply(this, args);
285 | var observer = this[OBSERVE_NAME];
286 | var inserted = void 0;
287 | switch (method) {
288 | case 'push':
289 | inserted = args;
290 | break;
291 | case 'unshift':
292 | inserted = args;
293 | break;
294 | case 'splice':
295 | inserted = args.slice(2);
296 | break;
297 | }
298 | if (inserted) observer.observeArray(inserted);
299 | observer.dep.notify(); // notify change
300 | return result;
301 | });
302 | };
303 |
304 | for (var i = 0, l = arrayMutativeMethods.length; i < l; i++) {
305 | _loop(i, l);
306 | }
307 |
308 | /**
309 | * Swap the element at the given index with a new value
310 | * and emits corresponding event.
311 | *
312 | * @param {Number} index
313 | * @param {*} value
314 | * @return {*} - replaced element
315 | */
316 |
317 | function $set(index, value) {
318 | if (index >= this.length) {
319 | this.length = Number(index) + 1;
320 | }
321 | return this.splice(index, 1, value)[0];
322 | }
323 | defineValue(arrayPrototype, '$set', $set);
324 |
325 | /**
326 | * Convenience method to remove the element at given index
327 | * or target element reference.
328 | *
329 | * @param {*} item
330 | * @return {*} - removed element
331 | */
332 |
333 | function $remove(item) {
334 | if (!this.length) return;
335 | var index = this.indexOf(item);
336 | if (index > -1) {
337 | return this.splice(index, 1);
338 | }
339 | }
340 | defineValue(arrayPrototype, '$remove', $remove);
341 |
342 | /**
343 | * Observer class that are attached to each observed
344 | * object. Once attached, the observer converts target
345 | * object's property keys into getter/setters that
346 | * collect dependencies and dispatches updates.
347 | *
348 | * @class
349 | * @param {Array|Object} value
350 | */
351 |
352 | var Observer = function () {
353 | function Observer(value) {
354 | classCallCheck(this, Observer);
355 |
356 | this.value = value;
357 | this.dep = new Dep();
358 | defineValue(value, OBSERVE_NAME, this);
359 | if (isArray(value)) {
360 | amend(value);
361 | this.observeArray(value);
362 | } else {
363 | this.walk(value);
364 | }
365 | }
366 |
367 | /**
368 | * Walk through each property and convert them into
369 | * getter/setters. This method should only be called when
370 | * value type is Object.
371 | *
372 | * @param {Object} object
373 | */
374 |
375 | createClass(Observer, [{
376 | key: 'walk',
377 | value: function walk(object) {
378 | var _this = this;
379 |
380 | everyEntries(object, function (key, value) {
381 | return _this.convert(key, value);
382 | });
383 | }
384 |
385 | /**
386 | * Observe a list of Array items.
387 | *
388 | * @param {Array} items
389 | */
390 |
391 | }, {
392 | key: 'observeArray',
393 | value: function observeArray(items) {
394 | for (var i = 0, l = items.length; i < l; i++) {
395 | observe$1(items[i]);
396 | }
397 | }
398 |
399 | /**
400 | * Convert a property into getter/setter so we can emit
401 | * the events when the property is accessed/changed.
402 | *
403 | * @param {String} key
404 | * @param {*} value
405 | */
406 |
407 | }, {
408 | key: 'convert',
409 | value: function convert(key, value) {
410 | defineReactive(this.value, key, value);
411 | }
412 | }]);
413 | return Observer;
414 | }();
415 |
416 | /**
417 | * Attempt to create an observer instance for a value,
418 | * returns the new observer if successfully observed,
419 | * or the existing observer if the value already has one.
420 | *
421 | * @param {*} value
422 | * @return {Observer|undefined}
423 | */
424 |
425 | function observe$1(value) {
426 | if (!value || (typeof value === 'undefined' ? 'undefined' : _typeof(value)) !== 'object') return;
427 | var observer = void 0;
428 | if (Object.prototype.hasOwnProperty.call(value, OBSERVE_NAME) && value[OBSERVE_NAME] instanceof Observer) {
429 | observer = value[OBSERVE_NAME];
430 | } else if ((isArray(value) || isPlainObject(value)) && Object.isExtensible(value)) {
431 | observer = new Observer(value);
432 | }
433 | return observer;
434 | }
435 |
436 | /**
437 | * Define a reactive property on an Object.
438 | *
439 | * @param {Object} object
440 | * @param {String} key
441 | * @param {*} value
442 | */
443 |
444 | function defineReactive(object, key, value) {
445 | var dep = new Dep();
446 |
447 | var desc = Object.getOwnPropertyDescriptor(object, key);
448 | if (desc && desc.configurable === false) return;
449 |
450 | // cater for pre-defined getter/setters
451 | var getter = desc && desc.get;
452 | var setter = desc && desc.set;
453 |
454 | var childOb = observe$1(value);
455 |
456 | function reactiveGetter() {
457 | var currentValue = getter ? getter.call(object) : value;
458 | if (Dep.target) {
459 | dep.depend();
460 | if (childOb) {
461 | childOb.dep.depend();
462 | }
463 | if (isArray(currentValue)) {
464 | for (var i = 0, l = currentValue.length, e; i < l; i++) {
465 | e = currentValue[i];
466 | e && e[OBSERVE_NAME] && e[OBSERVE_NAME].dep.depend();
467 | }
468 | }
469 | }
470 | return currentValue;
471 | }
472 | function reactiveSetter(newValue) {
473 | var oldValue = getter ? getter.call(object) : value;
474 | if (newValue === oldValue) return;
475 | if (setter) {
476 | setter.call(object, newValue);
477 | } else {
478 | value = newValue;
479 | }
480 | childOb = observe$1(newValue);
481 | dep.notify();
482 | }
483 | defineAccessor(object, key, reactiveGetter, reactiveSetter);
484 | }
485 |
486 | /**
487 | * Build a getter function. Requires eval.
488 | *
489 | * We isolate the try/catch so it doesn't affect the
490 | * optimization of the parse function when it is not called.
491 | *
492 | * @param {String} body
493 | * @return {Function|undefined}
494 | */
495 |
496 | function makeGetterFunction(body) {
497 | try {
498 | /* eslint-disable no-new-func */
499 | return new Function('scope', 'return ' + body + ';');
500 | /* eslint-enable no-new-func */
501 | } catch (e) {
502 | warn('Invalid expression. Generated function body: ' + body);
503 | }
504 | }
505 |
506 | /**
507 | * Parse an expression to getter.
508 | *
509 | * @param {String} expression
510 | * @return {Function|undefined}
511 | */
512 |
513 | function parse(expression) {
514 | expression = String.prototype.trim.call(expression);
515 | return makeGetterFunction('scope.' + expression);
516 | }
517 |
518 | var callbacks = [];
519 | var pending = false;
520 | function nextTickHandler() {
521 | pending = false;
522 | var callbackCopies = callbacks.slice(0);
523 | callbacks.length = 0;
524 | for (var i = 0; i < callbackCopies.length; i++) {
525 | callbackCopies[i]();
526 | }
527 | }
528 |
529 | var callNextTick;
530 | if ((typeof process === 'undefined' ? 'undefined' : _typeof(process)) === 'object' && process && typeof process.nextTick === 'function') {
531 | callNextTick = process.nextTick;
532 | } else if (typeof MutationObserver !== 'undefined') {
533 | var counter = 0;
534 | var textNode = document.createTextNode(counter);
535 | var observer = new MutationObserver(nextTickHandler);
536 | observer.observe(textNode, {
537 | characterData: true
538 | });
539 | callNextTick = function callNextTick() {
540 | counter = counter === 0 ? 1 : 0;
541 | textNode.data = String(counter);
542 | };
543 | } else {
544 | callNextTick = setTimeout;
545 | }
546 |
547 | var nextTick = function nextTick(callback, context) {
548 | var func = callback;
549 | if (context) {
550 | var args = [];
551 | var l = arguments.length;
552 | while (--l > 1) {
553 | args.unshift(arguments[l]);
554 | }
555 | func = function func() {
556 | callback.apply(context, args);
557 | };
558 | }
559 | callbacks.push(func);
560 | if (pending) {
561 | return;
562 | }
563 | pending = true;
564 | callNextTick(nextTickHandler);
565 | };
566 |
567 | var queue = [];
568 | var has = {};
569 | var waiting = false;
570 | var queueIndex = void 0;
571 |
572 | /**
573 | * Reset the batcher's state.
574 | */
575 |
576 | function resetBatcherState() {
577 | queue = [];
578 | has = {};
579 | waiting = false;
580 | }
581 |
582 | /**
583 | * Flush queue and run the watchers.
584 | */
585 |
586 | function flushBatcherQueue() {
587 | runBatcherQueue(queue);
588 | resetBatcherState();
589 | }
590 |
591 | /**
592 | * Run the watchers in a single queue.
593 | *
594 | * @param {Array} queue
595 | */
596 |
597 | function runBatcherQueue(queue) {
598 | // do not cache length because more watchers might be pushed
599 | // as we run existing watchers
600 | for (queueIndex = 0; queueIndex < queue.length; queueIndex++) {
601 | var watcher = queue[queueIndex];
602 | var id = watcher.id;
603 | has[id] = null;
604 | watcher.run();
605 | }
606 | }
607 |
608 | /**
609 | * Push a watcher into the watcher queue.
610 | * Jobs with duplicate IDs will be skipped unless it's
611 | * pushed when the queue is being flushed.
612 | *
613 | * @param {Watcher} watcher
614 | * properties:
615 | * - {Number} id
616 | * - {Function} run
617 | */
618 |
619 | function batch(watcher) {
620 | var id = watcher.id;
621 | if (has[id] == null) {
622 | has[id] = queue.length;
623 | queue.push(watcher);
624 | // queue the flush
625 | if (!waiting) {
626 | waiting = true;
627 | nextTick(flushBatcherQueue);
628 | }
629 | }
630 | }
631 |
632 | var uid$1 = 0;
633 |
634 | var Watcher = function () {
635 |
636 | /**
637 | * A watcher parses an expression, collects dependencies,
638 | * and fires callback when the expression value changes.
639 | *
640 | * @param {Object} owner
641 | * @param {String|Function} getter
642 | * @param {Function} callback
643 | * @param {Object} options
644 | * - {Boolean} deep
645 | * - {Boolean} sync
646 | * - {Boolean} lazy
647 | * @constructor
648 | */
649 |
650 | function Watcher(owner, getter, callback, options) {
651 | classCallCheck(this, Watcher);
652 |
653 | owner[WATCHERS_PROPERTY_NAME].push(this);
654 | this.owner = owner;
655 | this.getter = getter;
656 | this.callback = callback;
657 | this.options = options;
658 | // uid for batching
659 | this.id = ++uid$1;
660 | this.active = true;
661 | // for lazy watchers
662 | this.dirty = options.lazy;
663 | this.deps = [];
664 | this.newDeps = [];
665 | this.depIds = new _Set();
666 | this.newDepIds = new _Set();
667 | this.value = options.lazy ? undefined : this.get();
668 | }
669 |
670 | /**
671 | * Evaluate the getter, and re-collect dependencies.
672 | */
673 |
674 | createClass(Watcher, [{
675 | key: 'get',
676 | value: function get$$1() {
677 | this.beforeGet();
678 | var scope = this.owner;
679 | var value = this.getter.call(scope, scope);
680 | if (this.options.deep) {
681 | traverse(value);
682 | }
683 | this.afterGet();
684 | return value;
685 | }
686 |
687 | /**
688 | * Prepare for dependency collection.
689 | */
690 |
691 | }, {
692 | key: 'beforeGet',
693 | value: function beforeGet() {
694 | Dep.target = this;
695 | }
696 |
697 | /**
698 | * Add a dependency to this directive.
699 | *
700 | * @param {Dep} dep
701 | */
702 |
703 | }, {
704 | key: 'addDep',
705 | value: function addDep(dep) {
706 | var id = dep.id;
707 | if (!this.newDepIds.has(id)) {
708 | this.newDepIds.add(id);
709 | this.newDeps.push(dep);
710 | if (!this.depIds.has(id)) {
711 | dep.addSub(this);
712 | }
713 | }
714 | }
715 |
716 | /**
717 | * Clean up for dependency collection.
718 | */
719 |
720 | }, {
721 | key: 'afterGet',
722 | value: function afterGet() {
723 | Dep.target = null;
724 | var i = this.deps.length;
725 | while (i--) {
726 | var dep = this.deps[i];
727 | if (!this.newDepIds.has(dep.id)) {
728 | dep.removeSub(this);
729 | }
730 | }
731 | var tmp = this.depIds;
732 | this.depIds = this.newDepIds;
733 | this.newDepIds = tmp;
734 | this.newDepIds.clear();
735 | tmp = this.deps;
736 | this.deps = this.newDeps;
737 | this.newDeps = tmp;
738 | this.newDeps.length = 0;
739 | }
740 |
741 | /**
742 | * Will be called when a dependency changes.
743 | */
744 |
745 | }, {
746 | key: 'update',
747 | value: function update() {
748 | if (this.options.lazy) {
749 | this.dirty = true;
750 | } else if (this.options.sync) {
751 | this.run();
752 | } else {
753 | batch(this);
754 | }
755 | }
756 |
757 | /**
758 | * Will be called by the batcher.
759 | */
760 |
761 | }, {
762 | key: 'run',
763 | value: function run() {
764 | if (this.active) {
765 | var value = this.get();
766 | if (value !== this.value
767 | // Deep watchers and watchers on Object/Arrays should fire even when
768 | // the value is the same, because the value may have mutated;
769 | || isObject(value) || this.options.deep) {
770 | var oldValue = this.value;
771 | this.value = value;
772 | this.callback.call(this.owner, value, oldValue);
773 | }
774 | }
775 | }
776 |
777 | /**
778 | * Evaluate the value of the watcher.
779 | * This only gets called for lazy watchers.
780 | */
781 |
782 | }, {
783 | key: 'evaluate',
784 | value: function evaluate() {
785 | // avoid overwriting another watcher that is being collected.
786 | var current = Dep.target;
787 | this.value = this.get();
788 | this.dirty = false;
789 | Dep.target = current;
790 | }
791 |
792 | /**
793 | * Depend on all deps collected by this watcher.
794 | */
795 |
796 | }, {
797 | key: 'depend',
798 | value: function depend() {
799 | var i = this.deps.length;
800 | while (i--) {
801 | this.deps[i].depend();
802 | }
803 | }
804 |
805 | /**
806 | * Remove self from all dependencies' subcriber list.
807 | */
808 |
809 | }, {
810 | key: 'teardown',
811 | value: function teardown() {
812 | if (this.active) {
813 | var i = this.deps.length;
814 | while (i--) {
815 | this.deps[i].removeSub(this);
816 | }
817 | this.active = false;
818 | this.owner = this.callback = this.value = null;
819 | }
820 | }
821 | }]);
822 | return Watcher;
823 | }();
824 |
825 | /**
826 | * Recrusively traverse an object to evoke all converted
827 | * getters, so that every nested property inside the object
828 | * is collected as a "deep" dependency.
829 | *
830 | * @param {*} value
831 | */
832 |
833 | function traverse(value) {
834 | var i = void 0,
835 | keys = void 0;
836 | if (isArray(value)) {
837 | i = value.length;
838 | while (i--) {
839 | traverse(value[i]);
840 | }
841 | } else if (isObject(value)) {
842 | keys = Object.keys(value);
843 | i = keys.length;
844 | while (i--) {
845 | traverse(value[keys[i]]);
846 | }
847 | }
848 | }
849 |
850 | /**
851 | * Create an watcher instance, returns the new watcher.
852 | *
853 | * @param {Object} owner
854 | * @param {String|Function} expressionOrFunction
855 | * @param {Function} callback
856 | * @param {Object} options
857 | * - {Boolean} deep
858 | * - {Boolean} sync
859 | * - {Boolean} lazy
860 | * @return {Watcher}
861 | */
862 |
863 | function watch$1(owner, expressionOrFunction, callback, options) {
864 | // parse expression for getter
865 | var getter = isFunction(expressionOrFunction) ? expressionOrFunction : parse(expressionOrFunction);
866 | return new Watcher(owner, getter, callback, options);
867 | }
868 |
869 | /**
870 | * Make a computed getter, which can collect dependencies.
871 | *
872 | * @param {Object} owner
873 | * @param {Function} getter
874 | */
875 |
876 | function makeComputed(owner, getter) {
877 | var watcher = new Watcher(owner, getter, null, {
878 | deep: observe$$1.deep,
879 | lazy: true,
880 | sync: observe$$1.sync
881 | });
882 | return function computedGetter() {
883 | if (watcher.options.lazy && Dep.target && !Dep.target.options.lazy) {
884 | watcher.options.lazy = false;
885 | watcher.callback = function () {
886 | var deps = watcher.deps;
887 | for (var i = 0, l = deps.length; i < l; i++) {
888 | deps[i].notify();
889 | }
890 | };
891 | }
892 | if (watcher.dirty) {
893 | watcher.evaluate();
894 | }
895 | if (Dep.target) {
896 | watcher.depend();
897 | }
898 | return watcher.value;
899 | };
900 | }
901 |
902 | Object.defineProperties(observe$$1, {
903 | 'react': { value: react },
904 | 'compute': { value: compute },
905 | 'watch': { value: watch$$1 },
906 | 'default': { value: watch$$1, writable: true }, // Only could be react, compute or watch
907 | 'deep': { value: false, writable: true },
908 | 'lazy': { value: false, writable: true },
909 | 'sync': { value: false, writable: true }
910 | });
911 |
912 | /**
913 | * observe
914 | *
915 | * @public
916 | * @param {Object} target
917 | * @param {*} [expression]
918 | * @param {*} [func]
919 | * @param {*} [options]
920 | * @return {Function} observe
921 | */
922 |
923 | function observe$$1(target, expression, func, options) {
924 | ensure(target);
925 | return observe$$1.default(target, expression, func, options);
926 | }
927 |
928 | /**
929 | * React options
930 | *
931 | * @param {Object} options
932 | * @param {Object} [target]
933 | * @return {Function} observe
934 | */
935 |
936 | function react(options, target) {
937 | if (target) {
938 | ensure(target);
939 | } else {
940 | target = {};
941 | init(target);
942 | }
943 | options.methods && carryMethods(target, options.methods);
944 | options.data && reactProperties(target, options.data);
945 | options.computed && computeProperties(target, options.computed);
946 | options.watchers && watchProperties(target, options.watchers);
947 | return target;
948 | }
949 |
950 | /**
951 | * Compute property
952 | *
953 | * @param {Object} target
954 | * @param {String} name
955 | * @param {Function|Object} getterOrAccessor
956 | * - Function getter
957 | * - Object accessor
958 | * - Function [get] - getter
959 | * - Function [set] - setter
960 | * - Boolean [cache]
961 | * @param {Boolean} [cache]
962 | */
963 |
964 | function compute(target, name, getterOrAccessor, cache) {
965 | ensure(target);
966 | var getter = void 0,
967 | setter = void 0;
968 | if (isFunction(getterOrAccessor)) {
969 | getter = cache !== false ? makeComputed(target, getterOrAccessor) : getterOrAccessor.bind(this);
970 | setter = noop;
971 | } else {
972 | getter = getterOrAccessor.get ? getterOrAccessor.cache !== false || cache !== false ? makeComputed(target, getterOrAccessor.get) : getterOrAccessor.get.bind(this) : noop;
973 | setter = getterOrAccessor.set ? getterOrAccessor.set.bind(this) : noop;
974 | }
975 | defineAccessor(target, name, getter, setter);
976 | }
977 |
978 | /**
979 | * Watch property
980 | *
981 | * @param {Object} target
982 | * @param {String|Function} expressionOrFunction
983 | * @param {Function} callback
984 | * @param {Object} [options]
985 | * - {Boolean} deep
986 | * - {Boolean} sync
987 | * - {Boolean} lazy
988 | * @return {Watcher}
989 | */
990 |
991 | function watch$$1(target, expressionOrFunction, callback) {
992 | var options = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : observe$$1;
993 |
994 | ensure(target);
995 | return watch$1(target, expressionOrFunction, callback, options);
996 | }
997 |
998 | /**
999 | * @param {Object} target
1000 | */
1001 |
1002 | function init(target) {
1003 | defineValue(target, WATCHERS_PROPERTY_NAME, [], false);
1004 | defineValue(target, DATA_PROPTERTY_NAME, Object.create(null), false);
1005 | observe$1(target[DATA_PROPTERTY_NAME]);
1006 | reactSelfProperties(target);
1007 | }
1008 |
1009 | function ensure(target) {
1010 | if (!Object.prototype.hasOwnProperty.call(target, WATCHERS_PROPERTY_NAME)) {
1011 | init(target);
1012 | }
1013 | }
1014 |
1015 | /**
1016 | * @param {Object} target
1017 | * @param {Object} methods
1018 | */
1019 |
1020 | function carryMethods(target, methods) {
1021 | everyEntries(methods, function (name, method) {
1022 | target[name] = method.bind(target);
1023 | });
1024 | }
1025 |
1026 | /**
1027 | * @param {Object} target
1028 | * @param {String} key
1029 | * @param {*} value
1030 | */
1031 |
1032 | function reactProperty(target, key, value) {
1033 | target[DATA_PROPTERTY_NAME][key] = value;
1034 | defineReactive(target[DATA_PROPTERTY_NAME], key, value);
1035 | proxy(target, key);
1036 | }
1037 |
1038 | /**
1039 | * @param {Object} target
1040 | * @param {Object} properties
1041 | */
1042 |
1043 | function reactProperties(target, properties) {
1044 | everyEntries(properties, function (key, value) {
1045 | return reactProperty(target, key, value);
1046 | });
1047 | }
1048 |
1049 | /**
1050 | * @param {Object} target
1051 | */
1052 |
1053 | function reactSelfProperties(target) {
1054 | everyEntries(target, function (key, value) {
1055 | !isFunction(value) && reactProperty(target, key, value);
1056 | });
1057 | }
1058 |
1059 | /**
1060 | * @param {Object} target
1061 | * @param {Object} properties
1062 | */
1063 |
1064 | function computeProperties(target, properties) {
1065 | everyEntries(properties, function (key, value) {
1066 | return compute(target, key, value);
1067 | });
1068 | }
1069 |
1070 | /**
1071 | * @param {Object} target
1072 | * @param {Object} properties
1073 | */
1074 |
1075 | function watchProperties(target, properties) {
1076 | everyEntries(properties, function (expression, functionOrOption) {
1077 | if (isFunction(functionOrOption)) {
1078 | watch$$1(target, expression, functionOrOption);
1079 | } else {
1080 | watch$$1(target, expression, functionOrOption.watcher, functionOrOption);
1081 | }
1082 | });
1083 | }
1084 |
1085 | /**
1086 | * @param {Object} target
1087 | * @param {String} key
1088 | */
1089 |
1090 | function proxy(target, key) {
1091 | function getter() {
1092 | return target[DATA_PROPTERTY_NAME][key];
1093 | }
1094 | function setter(value) {
1095 | target[DATA_PROPTERTY_NAME][key] = value;
1096 | }
1097 | defineAccessor(target, key, getter, setter);
1098 | }
1099 |
1100 | return observe$$1;
1101 |
1102 | })));
1103 | //# sourceMappingURL=smart-observe.js.map
1104 |
--------------------------------------------------------------------------------
/dist/smart-observe.js.map:
--------------------------------------------------------------------------------
1 | {"version":3,"file":"smart-observe.js","sources":["../src/dep.js","../src/constants.js","../src/util.js","../src/array.js","../src/observe.js","../src/expression.js","../node_modules/smart-next-tick/nextTick.js","../src/batcher.js","../src/watcher.js","../src/index.js"],"sourcesContent":["let uid = 0\n\n/**\n * A dep is an observable that can have multiple\n * watcher subscribing to it.\n */\n\nexport default class Dep {\n // the current target watcher being evaluated.\n // this is globally unique because there could be only one\n // watcher being evaluated at any time.\n static target = null\n\n constructor () {\n this.id = uid++\n this.subs = []\n }\n\n /**\n * Add a subscriber.\n *\n * @param {Watcher} sub\n */\n\n addSub (sub) {\n this.subs.push(sub)\n }\n\n /**\n * Remove a subscriber.\n *\n * @param {Watcher} sub\n */\n\n removeSub (sub) {\n this.subs.$remove(sub)\n }\n\n /**\n * Add self as a dependency to the target watcher.\n */\n\n depend () {\n Dep.target.addDep(this)\n }\n\n /**\n * Notify all subscribers of a new value.\n */\n\n notify () {\n const subs = this.subs\n for (let i = 0, l = subs.length; i < l; i++) {\n subs[i].update()\n }\n }\n}\n","export const OBSERVE_NAME = '__s_o__'\nexport const WATCHERS_PROPERTY_NAME = '__watchers__'\nexport const DATA_PROPTERTY_NAME = '__data__'\n\nexport const DEBUGGING = typeof process !== 'undefined'\n && process.env.NODE_ENV !== 'production'\n","import {DEBUGGING} from './constants'\n\n/**\n * Define property with value.\n *\n * @param {Object} object\n * @param {String} property\n * @param {*} value\n * @param {Boolean} [enumerable]\n */\n\nexport function defineValue (object, property, value, enumerable) {\n Object.defineProperty(object, property, {\n value,\n enumerable: !!enumerable,\n writable: true,\n configurable: true,\n })\n}\n\n/**\n * Define property with getter and setter.\n *\n * @param {Object} object\n * @param {String} property\n * @param {Function} getter\n * @param {Function} setter\n */\n\nexport function defineAccessor (object, property, getter, setter) {\n Object.defineProperty(object, property, {\n get: getter,\n set: setter,\n enumerable: true,\n configurable: true,\n })\n}\n\n/**\n * Array type check.\n *\n * @return {Boolean}\n */\n\nexport const isArray = Array.isArray\n\n/**\n * Strict object type check. Only returns true\n * for plain JavaScript objects.\n *\n * @param {*} object\n * @return {Boolean}\n */\n\nconst toString = Object.prototype.toString\nconst OBJECT_STRING = '[object Object]'\nexport function isPlainObject (object) {\n return toString.call(object) === OBJECT_STRING\n}\n\n/**\n * Quick object check - this is primarily used to tell\n * Objects from primitive values when we know the value\n * is a JSON-compliant type.\n *\n * @param {*} object\n * @return {Boolean}\n */\n\nexport function isObject (object) {\n return object !== null && typeof object === 'object'\n}\n\n/**\n * Function type check\n *\n * @param {*} func\n * @param {Boolean}\n */\n\nexport function isFunction (func) {\n return typeof func === 'function'\n}\n\n/**\n * Iterate object\n *\n * @param {Object} object\n * @param {Function} callback\n */\n\nexport function everyEntries (object, callback) {\n const keys = Object.keys(object)\n for (let i = 0, l = keys.length; i < l; i++) {\n callback(keys[i], object[keys[i]])\n }\n}\n\n/**\n * noop is function which is nothing to do.\n */\n\nexport function noop () {}\n\n/**\n * @param {String} string\n */\n\nexport const warn = typeof DEBUGGING !== 'undefined' && DEBUGGING\n && typeof console !== 'undefined' && console\n && isFunction(console.warn)\n ? console.warn\n : noop\n\nexport let _Set\nif (typeof Set !== 'undefined' && Set.toString().match(/native code/)) {\n // use native Set when available.\n _Set = Set\n} else {\n // a non-standard Set polyfill that only works with primitive keys.\n _Set = function () {\n this.set = Object.create(null)\n }\n _Set.prototype.has = function (key) {\n return this.set[key] !== undefined\n }\n _Set.prototype.add = function (key) {\n this.set[key] = 1\n }\n _Set.prototype.clear = function () {\n this.set = Object.create(null)\n }\n}\n","import {defineValue} from './util'\nimport {OBSERVE_NAME} from './constants'\n\nconst arrayPrototype = Array.prototype\nconst arrayMethods = Object.create(arrayPrototype)\nconst arrayMutativeMethods = [\n 'push',\n 'pop',\n 'shift',\n 'unshift',\n 'splice',\n 'sort',\n 'reverse',\n]\n\n/**\n * Augment an target Array with arrayMethods\n *\n * @param {Array} array\n */\n\nexport default function amend (array) {\n Object.setPrototypeOf(array, arrayMethods)\n}\n\n/**\n * Intercept mutating methods and emit events\n */\n\nfor (let i = 0, l = arrayMutativeMethods.length; i < l; i++) {\n const method = arrayMutativeMethods[i]\n // cache original method\n const original = arrayPrototype[method]\n defineValue(arrayMethods, method, function mutator (...args) {\n const result = original.apply(this, args)\n const observer = this[OBSERVE_NAME]\n let inserted\n switch (method) {\n case 'push':\n inserted = args\n break\n case 'unshift':\n inserted = args\n break\n case 'splice':\n inserted = args.slice(2)\n break\n }\n if (inserted) observer.observeArray(inserted)\n observer.dep.notify() // notify change\n return result\n })\n}\n\n/**\n * Swap the element at the given index with a new value\n * and emits corresponding event.\n *\n * @param {Number} index\n * @param {*} value\n * @return {*} - replaced element\n */\n\nfunction $set (index, value) {\n if (index >= this.length) {\n this.length = Number(index) + 1\n }\n return this.splice(index, 1, value)[0]\n}\ndefineValue(arrayPrototype, '$set', $set)\n\n/**\n * Convenience method to remove the element at given index\n * or target element reference.\n *\n * @param {*} item\n * @return {*} - removed element\n */\n\nfunction $remove (item) {\n if (!this.length) return\n const index = this.indexOf(item)\n if (index > -1) {\n return this.splice(index, 1)\n }\n}\ndefineValue(arrayPrototype, '$remove', $remove)\n","import Dep from './dep'\nimport amendArray from './array'\nimport {\n defineValue,\n defineAccessor,\n isArray,\n isPlainObject,\n everyEntries,\n} from './util'\nimport {OBSERVE_NAME} from './constants'\n\n/**\n * Observer class that are attached to each observed\n * object. Once attached, the observer converts target\n * object's property keys into getter/setters that\n * collect dependencies and dispatches updates.\n *\n * @class\n * @param {Array|Object} value\n */\n\nclass Observer {\n constructor (value) {\n this.value = value\n this.dep = new Dep()\n defineValue(value, OBSERVE_NAME, this)\n if (isArray(value)) {\n amendArray(value)\n this.observeArray(value)\n } else {\n this.walk(value)\n }\n }\n\n /**\n * Walk through each property and convert them into\n * getter/setters. This method should only be called when\n * value type is Object.\n *\n * @param {Object} object\n */\n\n walk (object) {\n everyEntries(object, (key, value) => this.convert(key, value))\n }\n\n /**\n * Observe a list of Array items.\n *\n * @param {Array} items\n */\n\n observeArray (items) {\n for (let i = 0, l = items.length; i < l; i++) {\n observe(items[i])\n }\n }\n\n /**\n * Convert a property into getter/setter so we can emit\n * the events when the property is accessed/changed.\n *\n * @param {String} key\n * @param {*} value\n */\n\n convert (key, value) {\n defineReactive(this.value, key, value)\n }\n}\n\n/**\n * Attempt to create an observer instance for a value,\n * returns the new observer if successfully observed,\n * or the existing observer if the value already has one.\n *\n * @param {*} value\n * @return {Observer|undefined}\n */\n\nexport function observe (value) {\n if (!value || typeof value !== 'object') return\n let observer\n if (\n Object.prototype.hasOwnProperty.call(value, OBSERVE_NAME)\n && value[OBSERVE_NAME] instanceof Observer\n ) {\n observer = value[OBSERVE_NAME]\n } else if (\n (isArray(value) || isPlainObject(value))\n && Object.isExtensible(value)\n ) {\n observer = new Observer(value)\n }\n return observer\n}\n\n/**\n * Define a reactive property on an Object.\n *\n * @param {Object} object\n * @param {String} key\n * @param {*} value\n */\n\nexport function defineReactive (object, key, value) {\n const dep = new Dep()\n\n const desc = Object.getOwnPropertyDescriptor(object, key)\n if (desc && desc.configurable === false) return\n\n // cater for pre-defined getter/setters\n const getter = desc && desc.get\n const setter = desc && desc.set\n\n let childOb = observe(value)\n\n function reactiveGetter () {\n const currentValue = getter ? getter.call(object) : value\n if (Dep.target) {\n dep.depend()\n if (childOb) {\n childOb.dep.depend()\n }\n if (isArray(currentValue)) {\n for (let i = 0, l = currentValue.length, e; i < l; i++) {\n e = currentValue[i]\n e && e[OBSERVE_NAME] && e[OBSERVE_NAME].dep.depend()\n }\n }\n }\n return currentValue\n }\n function reactiveSetter (newValue) {\n const oldValue = getter ? getter.call(object) : value\n if (newValue === oldValue) return\n if (setter) {\n setter.call(object, newValue)\n } else {\n value = newValue\n }\n childOb = observe(newValue)\n dep.notify()\n }\n defineAccessor(object, key, reactiveGetter, reactiveSetter)\n}\n","import {warn} from './util'\n\n/**\n * Build a getter function. Requires eval.\n *\n * We isolate the try/catch so it doesn't affect the\n * optimization of the parse function when it is not called.\n *\n * @param {String} body\n * @return {Function|undefined}\n */\n\nfunction makeGetterFunction (body) {\n try {\n /* eslint-disable no-new-func */\n return new Function('scope', `return ${body};`)\n /* eslint-enable no-new-func */\n } catch (e) {\n warn('Invalid expression. Generated function body: ' + body)\n }\n}\n\n/**\n * Parse an expression to getter.\n *\n * @param {String} expression\n * @return {Function|undefined}\n */\n\nexport default function parse (expression) {\n expression = String.prototype.trim.call(expression)\n return makeGetterFunction('scope.' + expression)\n}\n","var callbacks = []\nvar pending = false\nfunction nextTickHandler () {\n pending = false\n var callbackCopies = callbacks.slice(0)\n callbacks.length = 0\n for (var i = 0; i < callbackCopies.length; i++) {\n callbackCopies[i]()\n }\n}\n\nvar callNextTick\nif (typeof process === 'object'\n && process\n && typeof process.nextTick === 'function'\n) {\n callNextTick = process.nextTick\n} else if (typeof MutationObserver !== 'undefined') {\n var counter = 0\n var textNode = document.createTextNode(counter)\n var observer = new MutationObserver(nextTickHandler)\n observer.observe(textNode, {\n characterData: true\n })\n callNextTick = function () {\n counter = counter === 0 ? 1 : 0\n textNode.data = String(counter)\n }\n} else {\n callNextTick = setTimeout\n}\n\n\nmodule.exports = function nextTick (callback, context) {\n var func = callback\n if (context) {\n var args = []\n var l = arguments.length\n while (--l > 1) {\n args.unshift(arguments[l])\n }\n func = function () {\n callback.apply(context, args)\n }\n }\n callbacks.push(func)\n if (pending) {\n return\n }\n pending = true\n callNextTick(nextTickHandler)\n}\n","import nextTick from 'smart-next-tick'\n\nlet queue = []\nlet has = {}\nlet waiting = false\nlet queueIndex\n\n/**\n * Reset the batcher's state.\n */\n\nfunction resetBatcherState () {\n queue = []\n has = {}\n waiting = false\n}\n\n/**\n * Flush queue and run the watchers.\n */\n\nfunction flushBatcherQueue () {\n runBatcherQueue(queue)\n resetBatcherState()\n}\n\n/**\n * Run the watchers in a single queue.\n *\n * @param {Array} queue\n */\n\nfunction runBatcherQueue (queue) {\n // do not cache length because more watchers might be pushed\n // as we run existing watchers\n for (queueIndex = 0; queueIndex < queue.length; queueIndex++) {\n const watcher = queue[queueIndex]\n const id = watcher.id\n has[id] = null\n watcher.run()\n }\n}\n\n/**\n * Push a watcher into the watcher queue.\n * Jobs with duplicate IDs will be skipped unless it's\n * pushed when the queue is being flushed.\n *\n * @param {Watcher} watcher\n * properties:\n * - {Number} id\n * - {Function} run\n */\n\nexport default function batch (watcher) {\n const id = watcher.id\n if (has[id] == null) {\n has[id] = queue.length\n queue.push(watcher)\n // queue the flush\n if (!waiting) {\n waiting = true\n nextTick(flushBatcherQueue)\n }\n }\n}\n","import observe from './index'\nimport Dep from './dep'\nimport parseExpression from './expression'\nimport batch from './batcher'\nimport {\n isArray,\n isObject,\n isFunction,\n _Set as Set,\n} from './util'\nimport {WATCHERS_PROPERTY_NAME} from './constants'\n\nlet uid = 0\n\nclass Watcher {\n\n /**\n * A watcher parses an expression, collects dependencies,\n * and fires callback when the expression value changes.\n *\n * @param {Object} owner\n * @param {String|Function} getter\n * @param {Function} callback\n * @param {Object} options\n * - {Boolean} deep\n * - {Boolean} sync\n * - {Boolean} lazy\n * @constructor\n */\n\n constructor (owner, getter, callback, options) {\n owner[WATCHERS_PROPERTY_NAME].push(this)\n this.owner = owner\n this.getter = getter\n this.callback = callback\n this.options = options\n // uid for batching\n this.id = ++uid\n this.active = true\n // for lazy watchers\n this.dirty = options.lazy\n this.deps = []\n this.newDeps = []\n this.depIds = new Set()\n this.newDepIds = new Set()\n this.value = options.lazy\n ? undefined\n : this.get()\n }\n\n /**\n * Evaluate the getter, and re-collect dependencies.\n */\n\n get () {\n this.beforeGet()\n const scope = this.owner\n const value = this.getter.call(scope, scope)\n if (this.options.deep) {\n traverse(value)\n }\n this.afterGet()\n return value\n }\n\n /**\n * Prepare for dependency collection.\n */\n\n beforeGet () {\n Dep.target = this\n }\n\n /**\n * Add a dependency to this directive.\n *\n * @param {Dep} dep\n */\n\n addDep (dep) {\n const id = dep.id\n if (!this.newDepIds.has(id)) {\n this.newDepIds.add(id)\n this.newDeps.push(dep)\n if (!this.depIds.has(id)) {\n dep.addSub(this)\n }\n }\n }\n\n /**\n * Clean up for dependency collection.\n */\n\n afterGet () {\n Dep.target = null\n let i = this.deps.length\n while (i--) {\n const dep = this.deps[i]\n if (!this.newDepIds.has(dep.id)) {\n dep.removeSub(this)\n }\n }\n let tmp = this.depIds\n this.depIds = this.newDepIds\n this.newDepIds = tmp\n this.newDepIds.clear()\n tmp = this.deps\n this.deps = this.newDeps\n this.newDeps = tmp\n this.newDeps.length = 0\n }\n\n /**\n * Will be called when a dependency changes.\n */\n\n update () {\n if (this.options.lazy) {\n this.dirty = true\n } else if (this.options.sync) {\n this.run()\n } else {\n batch(this)\n }\n }\n\n /**\n * Will be called by the batcher.\n */\n\n run () {\n if (this.active) {\n const value = this.get()\n if (\n value !== this.value\n // Deep watchers and watchers on Object/Arrays should fire even when\n // the value is the same, because the value may have mutated;\n || ((isObject(value) || this.options.deep))\n ) {\n const oldValue = this.value\n this.value = value\n this.callback.call(this.owner, value, oldValue)\n }\n }\n }\n\n /**\n * Evaluate the value of the watcher.\n * This only gets called for lazy watchers.\n */\n\n evaluate () {\n // avoid overwriting another watcher that is being collected.\n const current = Dep.target\n this.value = this.get()\n this.dirty = false\n Dep.target = current\n }\n\n /**\n * Depend on all deps collected by this watcher.\n */\n\n depend () {\n let i = this.deps.length\n while (i--) {\n this.deps[i].depend()\n }\n }\n\n /**\n * Remove self from all dependencies' subcriber list.\n */\n\n teardown () {\n if (this.active) {\n let i = this.deps.length\n while (i--) {\n this.deps[i].removeSub(this)\n }\n this.active = false\n this.owner = this.callback = this.value = null\n }\n }\n}\n\n/**\n * Recrusively traverse an object to evoke all converted\n * getters, so that every nested property inside the object\n * is collected as a \"deep\" dependency.\n *\n * @param {*} value\n */\n\nfunction traverse (value) {\n let i, keys\n if (isArray(value)) {\n i = value.length\n while (i--) traverse(value[i])\n } else if (isObject(value)) {\n keys = Object.keys(value)\n i = keys.length\n while (i--) traverse(value[keys[i]])\n }\n}\n\n/**\n * Create an watcher instance, returns the new watcher.\n *\n * @param {Object} owner\n * @param {String|Function} expressionOrFunction\n * @param {Function} callback\n * @param {Object} options\n * - {Boolean} deep\n * - {Boolean} sync\n * - {Boolean} lazy\n * @return {Watcher}\n */\n\nexport function watch (owner, expressionOrFunction, callback, options) {\n // parse expression for getter\n const getter = isFunction(expressionOrFunction)\n ? expressionOrFunction\n : parseExpression(expressionOrFunction)\n return new Watcher(owner, getter, callback, options)\n}\n\n/**\n * Make a computed getter, which can collect dependencies.\n *\n * @param {Object} owner\n * @param {Function} getter\n */\n\nexport function makeComputed (owner, getter) {\n const watcher = new Watcher(owner, getter, null, {\n deep: observe.deep,\n lazy: true,\n sync: observe.sync,\n })\n return function computedGetter () {\n if (watcher.options.lazy && Dep.target && !Dep.target.options.lazy) {\n watcher.options.lazy = false\n watcher.callback = function () {\n const deps = watcher.deps\n for (let i = 0, l = deps.length; i < l; i++) {\n deps[i].notify()\n }\n }\n }\n if (watcher.dirty) {\n watcher.evaluate()\n }\n if (Dep.target) {\n watcher.depend()\n }\n return watcher.value\n }\n}\n","import {\n observe as doObserve,\n defineReactive,\n} from './observe'\nimport {\n watch as doWatch,\n makeComputed,\n} from './watcher'\nimport {\n defineValue,\n defineAccessor,\n noop,\n isFunction,\n everyEntries,\n} from './util'\nimport {\n WATCHERS_PROPERTY_NAME,\n DATA_PROPTERTY_NAME,\n} from './constants'\n\nObject.defineProperties(observe, {\n 'react': {value: react},\n 'compute': {value: compute},\n 'watch': {value: watch},\n 'default': {value: watch, writable: true}, // Only could be react, compute or watch\n 'deep': {value: false, writable: true},\n 'lazy': {value: false, writable: true},\n 'sync': {value: false, writable: true},\n})\n\n/**\n * observe\n *\n * @public\n * @param {Object} target\n * @param {*} [expression]\n * @param {*} [func]\n * @param {*} [options]\n * @return {Function} observe\n */\n\nexport default function observe (target, expression, func, options) {\n ensure(target)\n return observe.default(target, expression, func, options)\n}\n\n/**\n * React options\n *\n * @param {Object} options\n * @param {Object} [target]\n * @return {Function} observe\n */\n\nfunction react (options, target) {\n if (target) {\n ensure(target)\n } else {\n target = {}\n init(target)\n }\n options.methods && carryMethods(target, options.methods)\n options.data && reactProperties(target, options.data)\n options.computed && computeProperties(target, options.computed)\n options.watchers && watchProperties(target, options.watchers)\n return target\n}\n\n/**\n * Compute property\n *\n * @param {Object} target\n * @param {String} name\n * @param {Function|Object} getterOrAccessor\n * - Function getter\n * - Object accessor\n * - Function [get] - getter\n * - Function [set] - setter\n * - Boolean [cache]\n * @param {Boolean} [cache]\n */\n\nfunction compute (target, name, getterOrAccessor, cache) {\n ensure(target)\n let getter, setter\n if (isFunction(getterOrAccessor)) {\n getter = cache !== false\n ? makeComputed(target, getterOrAccessor)\n : getterOrAccessor.bind(this)\n setter = noop\n } else {\n getter = getterOrAccessor.get\n ? getterOrAccessor.cache !== false || cache !== false\n ? makeComputed(target, getterOrAccessor.get)\n : getterOrAccessor.get.bind(this)\n : noop\n setter = getterOrAccessor.set ? getterOrAccessor.set.bind(this) : noop\n }\n defineAccessor(target, name, getter, setter)\n}\n\n/**\n * Watch property\n *\n * @param {Object} target\n * @param {String|Function} expressionOrFunction\n * @param {Function} callback\n * @param {Object} [options]\n * - {Boolean} deep\n * - {Boolean} sync\n * - {Boolean} lazy\n * @return {Watcher}\n */\n\nfunction watch (target, expressionOrFunction, callback, options = observe) {\n ensure(target)\n return doWatch(target, expressionOrFunction, callback, options)\n}\n\n/**\n * @param {Object} target\n */\n\nfunction init (target) {\n defineValue(target, WATCHERS_PROPERTY_NAME, [], false)\n defineValue(target, DATA_PROPTERTY_NAME, Object.create(null), false)\n doObserve(target[DATA_PROPTERTY_NAME])\n reactSelfProperties(target)\n}\n\nfunction ensure (target) {\n if (!Object.prototype.hasOwnProperty.call(target, WATCHERS_PROPERTY_NAME)) {\n init(target)\n }\n}\n\n/**\n * @param {Object} target\n * @param {Object} methods\n */\n\nfunction carryMethods (target, methods) {\n everyEntries(methods, (name, method) => {\n target[name] = method.bind(target)\n })\n}\n\n/**\n * @param {Object} target\n * @param {String} key\n * @param {*} value\n */\n\nfunction reactProperty (target, key, value) {\n target[DATA_PROPTERTY_NAME][key] = value\n defineReactive(target[DATA_PROPTERTY_NAME], key, value)\n proxy(target, key)\n}\n\n/**\n * @param {Object} target\n * @param {Object} properties\n */\n\nfunction reactProperties (target, properties) {\n everyEntries(properties, (key, value) => reactProperty(target, key, value))\n}\n\n/**\n * @param {Object} target\n */\n\nfunction reactSelfProperties (target) {\n everyEntries(target, (key, value) => {\n !isFunction(value) && reactProperty(target, key, value)\n })\n}\n\n/**\n * @param {Object} target\n * @param {Object} properties\n */\n\nfunction computeProperties (target, properties) {\n everyEntries(properties, (key, value) => compute(target, key, value))\n}\n\n/**\n * @param {Object} target\n * @param {Object} properties\n */\n\nfunction watchProperties (target, properties) {\n everyEntries(properties, (expression, functionOrOption) => {\n if (isFunction(functionOrOption)) {\n watch(target, expression, functionOrOption)\n } else {\n watch(target, expression, functionOrOption.watcher, functionOrOption)\n }\n })\n}\n\n/**\n * @param {Object} target\n * @param {String} key\n */\n\nfunction proxy (target, key) {\n function getter () {\n return target[DATA_PROPTERTY_NAME][key]\n }\n function setter (value) {\n target[DATA_PROPTERTY_NAME][key] = value\n }\n defineAccessor(target, key, getter, setter)\n}\n"],"names":["uid","Dep","id","subs","sub","push","$remove","target","addDep","i","l","length","update","OBSERVE_NAME","WATCHERS_PROPERTY_NAME","DATA_PROPTERTY_NAME","DEBUGGING","process","env","NODE_ENV","defineValue","object","property","value","enumerable","defineProperty","defineAccessor","getter","setter","isArray","Array","toString","Object","prototype","OBJECT_STRING","isPlainObject","call","isObject","isFunction","func","everyEntries","callback","keys","noop","warn","console","_Set","Set","match","set","create","has","key","undefined","add","clear","arrayPrototype","arrayMethods","arrayMutativeMethods","amend","array","setPrototypeOf","method","original","mutator","args","result","apply","observer","inserted","slice","observeArray","dep","notify","$set","index","Number","splice","item","indexOf","Observer","walk","convert","items","observe","hasOwnProperty","isExtensible","defineReactive","desc","getOwnPropertyDescriptor","configurable","get","childOb","reactiveGetter","currentValue","depend","e","reactiveSetter","newValue","oldValue","makeGetterFunction","body","Function","parse","expression","String","trim","callbacks","pending","nextTickHandler","callbackCopies","callNextTick","nextTick","MutationObserver","counter","textNode","document","createTextNode","data","setTimeout","context","arguments","unshift","queue","waiting","queueIndex","resetBatcherState","flushBatcherQueue","runBatcherQueue","watcher","run","batch","Watcher","owner","options","active","dirty","lazy","deps","newDeps","depIds","newDepIds","beforeGet","scope","deep","afterGet","addSub","removeSub","tmp","sync","current","traverse","watch","expressionOrFunction","parseExpression","makeComputed","computedGetter","evaluate","defineProperties","react","compute","writable","default","methods","carryMethods","reactProperties","computed","computeProperties","watchers","watchProperties","name","getterOrAccessor","cache","bind","doWatch","init","ensure","reactProperty","properties","reactSelfProperties","functionOrOption","proxy"],"mappings":"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"}
--------------------------------------------------------------------------------
/dist/smart-observe.min.js:
--------------------------------------------------------------------------------
1 | !function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define("observe",t):e.observe=t()}(this,function(){"use strict";function e(e,t,n,i){Object.defineProperty(e,t,{value:n,enumerable:!!i,writable:!0,configurable:!0})}function t(e,t,n,i){Object.defineProperty(e,t,{get:n,set:i,enumerable:!0,configurable:!0})}function n(e){return K.call(e)===L}function i(e){return null!==e&&"object"===("undefined"==typeof e?"undefined":N(e))}function o(e){return"function"==typeof e}function r(e,t){for(var n=Object.keys(e),i=0,o=n.length;i=this.length&&(this.length=Number(e)+1),this.splice(e,1,t)[0]}function c(e){if(this.length){var t=this.indexOf(e);return t>-1?this.splice(t,1):void 0}}function f(e){if(e&&"object"===("undefined"==typeof e?"undefined":N(e))){var t=void 0;return Object.prototype.hasOwnProperty.call(e,V)&&e[V]instanceof ne?t=e[V]:(J(e)||n(e))&&Object.isExtensible(e)&&(t=new ne(e)),t}}function l(e,n,i){function o(){var t=a?a.call(e):i;if(F.target&&(s.depend(),l&&l.dep.depend(),J(t)))for(var n,o=0,r=t.length;o3&&void 0!==arguments[3]?arguments[3]:O;return I(e),k(e,t,n,i)}function _(t){e(t,q,[],!1),e(t,B,Object.create(null),!1),f(t[B]),A(t)}function I(e){Object.prototype.hasOwnProperty.call(e,q)||_(e)}function x(e,t){r(t,function(t,n){e[t]=n.bind(e)})}function z(e,t,n){e[B][t]=n,l(e[B],t,n),E(e,t)}function P(e,t){r(t,function(t,n){return z(e,t,n)})}function A(e){r(e,function(t,n){!o(n)&&z(e,t,n)})}function G(e,t){r(t,function(t,n){return D(e,t,n)})}function T(e,t){r(t,function(t,n){o(n)?S(e,t,n):S(e,t,n.watcher,n)})}function E(e,n){function i(){return e[B][n]}function o(t){e[B][n]=t}t(e,n,i,o)}var N="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},$=function(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")},M=function(){function e(e,t){for(var n=0;n1;)i.unshift(arguments[o]);n=function(){e.apply(t,i)}}ie.push(n),oe||(oe=!0,te(p))},ce=[],fe={},le=!1,he=void 0,de=0,pe=function(){function e(t,n,i,o){$(this,e),t[q].push(this),this.owner=t,this.getter=n,this.callback=i,this.options=o,this.id=++de,this.active=!0,this.dirty=o.lazy,this.deps=[],this.newDeps=[],this.depIds=new R,this.newDepIds=new R,this.value=o.lazy?void 0:this.get()}return M(e,[{key:"get",value:function(){this.beforeGet();var e=this.owner,t=this.getter.call(e,e);return this.options.deep&&w(t),this.afterGet(),t}},{key:"beforeGet",value:function(){F.target=this}},{key:"addDep",value:function(e){var t=e.id;this.newDepIds.has(t)||(this.newDepIds.add(t),this.newDeps.push(e),this.depIds.has(t)||e.addSub(this))}},{key:"afterGet",value:function(){F.target=null;for(var e=this.deps.length;e--;){var t=this.deps[e];this.newDepIds.has(t.id)||t.removeSub(this)}var n=this.depIds;this.depIds=this.newDepIds,this.newDepIds=n,this.newDepIds.clear(),n=this.deps,this.deps=this.newDeps,this.newDeps=n,this.newDeps.length=0}},{key:"update",value:function(){this.options.lazy?this.dirty=!0:this.options.sync?this.run():g(this)}},{key:"run",value:function(){if(this.active){var e=this.get();if(e!==this.value||i(e)||this.options.deep){var t=this.value;this.value=e,this.callback.call(this.owner,e,t)}}}},{key:"evaluate",value:function(){var e=F.target;this.value=this.get(),this.dirty=!1,F.target=e}},{key:"depend",value:function(){for(var e=this.deps.length;e--;)this.deps[e].depend()}},{key:"teardown",value:function(){if(this.active){for(var e=this.deps.length;e--;)this.deps[e].removeSub(this);this.active=!1,this.owner=this.callback=this.value=null}}}]),e}();return Object.defineProperties(O,{react:{value:j},compute:{value:D},watch:{value:S},default:{value:S,writable:!0},deep:{value:!1,writable:!0},lazy:{value:!1,writable:!0},sync:{value:!1,writable:!0}}),O});
2 | //# sourceMappingURL=smart-observe.min.js.map
3 |
--------------------------------------------------------------------------------
/dist/smart-observe.min.js.map:
--------------------------------------------------------------------------------
1 | {"version":3,"file":"smart-observe.min.js","sources":["../src/util.js","../src/array.js","../src/observe.js","../src/expression.js","../node_modules/smart-next-tick/nextTick.js","../src/batcher.js","../src/watcher.js","../src/index.js","../src/dep.js","../src/constants.js"],"sourcesContent":["import {DEBUGGING} from './constants'\n\n/**\n * Define property with value.\n *\n * @param {Object} object\n * @param {String} property\n * @param {*} value\n * @param {Boolean} [enumerable]\n */\n\nexport function defineValue (object, property, value, enumerable) {\n Object.defineProperty(object, property, {\n value,\n enumerable: !!enumerable,\n writable: true,\n configurable: true,\n })\n}\n\n/**\n * Define property with getter and setter.\n *\n * @param {Object} object\n * @param {String} property\n * @param {Function} getter\n * @param {Function} setter\n */\n\nexport function defineAccessor (object, property, getter, setter) {\n Object.defineProperty(object, property, {\n get: getter,\n set: setter,\n enumerable: true,\n configurable: true,\n })\n}\n\n/**\n * Array type check.\n *\n * @return {Boolean}\n */\n\nexport const isArray = Array.isArray\n\n/**\n * Strict object type check. Only returns true\n * for plain JavaScript objects.\n *\n * @param {*} object\n * @return {Boolean}\n */\n\nconst toString = Object.prototype.toString\nconst OBJECT_STRING = '[object Object]'\nexport function isPlainObject (object) {\n return toString.call(object) === OBJECT_STRING\n}\n\n/**\n * Quick object check - this is primarily used to tell\n * Objects from primitive values when we know the value\n * is a JSON-compliant type.\n *\n * @param {*} object\n * @return {Boolean}\n */\n\nexport function isObject (object) {\n return object !== null && typeof object === 'object'\n}\n\n/**\n * Function type check\n *\n * @param {*} func\n * @param {Boolean}\n */\n\nexport function isFunction (func) {\n return typeof func === 'function'\n}\n\n/**\n * Iterate object\n *\n * @param {Object} object\n * @param {Function} callback\n */\n\nexport function everyEntries (object, callback) {\n const keys = Object.keys(object)\n for (let i = 0, l = keys.length; i < l; i++) {\n callback(keys[i], object[keys[i]])\n }\n}\n\n/**\n * noop is function which is nothing to do.\n */\n\nexport function noop () {}\n\n/**\n * @param {String} string\n */\n\nexport const warn = typeof DEBUGGING !== 'undefined' && DEBUGGING\n && typeof console !== 'undefined' && console\n && isFunction(console.warn)\n ? console.warn\n : noop\n\nexport let _Set\nif (typeof Set !== 'undefined' && Set.toString().match(/native code/)) {\n // use native Set when available.\n _Set = Set\n} else {\n // a non-standard Set polyfill that only works with primitive keys.\n _Set = function () {\n this.set = Object.create(null)\n }\n _Set.prototype.has = function (key) {\n return this.set[key] !== undefined\n }\n _Set.prototype.add = function (key) {\n this.set[key] = 1\n }\n _Set.prototype.clear = function () {\n this.set = Object.create(null)\n }\n}\n","import {defineValue} from './util'\nimport {OBSERVE_NAME} from './constants'\n\nconst arrayPrototype = Array.prototype\nconst arrayMethods = Object.create(arrayPrototype)\nconst arrayMutativeMethods = [\n 'push',\n 'pop',\n 'shift',\n 'unshift',\n 'splice',\n 'sort',\n 'reverse',\n]\n\n/**\n * Augment an target Array with arrayMethods\n *\n * @param {Array} array\n */\n\nexport default function amend (array) {\n Object.setPrototypeOf(array, arrayMethods)\n}\n\n/**\n * Intercept mutating methods and emit events\n */\n\nfor (let i = 0, l = arrayMutativeMethods.length; i < l; i++) {\n const method = arrayMutativeMethods[i]\n // cache original method\n const original = arrayPrototype[method]\n defineValue(arrayMethods, method, function mutator (...args) {\n const result = original.apply(this, args)\n const observer = this[OBSERVE_NAME]\n let inserted\n switch (method) {\n case 'push':\n inserted = args\n break\n case 'unshift':\n inserted = args\n break\n case 'splice':\n inserted = args.slice(2)\n break\n }\n if (inserted) observer.observeArray(inserted)\n observer.dep.notify() // notify change\n return result\n })\n}\n\n/**\n * Swap the element at the given index with a new value\n * and emits corresponding event.\n *\n * @param {Number} index\n * @param {*} value\n * @return {*} - replaced element\n */\n\nfunction $set (index, value) {\n if (index >= this.length) {\n this.length = Number(index) + 1\n }\n return this.splice(index, 1, value)[0]\n}\ndefineValue(arrayPrototype, '$set', $set)\n\n/**\n * Convenience method to remove the element at given index\n * or target element reference.\n *\n * @param {*} item\n * @return {*} - removed element\n */\n\nfunction $remove (item) {\n if (!this.length) return\n const index = this.indexOf(item)\n if (index > -1) {\n return this.splice(index, 1)\n }\n}\ndefineValue(arrayPrototype, '$remove', $remove)\n","import Dep from './dep'\nimport amendArray from './array'\nimport {\n defineValue,\n defineAccessor,\n isArray,\n isPlainObject,\n everyEntries,\n} from './util'\nimport {OBSERVE_NAME} from './constants'\n\n/**\n * Observer class that are attached to each observed\n * object. Once attached, the observer converts target\n * object's property keys into getter/setters that\n * collect dependencies and dispatches updates.\n *\n * @class\n * @param {Array|Object} value\n */\n\nclass Observer {\n constructor (value) {\n this.value = value\n this.dep = new Dep()\n defineValue(value, OBSERVE_NAME, this)\n if (isArray(value)) {\n amendArray(value)\n this.observeArray(value)\n } else {\n this.walk(value)\n }\n }\n\n /**\n * Walk through each property and convert them into\n * getter/setters. This method should only be called when\n * value type is Object.\n *\n * @param {Object} object\n */\n\n walk (object) {\n everyEntries(object, (key, value) => this.convert(key, value))\n }\n\n /**\n * Observe a list of Array items.\n *\n * @param {Array} items\n */\n\n observeArray (items) {\n for (let i = 0, l = items.length; i < l; i++) {\n observe(items[i])\n }\n }\n\n /**\n * Convert a property into getter/setter so we can emit\n * the events when the property is accessed/changed.\n *\n * @param {String} key\n * @param {*} value\n */\n\n convert (key, value) {\n defineReactive(this.value, key, value)\n }\n}\n\n/**\n * Attempt to create an observer instance for a value,\n * returns the new observer if successfully observed,\n * or the existing observer if the value already has one.\n *\n * @param {*} value\n * @return {Observer|undefined}\n */\n\nexport function observe (value) {\n if (!value || typeof value !== 'object') return\n let observer\n if (\n Object.prototype.hasOwnProperty.call(value, OBSERVE_NAME)\n && value[OBSERVE_NAME] instanceof Observer\n ) {\n observer = value[OBSERVE_NAME]\n } else if (\n (isArray(value) || isPlainObject(value))\n && Object.isExtensible(value)\n ) {\n observer = new Observer(value)\n }\n return observer\n}\n\n/**\n * Define a reactive property on an Object.\n *\n * @param {Object} object\n * @param {String} key\n * @param {*} value\n */\n\nexport function defineReactive (object, key, value) {\n const dep = new Dep()\n\n const desc = Object.getOwnPropertyDescriptor(object, key)\n if (desc && desc.configurable === false) return\n\n // cater for pre-defined getter/setters\n const getter = desc && desc.get\n const setter = desc && desc.set\n\n let childOb = observe(value)\n\n function reactiveGetter () {\n const currentValue = getter ? getter.call(object) : value\n if (Dep.target) {\n dep.depend()\n if (childOb) {\n childOb.dep.depend()\n }\n if (isArray(currentValue)) {\n for (let i = 0, l = currentValue.length, e; i < l; i++) {\n e = currentValue[i]\n e && e[OBSERVE_NAME] && e[OBSERVE_NAME].dep.depend()\n }\n }\n }\n return currentValue\n }\n function reactiveSetter (newValue) {\n const oldValue = getter ? getter.call(object) : value\n if (newValue === oldValue) return\n if (setter) {\n setter.call(object, newValue)\n } else {\n value = newValue\n }\n childOb = observe(newValue)\n dep.notify()\n }\n defineAccessor(object, key, reactiveGetter, reactiveSetter)\n}\n","import {warn} from './util'\n\n/**\n * Build a getter function. Requires eval.\n *\n * We isolate the try/catch so it doesn't affect the\n * optimization of the parse function when it is not called.\n *\n * @param {String} body\n * @return {Function|undefined}\n */\n\nfunction makeGetterFunction (body) {\n try {\n /* eslint-disable no-new-func */\n return new Function('scope', `return ${body};`)\n /* eslint-enable no-new-func */\n } catch (e) {\n warn('Invalid expression. Generated function body: ' + body)\n }\n}\n\n/**\n * Parse an expression to getter.\n *\n * @param {String} expression\n * @return {Function|undefined}\n */\n\nexport default function parse (expression) {\n expression = String.prototype.trim.call(expression)\n return makeGetterFunction('scope.' + expression)\n}\n","var callbacks = []\nvar pending = false\nfunction nextTickHandler () {\n pending = false\n var callbackCopies = callbacks.slice(0)\n callbacks.length = 0\n for (var i = 0; i < callbackCopies.length; i++) {\n callbackCopies[i]()\n }\n}\n\nvar callNextTick\nif (typeof process === 'object'\n && process\n && typeof process.nextTick === 'function'\n) {\n callNextTick = process.nextTick\n} else if (typeof MutationObserver !== 'undefined') {\n var counter = 0\n var textNode = document.createTextNode(counter)\n var observer = new MutationObserver(nextTickHandler)\n observer.observe(textNode, {\n characterData: true\n })\n callNextTick = function () {\n counter = counter === 0 ? 1 : 0\n textNode.data = String(counter)\n }\n} else {\n callNextTick = setTimeout\n}\n\n\nmodule.exports = function nextTick (callback, context) {\n var func = callback\n if (context) {\n var args = []\n var l = arguments.length\n while (--l > 1) {\n args.unshift(arguments[l])\n }\n func = function () {\n callback.apply(context, args)\n }\n }\n callbacks.push(func)\n if (pending) {\n return\n }\n pending = true\n callNextTick(nextTickHandler)\n}\n","import nextTick from 'smart-next-tick'\n\nlet queue = []\nlet has = {}\nlet waiting = false\nlet queueIndex\n\n/**\n * Reset the batcher's state.\n */\n\nfunction resetBatcherState () {\n queue = []\n has = {}\n waiting = false\n}\n\n/**\n * Flush queue and run the watchers.\n */\n\nfunction flushBatcherQueue () {\n runBatcherQueue(queue)\n resetBatcherState()\n}\n\n/**\n * Run the watchers in a single queue.\n *\n * @param {Array} queue\n */\n\nfunction runBatcherQueue (queue) {\n // do not cache length because more watchers might be pushed\n // as we run existing watchers\n for (queueIndex = 0; queueIndex < queue.length; queueIndex++) {\n const watcher = queue[queueIndex]\n const id = watcher.id\n has[id] = null\n watcher.run()\n }\n}\n\n/**\n * Push a watcher into the watcher queue.\n * Jobs with duplicate IDs will be skipped unless it's\n * pushed when the queue is being flushed.\n *\n * @param {Watcher} watcher\n * properties:\n * - {Number} id\n * - {Function} run\n */\n\nexport default function batch (watcher) {\n const id = watcher.id\n if (has[id] == null) {\n has[id] = queue.length\n queue.push(watcher)\n // queue the flush\n if (!waiting) {\n waiting = true\n nextTick(flushBatcherQueue)\n }\n }\n}\n","import observe from './index'\nimport Dep from './dep'\nimport parseExpression from './expression'\nimport batch from './batcher'\nimport {\n isArray,\n isObject,\n isFunction,\n _Set as Set,\n} from './util'\nimport {WATCHERS_PROPERTY_NAME} from './constants'\n\nlet uid = 0\n\nclass Watcher {\n\n /**\n * A watcher parses an expression, collects dependencies,\n * and fires callback when the expression value changes.\n *\n * @param {Object} owner\n * @param {String|Function} getter\n * @param {Function} callback\n * @param {Object} options\n * - {Boolean} deep\n * - {Boolean} sync\n * - {Boolean} lazy\n * @constructor\n */\n\n constructor (owner, getter, callback, options) {\n owner[WATCHERS_PROPERTY_NAME].push(this)\n this.owner = owner\n this.getter = getter\n this.callback = callback\n this.options = options\n // uid for batching\n this.id = ++uid\n this.active = true\n // for lazy watchers\n this.dirty = options.lazy\n this.deps = []\n this.newDeps = []\n this.depIds = new Set()\n this.newDepIds = new Set()\n this.value = options.lazy\n ? undefined\n : this.get()\n }\n\n /**\n * Evaluate the getter, and re-collect dependencies.\n */\n\n get () {\n this.beforeGet()\n const scope = this.owner\n const value = this.getter.call(scope, scope)\n if (this.options.deep) {\n traverse(value)\n }\n this.afterGet()\n return value\n }\n\n /**\n * Prepare for dependency collection.\n */\n\n beforeGet () {\n Dep.target = this\n }\n\n /**\n * Add a dependency to this directive.\n *\n * @param {Dep} dep\n */\n\n addDep (dep) {\n const id = dep.id\n if (!this.newDepIds.has(id)) {\n this.newDepIds.add(id)\n this.newDeps.push(dep)\n if (!this.depIds.has(id)) {\n dep.addSub(this)\n }\n }\n }\n\n /**\n * Clean up for dependency collection.\n */\n\n afterGet () {\n Dep.target = null\n let i = this.deps.length\n while (i--) {\n const dep = this.deps[i]\n if (!this.newDepIds.has(dep.id)) {\n dep.removeSub(this)\n }\n }\n let tmp = this.depIds\n this.depIds = this.newDepIds\n this.newDepIds = tmp\n this.newDepIds.clear()\n tmp = this.deps\n this.deps = this.newDeps\n this.newDeps = tmp\n this.newDeps.length = 0\n }\n\n /**\n * Will be called when a dependency changes.\n */\n\n update () {\n if (this.options.lazy) {\n this.dirty = true\n } else if (this.options.sync) {\n this.run()\n } else {\n batch(this)\n }\n }\n\n /**\n * Will be called by the batcher.\n */\n\n run () {\n if (this.active) {\n const value = this.get()\n if (\n value !== this.value\n // Deep watchers and watchers on Object/Arrays should fire even when\n // the value is the same, because the value may have mutated;\n || ((isObject(value) || this.options.deep))\n ) {\n const oldValue = this.value\n this.value = value\n this.callback.call(this.owner, value, oldValue)\n }\n }\n }\n\n /**\n * Evaluate the value of the watcher.\n * This only gets called for lazy watchers.\n */\n\n evaluate () {\n // avoid overwriting another watcher that is being collected.\n const current = Dep.target\n this.value = this.get()\n this.dirty = false\n Dep.target = current\n }\n\n /**\n * Depend on all deps collected by this watcher.\n */\n\n depend () {\n let i = this.deps.length\n while (i--) {\n this.deps[i].depend()\n }\n }\n\n /**\n * Remove self from all dependencies' subcriber list.\n */\n\n teardown () {\n if (this.active) {\n let i = this.deps.length\n while (i--) {\n this.deps[i].removeSub(this)\n }\n this.active = false\n this.owner = this.callback = this.value = null\n }\n }\n}\n\n/**\n * Recrusively traverse an object to evoke all converted\n * getters, so that every nested property inside the object\n * is collected as a \"deep\" dependency.\n *\n * @param {*} value\n */\n\nfunction traverse (value) {\n let i, keys\n if (isArray(value)) {\n i = value.length\n while (i--) traverse(value[i])\n } else if (isObject(value)) {\n keys = Object.keys(value)\n i = keys.length\n while (i--) traverse(value[keys[i]])\n }\n}\n\n/**\n * Create an watcher instance, returns the new watcher.\n *\n * @param {Object} owner\n * @param {String|Function} expressionOrFunction\n * @param {Function} callback\n * @param {Object} options\n * - {Boolean} deep\n * - {Boolean} sync\n * - {Boolean} lazy\n * @return {Watcher}\n */\n\nexport function watch (owner, expressionOrFunction, callback, options) {\n // parse expression for getter\n const getter = isFunction(expressionOrFunction)\n ? expressionOrFunction\n : parseExpression(expressionOrFunction)\n return new Watcher(owner, getter, callback, options)\n}\n\n/**\n * Make a computed getter, which can collect dependencies.\n *\n * @param {Object} owner\n * @param {Function} getter\n */\n\nexport function makeComputed (owner, getter) {\n const watcher = new Watcher(owner, getter, null, {\n deep: observe.deep,\n lazy: true,\n sync: observe.sync,\n })\n return function computedGetter () {\n if (watcher.options.lazy && Dep.target && !Dep.target.options.lazy) {\n watcher.options.lazy = false\n watcher.callback = function () {\n const deps = watcher.deps\n for (let i = 0, l = deps.length; i < l; i++) {\n deps[i].notify()\n }\n }\n }\n if (watcher.dirty) {\n watcher.evaluate()\n }\n if (Dep.target) {\n watcher.depend()\n }\n return watcher.value\n }\n}\n","import {\n observe as doObserve,\n defineReactive,\n} from './observe'\nimport {\n watch as doWatch,\n makeComputed,\n} from './watcher'\nimport {\n defineValue,\n defineAccessor,\n noop,\n isFunction,\n everyEntries,\n} from './util'\nimport {\n WATCHERS_PROPERTY_NAME,\n DATA_PROPTERTY_NAME,\n} from './constants'\n\nObject.defineProperties(observe, {\n 'react': {value: react},\n 'compute': {value: compute},\n 'watch': {value: watch},\n 'default': {value: watch, writable: true}, // Only could be react, compute or watch\n 'deep': {value: false, writable: true},\n 'lazy': {value: false, writable: true},\n 'sync': {value: false, writable: true},\n})\n\n/**\n * observe\n *\n * @public\n * @param {Object} target\n * @param {*} [expression]\n * @param {*} [func]\n * @param {*} [options]\n * @return {Function} observe\n */\n\nexport default function observe (target, expression, func, options) {\n ensure(target)\n return observe.default(target, expression, func, options)\n}\n\n/**\n * React options\n *\n * @param {Object} options\n * @param {Object} [target]\n * @return {Function} observe\n */\n\nfunction react (options, target) {\n if (target) {\n ensure(target)\n } else {\n target = {}\n init(target)\n }\n options.methods && carryMethods(target, options.methods)\n options.data && reactProperties(target, options.data)\n options.computed && computeProperties(target, options.computed)\n options.watchers && watchProperties(target, options.watchers)\n return target\n}\n\n/**\n * Compute property\n *\n * @param {Object} target\n * @param {String} name\n * @param {Function|Object} getterOrAccessor\n * - Function getter\n * - Object accessor\n * - Function [get] - getter\n * - Function [set] - setter\n * - Boolean [cache]\n * @param {Boolean} [cache]\n */\n\nfunction compute (target, name, getterOrAccessor, cache) {\n ensure(target)\n let getter, setter\n if (isFunction(getterOrAccessor)) {\n getter = cache !== false\n ? makeComputed(target, getterOrAccessor)\n : getterOrAccessor.bind(this)\n setter = noop\n } else {\n getter = getterOrAccessor.get\n ? getterOrAccessor.cache !== false || cache !== false\n ? makeComputed(target, getterOrAccessor.get)\n : getterOrAccessor.get.bind(this)\n : noop\n setter = getterOrAccessor.set ? getterOrAccessor.set.bind(this) : noop\n }\n defineAccessor(target, name, getter, setter)\n}\n\n/**\n * Watch property\n *\n * @param {Object} target\n * @param {String|Function} expressionOrFunction\n * @param {Function} callback\n * @param {Object} [options]\n * - {Boolean} deep\n * - {Boolean} sync\n * - {Boolean} lazy\n * @return {Watcher}\n */\n\nfunction watch (target, expressionOrFunction, callback, options = observe) {\n ensure(target)\n return doWatch(target, expressionOrFunction, callback, options)\n}\n\n/**\n * @param {Object} target\n */\n\nfunction init (target) {\n defineValue(target, WATCHERS_PROPERTY_NAME, [], false)\n defineValue(target, DATA_PROPTERTY_NAME, Object.create(null), false)\n doObserve(target[DATA_PROPTERTY_NAME])\n reactSelfProperties(target)\n}\n\nfunction ensure (target) {\n if (!Object.prototype.hasOwnProperty.call(target, WATCHERS_PROPERTY_NAME)) {\n init(target)\n }\n}\n\n/**\n * @param {Object} target\n * @param {Object} methods\n */\n\nfunction carryMethods (target, methods) {\n everyEntries(methods, (name, method) => {\n target[name] = method.bind(target)\n })\n}\n\n/**\n * @param {Object} target\n * @param {String} key\n * @param {*} value\n */\n\nfunction reactProperty (target, key, value) {\n target[DATA_PROPTERTY_NAME][key] = value\n defineReactive(target[DATA_PROPTERTY_NAME], key, value)\n proxy(target, key)\n}\n\n/**\n * @param {Object} target\n * @param {Object} properties\n */\n\nfunction reactProperties (target, properties) {\n everyEntries(properties, (key, value) => reactProperty(target, key, value))\n}\n\n/**\n * @param {Object} target\n */\n\nfunction reactSelfProperties (target) {\n everyEntries(target, (key, value) => {\n !isFunction(value) && reactProperty(target, key, value)\n })\n}\n\n/**\n * @param {Object} target\n * @param {Object} properties\n */\n\nfunction computeProperties (target, properties) {\n everyEntries(properties, (key, value) => compute(target, key, value))\n}\n\n/**\n * @param {Object} target\n * @param {Object} properties\n */\n\nfunction watchProperties (target, properties) {\n everyEntries(properties, (expression, functionOrOption) => {\n if (isFunction(functionOrOption)) {\n watch(target, expression, functionOrOption)\n } else {\n watch(target, expression, functionOrOption.watcher, functionOrOption)\n }\n })\n}\n\n/**\n * @param {Object} target\n * @param {String} key\n */\n\nfunction proxy (target, key) {\n function getter () {\n return target[DATA_PROPTERTY_NAME][key]\n }\n function setter (value) {\n target[DATA_PROPTERTY_NAME][key] = value\n }\n defineAccessor(target, key, getter, setter)\n}\n","let uid = 0\n\n/**\n * A dep is an observable that can have multiple\n * watcher subscribing to it.\n */\n\nexport default class Dep {\n // the current target watcher being evaluated.\n // this is globally unique because there could be only one\n // watcher being evaluated at any time.\n static target = null\n\n constructor () {\n this.id = uid++\n this.subs = []\n }\n\n /**\n * Add a subscriber.\n *\n * @param {Watcher} sub\n */\n\n addSub (sub) {\n this.subs.push(sub)\n }\n\n /**\n * Remove a subscriber.\n *\n * @param {Watcher} sub\n */\n\n removeSub (sub) {\n this.subs.$remove(sub)\n }\n\n /**\n * Add self as a dependency to the target watcher.\n */\n\n depend () {\n Dep.target.addDep(this)\n }\n\n /**\n * Notify all subscribers of a new value.\n */\n\n notify () {\n const subs = this.subs\n for (let i = 0, l = subs.length; i < l; i++) {\n subs[i].update()\n }\n }\n}\n","export const OBSERVE_NAME = '__s_o__'\nexport const WATCHERS_PROPERTY_NAME = '__watchers__'\nexport const DATA_PROPTERTY_NAME = '__data__'\n\nexport const DEBUGGING = typeof process !== 'undefined'\n && process.env.NODE_ENV !== 'production'\n"],"names":["defineValue","object","property","value","enumerable","defineProperty","defineAccessor","getter","setter","isPlainObject","toString","call","OBJECT_STRING","isObject","isFunction","func","everyEntries","callback","keys","Object","i","l","length","noop","amend","array","setPrototypeOf","arrayMethods","$set","index","this","Number","splice","$remove","item","indexOf","observe","observer","prototype","hasOwnProperty","OBSERVE_NAME","Observer","isArray","isExtensible","defineReactive","key","reactiveGetter","currentValue","Dep","target","depend","childOb","dep","e","reactiveSetter","newValue","oldValue","notify","desc","getOwnPropertyDescriptor","configurable","get","set","makeGetterFunction","body","Function","parse","expression","String","trim","nextTickHandler","callbackCopies","callbacks","slice","resetBatcherState","flushBatcherQueue","queue","runBatcherQueue","queueIndex","watcher","id","run","batch","has","push","waiting","traverse","watch","owner","expressionOrFunction","options","parseExpression","Watcher","makeComputed","deep","sync","lazy","deps","dirty","evaluate","default","react","methods","carryMethods","data","reactProperties","computed","computeProperties","watchers","watchProperties","compute","name","getterOrAccessor","cache","bind","doWatch","init","WATCHERS_PROPERTY_NAME","DATA_PROPTERTY_NAME","create","ensure","method","reactProperty","properties","reactSelfProperties","functionOrOption","proxy","uid","subs","sub","addDep","update","DEBUGGING","process","env","NODE_ENV","Array","warn","console","_Set","Set","match","undefined","add","clear","arrayPrototype","arrayMutativeMethods","original","args","result","apply","inserted","observeArray","callNextTick","walk","_this","convert","items","pending","nextTick","MutationObserver","counter","textNode","document","createTextNode","setTimeout","context","arguments","unshift","active","newDeps","depIds","newDepIds","beforeGet","scope","afterGet","addSub","removeSub","tmp","current","defineProperties","writable"],"mappings":"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"}
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "smart-observe",
3 | "version": "1.0.4",
4 | "description": "smart-observe comes from Vue.js and is a small, efficient library for observing changes of javascript Object, Array and Class.",
5 | "main": "dist/smart-observe.js",
6 | "scripts": {
7 | "test": "mocha",
8 | "lint": "eslint src",
9 | "clean": "rm -rf dist/*",
10 | "rollup": "rollup --config --environment NODE_ENV:production --sourcemap",
11 | "prebuild": "npm run lint && npm run clean",
12 | "build": "npm run rollup && MIN=min npm run rollup",
13 | "postbuild": "npm run test"
14 | },
15 | "dependencies": {
16 | "smart-next-tick": "^1.1.0"
17 | },
18 | "devDependencies": {
19 | "babel-core": "^6.26.0",
20 | "babel-eslint": "^8.0.1",
21 | "babel-plugin-external-helpers": "^6.22.0",
22 | "babel-plugin-transform-class-properties": "^6.24.1",
23 | "babel-preset-env": "^1.6.1",
24 | "babel-preset-stage-0": "^6.24.1",
25 | "chai": "^4.1.2",
26 | "eslint": "^4.10.0",
27 | "eslint-config-standard": "^10.2.1",
28 | "eslint-plugin-import": "^2.8.0",
29 | "eslint-plugin-node": "^5.2.1",
30 | "eslint-plugin-promise": "^3.6.0",
31 | "eslint-plugin-standard": "^3.0.1",
32 | "mocha": "^4.0.1",
33 | "rollup": "^0.50.0",
34 | "rollup-plugin-babel": "^3.0.2",
35 | "rollup-plugin-commonjs": "^8.2.6",
36 | "rollup-plugin-node-resolve": "^3.0.0",
37 | "rollup-plugin-uglify": "^2.0.1"
38 | },
39 | "keywords": [
40 | "observe",
41 | "observer",
42 | "watch",
43 | "watcher",
44 | "computed",
45 | "vue",
46 | "vue.js",
47 | "ob.js",
48 | "ob"
49 | ],
50 | "repository": {
51 | "type": "git",
52 | "url": "git+https://github.com/cnlon/smart-observe.git"
53 | },
54 | "bugs": {
55 | "url": "https://github.com/cnlon/smart-observe/issues"
56 | },
57 | "homepage": "https://github.com/cnlon/smart-observe#readme",
58 | "author": "lon (http://lon.im)",
59 | "license": "MIT"
60 | }
61 |
--------------------------------------------------------------------------------
/rollup.config.js:
--------------------------------------------------------------------------------
1 | import resolve from 'rollup-plugin-node-resolve'
2 | import babel from 'rollup-plugin-babel'
3 | import uglify from 'rollup-plugin-uglify'
4 |
5 | const needMin = !!process.env.MIN
6 | let file = 'dist/smart-observe.js'
7 | const plugins = [
8 | resolve({
9 | jsnext: true,
10 | browser: true,
11 | }),
12 | babel({
13 | presets: [
14 | ['env', {
15 | targets: {
16 | browsers: ['last 3 versions', 'IE >= 9'],
17 | node: '4'
18 | },
19 | modules: false
20 | }]
21 | ],
22 | plugins: [
23 | 'transform-class-properties',
24 | 'external-helpers'
25 | ],
26 | })
27 | ]
28 | if (needMin) {
29 | file = 'dist/smart-observe.min.js'
30 | plugins.push(uglify())
31 | }
32 |
33 | export default {
34 | input: 'src/index.js',
35 | output: {
36 | file,
37 | format: 'umd',
38 | name: 'observe',
39 | banner:
40 | `/**
41 | * smart-observe --- By lon
42 | * https://github.com/cnlon/smart-observe
43 | */`,
44 | },
45 | plugins,
46 | }
47 |
--------------------------------------------------------------------------------
/src/array.js:
--------------------------------------------------------------------------------
1 | import {defineValue} from './util'
2 | import {OBSERVE_NAME} from './constants'
3 |
4 | const arrayPrototype = Array.prototype
5 | const arrayMethods = Object.create(arrayPrototype)
6 | const arrayMutativeMethods = [
7 | 'push',
8 | 'pop',
9 | 'shift',
10 | 'unshift',
11 | 'splice',
12 | 'sort',
13 | 'reverse',
14 | ]
15 |
16 | /**
17 | * Augment an target Array with arrayMethods
18 | *
19 | * @param {Array} array
20 | */
21 |
22 | export default function amend (array) {
23 | Object.setPrototypeOf(array, arrayMethods)
24 | }
25 |
26 | /**
27 | * Intercept mutating methods and emit events
28 | */
29 |
30 | for (let i = 0, l = arrayMutativeMethods.length; i < l; i++) {
31 | const method = arrayMutativeMethods[i]
32 | // cache original method
33 | const original = arrayPrototype[method]
34 | defineValue(arrayMethods, method, function mutator (...args) {
35 | const result = original.apply(this, args)
36 | const observer = this[OBSERVE_NAME]
37 | let inserted
38 | switch (method) {
39 | case 'push':
40 | inserted = args
41 | break
42 | case 'unshift':
43 | inserted = args
44 | break
45 | case 'splice':
46 | inserted = args.slice(2)
47 | break
48 | }
49 | if (inserted) observer.observeArray(inserted)
50 | observer.dep.notify() // notify change
51 | return result
52 | })
53 | }
54 |
55 | /**
56 | * Swap the element at the given index with a new value
57 | * and emits corresponding event.
58 | *
59 | * @param {number} index
60 | * @param {*} value
61 | * @return {*} - replaced element
62 | */
63 |
64 | function $set (index, value) {
65 | if (index >= this.length) {
66 | this.length = Number(index) + 1
67 | }
68 | return this.splice(index, 1, value)[0]
69 | }
70 | defineValue(arrayPrototype, '$set', $set)
71 |
72 | /**
73 | * Convenience method to remove the element at given index
74 | * or target element reference.
75 | *
76 | * @param {*} item
77 | * @return {*} - removed element
78 | */
79 |
80 | function $remove (item) {
81 | if (!this.length) return
82 | const index = this.indexOf(item)
83 | if (index > -1) {
84 | return this.splice(index, 1)
85 | }
86 | }
87 | defineValue(arrayPrototype, '$remove', $remove)
88 |
--------------------------------------------------------------------------------
/src/batcher.js:
--------------------------------------------------------------------------------
1 | import nextTick from 'smart-next-tick'
2 |
3 | let queue = []
4 | let has = {}
5 | let waiting = false
6 | let queueIndex
7 |
8 | /**
9 | * Reset the batcher's state.
10 | */
11 |
12 | function resetBatcherState () {
13 | queue = []
14 | has = {}
15 | waiting = false
16 | }
17 |
18 | /**
19 | * Flush queue and run the watchers.
20 | */
21 |
22 | function flushBatcherQueue () {
23 | runBatcherQueue(queue)
24 | resetBatcherState()
25 | }
26 |
27 | /**
28 | * Run the watchers in a single queue.
29 | *
30 | * @param {Array} queue
31 | */
32 |
33 | function runBatcherQueue (queue) {
34 | // do not cache length because more watchers might be pushed
35 | // as we run existing watchers
36 | for (queueIndex = 0; queueIndex < queue.length; queueIndex++) {
37 | const watcher = queue[queueIndex]
38 | const id = watcher.id
39 | has[id] = null
40 | watcher.run()
41 | }
42 | }
43 |
44 | /**
45 | * Push a watcher into the watcher queue.
46 | * Jobs with duplicate IDs will be skipped unless it's
47 | * pushed when the queue is being flushed.
48 | *
49 | * @param {Watcher} watcher
50 | * properties:
51 | * - {number} id
52 | * - {function} run
53 | */
54 |
55 | export default function batch (watcher) {
56 | const id = watcher.id
57 | if (has[id] == null) {
58 | has[id] = queue.length
59 | queue.push(watcher)
60 | // queue the flush
61 | if (!waiting) {
62 | waiting = true
63 | nextTick(flushBatcherQueue)
64 | }
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/src/constants.js:
--------------------------------------------------------------------------------
1 | export const OBSERVE_NAME = '__s_o__'
2 | export const WATCHERS_PROPERTY_NAME = '__watchers__'
3 | export const DATA_PROPTERTY_NAME = '__data__'
4 |
5 | export const DEBUGGING = typeof process !== 'undefined'
6 | && process.env.NODE_ENV !== 'production'
7 |
--------------------------------------------------------------------------------
/src/dep.js:
--------------------------------------------------------------------------------
1 | let uid = 0
2 |
3 | /**
4 | * A dep is an observable that can have multiple
5 | * watcher subscribing to it.
6 | */
7 |
8 | export default class Dep {
9 | // the current target watcher being evaluated.
10 | // this is globally unique because there could be only one
11 | // watcher being evaluated at any time.
12 | static target = null
13 |
14 | constructor () {
15 | this.id = uid++
16 | this.subs = []
17 | }
18 |
19 | /**
20 | * Add a subscriber.
21 | *
22 | * @param {Watcher} sub
23 | */
24 |
25 | addSub (sub) {
26 | this.subs.push(sub)
27 | }
28 |
29 | /**
30 | * Remove a subscriber.
31 | *
32 | * @param {Watcher} sub
33 | */
34 |
35 | removeSub (sub) {
36 | this.subs.$remove(sub)
37 | }
38 |
39 | /**
40 | * Add self as a dependency to the target watcher.
41 | */
42 |
43 | depend () {
44 | Dep.target.addDep(this)
45 | }
46 |
47 | /**
48 | * Notify all subscribers of a new value.
49 | */
50 |
51 | notify () {
52 | const subs = this.subs
53 | for (let i = 0, l = subs.length; i < l; i++) {
54 | subs[i].update()
55 | }
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/src/expression.js:
--------------------------------------------------------------------------------
1 | import {warn} from './util'
2 |
3 | /**
4 | * Build a getter function. Requires eval.
5 | *
6 | * We isolate the try/catch so it doesn't affect the
7 | * optimization of the parse function when it is not called.
8 | *
9 | * @param {string} body
10 | * @return {function|undefined}
11 | */
12 |
13 | function makeGetterFunction (body) {
14 | try {
15 | /* eslint-disable no-new-func */
16 | return new Function('scope', `return ${body};`)
17 | /* eslint-enable no-new-func */
18 | } catch (e) {
19 | warn('Invalid expression. Generated function body: ' + body)
20 | }
21 | }
22 |
23 | /**
24 | * Parse an expression to getter.
25 | *
26 | * @param {string} expression
27 | * @return {function|undefined}
28 | */
29 |
30 | export default function parse (expression) {
31 | expression = String.prototype.trim.call(expression)
32 | return makeGetterFunction('scope.' + expression)
33 | }
34 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | import {
2 | observe as doObserve,
3 | defineReactive,
4 | } from './observe'
5 | import {
6 | watch as doWatch,
7 | makeComputed,
8 | } from './watcher'
9 | import {
10 | defineValue,
11 | defineAccessor,
12 | noop,
13 | isFunction,
14 | everyEntries,
15 | } from './util'
16 | import {
17 | WATCHERS_PROPERTY_NAME,
18 | DATA_PROPTERTY_NAME,
19 | } from './constants'
20 |
21 | Object.defineProperties(observe, {
22 | 'react': {value: react},
23 | 'compute': {value: compute},
24 | 'watch': {value: watch},
25 | 'default': {value: watch, writable: true}, // Only could be react, compute or watch
26 | 'deep': {value: false, writable: true},
27 | 'lazy': {value: false, writable: true},
28 | 'sync': {value: false, writable: true},
29 | })
30 |
31 | /**
32 | * observe
33 | *
34 | * @public
35 | * @param {Object} target
36 | * @param {*} [expression]
37 | * @param {*} [func]
38 | * @param {*} [options]
39 | * @return {function} observe
40 | */
41 |
42 | export default function observe (target, expression, func, options) {
43 | ensure(target)
44 | return observe.default(target, expression, func, options)
45 | }
46 |
47 | /**
48 | * React options
49 | *
50 | * @param {Object} options
51 | * @param {Object} [target]
52 | * @return {function} observe
53 | */
54 |
55 | function react (options, target) {
56 | if (target) {
57 | ensure(target)
58 | } else {
59 | target = {}
60 | init(target)
61 | }
62 | options.methods && carryMethods(target, options.methods)
63 | options.data && reactProperties(target, options.data)
64 | options.computed && computeProperties(target, options.computed)
65 | options.watchers && watchProperties(target, options.watchers)
66 | return target
67 | }
68 |
69 | /**
70 | * Compute property
71 | *
72 | * @param {Object} target
73 | * @param {string} name
74 | * @param {function|Object} getterOrAccessor
75 | * - function getter
76 | * - Object accessor
77 | * - function [get] - getter
78 | * - function [set] - setter
79 | * - boolean [cache]
80 | * @param {boolean} [cache]
81 | */
82 |
83 | function compute (target, name, getterOrAccessor, cache) {
84 | ensure(target)
85 | let getter, setter
86 | if (isFunction(getterOrAccessor)) {
87 | getter = cache !== false
88 | ? makeComputed(target, getterOrAccessor)
89 | : getterOrAccessor.bind(this)
90 | setter = noop
91 | } else {
92 | getter = getterOrAccessor.get
93 | ? getterOrAccessor.cache !== false || cache !== false
94 | ? makeComputed(target, getterOrAccessor.get)
95 | : getterOrAccessor.get.bind(this)
96 | : noop
97 | setter = getterOrAccessor.set ? getterOrAccessor.set.bind(this) : noop
98 | }
99 | defineAccessor(target, name, getter, setter)
100 | }
101 |
102 | /**
103 | * Watch property
104 | *
105 | * @param {Object} target
106 | * @param {string|function} expressionOrFunction
107 | * @param {function} callback
108 | * @param {Object} [options]
109 | * - {boolean} deep
110 | * - {boolean} sync
111 | * - {boolean} lazy
112 | * @return {Watcher}
113 | */
114 |
115 | function watch (target, expressionOrFunction, callback, options = observe) {
116 | ensure(target)
117 | return doWatch(target, expressionOrFunction, callback, options)
118 | }
119 |
120 | /**
121 | * @param {Object} target
122 | */
123 |
124 | function init (target) {
125 | defineValue(target, WATCHERS_PROPERTY_NAME, [], false)
126 | defineValue(target, DATA_PROPTERTY_NAME, Object.create(null), false)
127 | doObserve(target[DATA_PROPTERTY_NAME])
128 | reactSelfProperties(target)
129 | }
130 |
131 | function ensure (target) {
132 | if (!Object.prototype.hasOwnProperty.call(target, WATCHERS_PROPERTY_NAME)) {
133 | init(target)
134 | }
135 | }
136 |
137 | /**
138 | * @param {Object} target
139 | * @param {Object} methods
140 | */
141 |
142 | function carryMethods (target, methods) {
143 | everyEntries(methods, (name, method) => {
144 | target[name] = method.bind(target)
145 | })
146 | }
147 |
148 | /**
149 | * @param {Object} target
150 | * @param {string} key
151 | * @param {*} value
152 | */
153 |
154 | function reactProperty (target, key, value) {
155 | target[DATA_PROPTERTY_NAME][key] = value
156 | defineReactive(target[DATA_PROPTERTY_NAME], key, value)
157 | proxy(target, key)
158 | }
159 |
160 | /**
161 | * @param {Object} target
162 | * @param {Object} properties
163 | */
164 |
165 | function reactProperties (target, properties) {
166 | everyEntries(properties, (key, value) => reactProperty(target, key, value))
167 | }
168 |
169 | /**
170 | * @param {Object} target
171 | */
172 |
173 | function reactSelfProperties (target) {
174 | everyEntries(target, (key, value) => {
175 | !isFunction(value) && reactProperty(target, key, value)
176 | })
177 | }
178 |
179 | /**
180 | * @param {Object} target
181 | * @param {Object} properties
182 | */
183 |
184 | function computeProperties (target, properties) {
185 | everyEntries(properties, (key, value) => compute(target, key, value))
186 | }
187 |
188 | /**
189 | * @param {Object} target
190 | * @param {Object} properties
191 | */
192 |
193 | function watchProperties (target, properties) {
194 | everyEntries(properties, (expression, functionOrOption) => {
195 | if (isFunction(functionOrOption)) {
196 | watch(target, expression, functionOrOption)
197 | } else {
198 | watch(target, expression, functionOrOption.watcher, functionOrOption)
199 | }
200 | })
201 | }
202 |
203 | /**
204 | * @param {Object} target
205 | * @param {string} key
206 | */
207 |
208 | function proxy (target, key) {
209 | function getter () {
210 | return target[DATA_PROPTERTY_NAME][key]
211 | }
212 | function setter (value) {
213 | target[DATA_PROPTERTY_NAME][key] = value
214 | }
215 | defineAccessor(target, key, getter, setter)
216 | }
217 |
--------------------------------------------------------------------------------
/src/observe.js:
--------------------------------------------------------------------------------
1 | import Dep from './dep'
2 | import amendArray from './array'
3 | import {
4 | defineValue,
5 | defineAccessor,
6 | isArray,
7 | isPlainObject,
8 | everyEntries,
9 | } from './util'
10 | import {OBSERVE_NAME} from './constants'
11 |
12 | /**
13 | * Observer class that are attached to each observed
14 | * object. Once attached, the observer converts target
15 | * object's property keys into getter/setters that
16 | * collect dependencies and dispatches updates.
17 | *
18 | * @class
19 | * @param {Array|Object} value
20 | */
21 |
22 | class Observer {
23 | constructor (value) {
24 | this.value = value
25 | this.dep = new Dep()
26 | defineValue(value, OBSERVE_NAME, this)
27 | if (isArray(value)) {
28 | amendArray(value)
29 | this.observeArray(value)
30 | } else {
31 | this.walk(value)
32 | }
33 | }
34 |
35 | /**
36 | * Walk through each property and convert them into
37 | * getter/setters. This method should only be called when
38 | * value type is Object.
39 | *
40 | * @param {Object} object
41 | */
42 |
43 | walk (object) {
44 | everyEntries(object, (key, value) => this.convert(key, value))
45 | }
46 |
47 | /**
48 | * Observe a list of Array items.
49 | *
50 | * @param {Array} items
51 | */
52 |
53 | observeArray (items) {
54 | for (let i = 0, l = items.length; i < l; i++) {
55 | observe(items[i])
56 | }
57 | }
58 |
59 | /**
60 | * Convert a property into getter/setter so we can emit
61 | * the events when the property is accessed/changed.
62 | *
63 | * @param {string} key
64 | * @param {*} value
65 | */
66 |
67 | convert (key, value) {
68 | defineReactive(this.value, key, value)
69 | }
70 | }
71 |
72 | /**
73 | * Attempt to create an observer instance for a value,
74 | * returns the new observer if successfully observed,
75 | * or the existing observer if the value already has one.
76 | *
77 | * @param {*} value
78 | * @return {Observer|undefined}
79 | */
80 |
81 | export function observe (value) {
82 | if (!value || typeof value !== 'object') return
83 | let observer
84 | if (
85 | Object.prototype.hasOwnProperty.call(value, OBSERVE_NAME)
86 | && value[OBSERVE_NAME] instanceof Observer
87 | ) {
88 | observer = value[OBSERVE_NAME]
89 | } else if (
90 | (isArray(value) || isPlainObject(value))
91 | && Object.isExtensible(value)
92 | ) {
93 | observer = new Observer(value)
94 | }
95 | return observer
96 | }
97 |
98 | /**
99 | * Define a reactive property on an Object.
100 | *
101 | * @param {Object} object
102 | * @param {string} key
103 | * @param {*} value
104 | */
105 |
106 | export function defineReactive (object, key, value) {
107 | const dep = new Dep()
108 |
109 | const desc = Object.getOwnPropertyDescriptor(object, key)
110 | if (desc && desc.configurable === false) return
111 |
112 | // cater for pre-defined getter/setters
113 | const getter = desc && desc.get
114 | const setter = desc && desc.set
115 |
116 | let childOb = observe(value)
117 |
118 | function reactiveGetter () {
119 | const currentValue = getter ? getter.call(object) : value
120 | if (Dep.target) {
121 | dep.depend()
122 | if (childOb) {
123 | childOb.dep.depend()
124 | }
125 | if (isArray(currentValue)) {
126 | for (let i = 0, l = currentValue.length, e; i < l; i++) {
127 | e = currentValue[i]
128 | e && e[OBSERVE_NAME] && e[OBSERVE_NAME].dep.depend()
129 | }
130 | }
131 | }
132 | return currentValue
133 | }
134 | function reactiveSetter (newValue) {
135 | const oldValue = getter ? getter.call(object) : value
136 | if (newValue === oldValue) return
137 | if (setter) {
138 | setter.call(object, newValue)
139 | } else {
140 | value = newValue
141 | }
142 | childOb = observe(newValue)
143 | dep.notify()
144 | }
145 | defineAccessor(object, key, reactiveGetter, reactiveSetter)
146 | }
147 |
--------------------------------------------------------------------------------
/src/util.js:
--------------------------------------------------------------------------------
1 | import {DEBUGGING} from './constants'
2 |
3 | /**
4 | * Define property with value.
5 | *
6 | * @param {Object} object
7 | * @param {string} property
8 | * @param {*} value
9 | * @param {boolean} [enumerable]
10 | */
11 |
12 | export function defineValue (object, property, value, enumerable) {
13 | Object.defineProperty(object, property, {
14 | value,
15 | enumerable: !!enumerable,
16 | writable: true,
17 | configurable: true,
18 | })
19 | }
20 |
21 | /**
22 | * Define property with getter and setter.
23 | *
24 | * @param {Object} object
25 | * @param {string} property
26 | * @param {function} getter
27 | * @param {function} setter
28 | */
29 |
30 | export function defineAccessor (object, property, getter, setter) {
31 | Object.defineProperty(object, property, {
32 | get: getter,
33 | set: setter,
34 | enumerable: true,
35 | configurable: true,
36 | })
37 | }
38 |
39 | /**
40 | * Array type check.
41 | *
42 | * @return {boolean}
43 | */
44 |
45 | export const isArray = Array.isArray
46 |
47 | /**
48 | * Strict object type check. Only returns true
49 | * for plain JavaScript objects.
50 | *
51 | * @param {*} Object
52 | * @return {boolean}
53 | */
54 |
55 | const toString = Object.prototype.toString
56 | const OBJECT_STRING = '[object Object]'
57 | export function isPlainObject (object) {
58 | return toString.call(object) === OBJECT_STRING
59 | }
60 |
61 | /**
62 | * Quick object check - this is primarily used to tell
63 | * Objects from primitive values when we know the value
64 | * is a JSON-compliant type.
65 | *
66 | * @param {*} object
67 | * @return {boolean}
68 | */
69 |
70 | export function isObject (object) {
71 | return object !== null && typeof object === 'object'
72 | }
73 |
74 | /**
75 | * Function type check
76 | *
77 | * @param {*} func
78 | * @param {boolean}
79 | */
80 |
81 | export function isFunction (func) {
82 | return typeof func === 'function'
83 | }
84 |
85 | /**
86 | * Iterate object
87 | *
88 | * @param {Object} object
89 | * @param {function} callback
90 | */
91 |
92 | export function everyEntries (object, callback) {
93 | const keys = Object.keys(object)
94 | for (let i = 0, l = keys.length; i < l; i++) {
95 | callback(keys[i], object[keys[i]])
96 | }
97 | }
98 |
99 | /**
100 | * noop is function which is nothing to do.
101 | */
102 |
103 | export function noop () {}
104 |
105 | /**
106 | * @param {string} string
107 | */
108 |
109 | export const warn = typeof DEBUGGING !== 'undefined'
110 | && DEBUGGING
111 | && typeof console !== 'undefined'
112 | && console
113 | && isFunction(console.warn)
114 | ? console.warn
115 | : noop
116 |
117 | export let _Set
118 | if (typeof Set !== 'undefined' && Set.toString().match(/native code/)) {
119 | // use native Set when available.
120 | _Set = Set
121 | } else {
122 | // a non-standard Set polyfill that only works with primitive keys.
123 | _Set = function () {
124 | this.set = Object.create(null)
125 | }
126 | _Set.prototype.has = function (key) {
127 | return this.set[key] !== undefined
128 | }
129 | _Set.prototype.add = function (key) {
130 | this.set[key] = 1
131 | }
132 | _Set.prototype.clear = function () {
133 | this.set = Object.create(null)
134 | }
135 | }
136 |
--------------------------------------------------------------------------------
/src/watcher.js:
--------------------------------------------------------------------------------
1 | import observe from './index'
2 | import Dep from './dep'
3 | import parseExpression from './expression'
4 | import batch from './batcher'
5 | import {
6 | isArray,
7 | isObject,
8 | isFunction,
9 | _Set as Set,
10 | } from './util'
11 | import {WATCHERS_PROPERTY_NAME} from './constants'
12 |
13 | let uid = 0
14 |
15 | class Watcher {
16 | /**
17 | * A watcher parses an expression, collects dependencies,
18 | * and fires callback when the expression value changes.
19 | *
20 | * @param {Object} owner
21 | * @param {string|function} getter
22 | * @param {function} callback
23 | * @param {Object} options
24 | * - {boolean} deep
25 | * - {boolean} sync
26 | * - {boolean} lazy
27 | * @constructor
28 | */
29 |
30 | constructor (owner, getter, callback, options) {
31 | owner[WATCHERS_PROPERTY_NAME].push(this)
32 | this.owner = owner
33 | this.getter = getter
34 | this.callback = callback
35 | this.options = options
36 | // uid for batching
37 | this.id = ++uid
38 | this.active = true
39 | // for lazy watchers
40 | this.dirty = options.lazy
41 | this.deps = []
42 | this.newDeps = []
43 | this.depIds = new Set()
44 | this.newDepIds = new Set()
45 | this.value = options.lazy
46 | ? undefined
47 | : this.get()
48 | }
49 |
50 | /**
51 | * Evaluate the getter, and re-collect dependencies.
52 | */
53 |
54 | get () {
55 | this.beforeGet()
56 | const scope = this.owner
57 | const value = this.getter.call(scope, scope)
58 | if (this.options.deep) {
59 | traverse(value)
60 | }
61 | this.afterGet()
62 | return value
63 | }
64 |
65 | /**
66 | * Prepare for dependency collection.
67 | */
68 |
69 | beforeGet () {
70 | Dep.target = this
71 | }
72 |
73 | /**
74 | * Add a dependency to this directive.
75 | *
76 | * @param {Dep} dep
77 | */
78 |
79 | addDep (dep) {
80 | const id = dep.id
81 | if (!this.newDepIds.has(id)) {
82 | this.newDepIds.add(id)
83 | this.newDeps.push(dep)
84 | if (!this.depIds.has(id)) {
85 | dep.addSub(this)
86 | }
87 | }
88 | }
89 |
90 | /**
91 | * Clean up for dependency collection.
92 | */
93 |
94 | afterGet () {
95 | Dep.target = null
96 | let i = this.deps.length
97 | while (i--) {
98 | const dep = this.deps[i]
99 | if (!this.newDepIds.has(dep.id)) {
100 | dep.removeSub(this)
101 | }
102 | }
103 | let tmp = this.depIds
104 | this.depIds = this.newDepIds
105 | this.newDepIds = tmp
106 | this.newDepIds.clear()
107 | tmp = this.deps
108 | this.deps = this.newDeps
109 | this.newDeps = tmp
110 | this.newDeps.length = 0
111 | }
112 |
113 | /**
114 | * Will be called when a dependency changes.
115 | */
116 |
117 | update () {
118 | if (this.options.lazy) {
119 | this.dirty = true
120 | } else if (this.options.sync) {
121 | this.run()
122 | } else {
123 | batch(this)
124 | }
125 | }
126 |
127 | /**
128 | * Will be called by the batcher.
129 | */
130 |
131 | run () {
132 | if (this.active) {
133 | const value = this.get()
134 | if (
135 | value !== this.value
136 | // Deep watchers and watchers on Object/Arrays should fire even when
137 | // the value is the same, because the value may have mutated;
138 | || ((isObject(value) || this.options.deep))
139 | ) {
140 | const oldValue = this.value
141 | this.value = value
142 | this.callback.call(this.owner, value, oldValue)
143 | }
144 | }
145 | }
146 |
147 | /**
148 | * Evaluate the value of the watcher.
149 | * This only gets called for lazy watchers.
150 | */
151 |
152 | evaluate () {
153 | // avoid overwriting another watcher that is being collected.
154 | const current = Dep.target
155 | this.value = this.get()
156 | this.dirty = false
157 | Dep.target = current
158 | }
159 |
160 | /**
161 | * Depend on all deps collected by this watcher.
162 | */
163 |
164 | depend () {
165 | let i = this.deps.length
166 | while (i--) {
167 | this.deps[i].depend()
168 | }
169 | }
170 |
171 | /**
172 | * Remove self from all dependencies' subcriber list.
173 | */
174 |
175 | teardown () {
176 | if (this.active) {
177 | let i = this.deps.length
178 | while (i--) {
179 | this.deps[i].removeSub(this)
180 | }
181 | this.active = false
182 | this.owner = this.callback = this.value = null
183 | }
184 | }
185 | }
186 |
187 | /**
188 | * Recrusively traverse an Object to evoke all converted
189 | * getters, so that every nested property inside the Object
190 | * is collected as a "deep" dependency.
191 | *
192 | * @param {*} value
193 | */
194 |
195 | function traverse (value) {
196 | let i, keys
197 | if (isArray(value)) {
198 | i = value.length
199 | while (i--) traverse(value[i])
200 | } else if (isObject(value)) {
201 | keys = Object.keys(value)
202 | i = keys.length
203 | while (i--) traverse(value[keys[i]])
204 | }
205 | }
206 |
207 | /**
208 | * Create an watcher instance, returns the new watcher.
209 | *
210 | * @param {Object} owner
211 | * @param {string|function} expressionOrFunction
212 | * @param {function} callback
213 | * @param {Object} options
214 | * - {boolean} deep
215 | * - {boolean} sync
216 | * - {boolean} lazy
217 | * @return {Watcher}
218 | */
219 |
220 | export function watch (owner, expressionOrFunction, callback, options) {
221 | // parse expression for getter
222 | const getter = isFunction(expressionOrFunction)
223 | ? expressionOrFunction
224 | : parseExpression(expressionOrFunction)
225 | return new Watcher(owner, getter, callback, options)
226 | }
227 |
228 | /**
229 | * Make a computed getter, which can collect dependencies.
230 | *
231 | * @param {Object} owner
232 | * @param {function} getter
233 | */
234 |
235 | export function makeComputed (owner, getter) {
236 | const watcher = new Watcher(owner, getter, null, {
237 | deep: observe.deep,
238 | lazy: true,
239 | sync: observe.sync,
240 | })
241 | return function computedGetter () {
242 | if (watcher.options.lazy && Dep.target && !Dep.target.options.lazy) {
243 | watcher.options.lazy = false
244 | watcher.callback = function () {
245 | const deps = watcher.deps
246 | for (let i = 0, l = deps.length; i < l; i++) {
247 | deps[i].notify()
248 | }
249 | }
250 | }
251 | if (watcher.dirty) {
252 | watcher.evaluate()
253 | }
254 | if (Dep.target) {
255 | watcher.depend()
256 | }
257 | return watcher.value
258 | }
259 | }
260 |
--------------------------------------------------------------------------------
/test/test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const assert = require('chai').assert
4 | const observe = require('../dist/smart-observe.js')
5 |
6 | const equal = assert.equal
7 |
8 | /* global describe, it */
9 | describe('smart-observe', function () {
10 | describe('#watch()', function () {
11 | const target = {a: 1, b: []}
12 | it('target.a\'s old value should equal 1, new value should equal 3, "this" should bound to target', done => {
13 | observe(target, 'a', function (newValue, oldValue) {
14 | equal(newValue, 3)
15 | equal(oldValue, 1)
16 | equal(newValue, this.a)
17 | done()
18 | })
19 | target.a = 3
20 | })
21 | it('target.b\'s new value should equal [1], "this" should bound to target', done => {
22 | observe(target, 'b', function (newValue) {
23 | equal(JSON.stringify(newValue), '[1]')
24 | equal(newValue, this.b)
25 | done()
26 | })
27 | target.b.push(1)
28 | })
29 | })
30 | describe('#compute()', function () {
31 | class Claz {
32 | constructor () {
33 | this.a = 1
34 | observe.compute(this, 'b', () => this.double(this.a))
35 | }
36 | double (num) {
37 | return num * 2
38 | }
39 | }
40 | const target = new Claz()
41 | target.a = 3
42 | it('target.b should equal 6', function (done) {
43 | equal(target.b, 6)
44 | done()
45 | })
46 | })
47 | describe('#react()', function () {
48 | it('area should equal 28.274333882308138', function (done) {
49 | const target = observe.react({
50 | data: {
51 | PI: Math.PI,
52 | radius: 1,
53 | },
54 | computed: {
55 | 'area': function () {
56 | return this.PI * this.square(this.radius)
57 | },
58 | },
59 | watchers: {
60 | 'area': function (newValue, oldValue) {
61 | equal(newValue, 28.274333882308138)
62 | done()
63 | },
64 | },
65 | methods: {
66 | square (num) {
67 | return num * num
68 | },
69 | },
70 | })
71 | target.radius = 3
72 | })
73 | })
74 | })
75 |
--------------------------------------------------------------------------------