The prototype

  • Practical application of the prototype
  • How does the prototype achieve its extensibility

Practical application of the prototype

Simple use of jquery and Zepto

<p>jquery test1</p>
<p>jquery test2</p>
<p>jquery test3</p>

<div id="div1">
    <p>jquery test in div</p>
</div>
Copy the code
 var $p = $("p")
$p.css('font-size'.'40px'// CSS is the prototype method console.log($p.html()) // HTML is the prototype method var$div1 = $("#div1")
$div1.css('color'.'blue'// CSS is the prototype method console.log($div1.html()) // HTML is the prototype methodCopy the code

How does Zepto use prototypes

// Empty object var zepto = {} zepto.init =function(){// in the source code, the processing situation here is more complicated. But because it is the only in view of the prototype, so this will weaken the var slice = Array. The prototype. The dom = slice slice var. Call (document. QuerySelectorAll (selector))returnZepto. Z(dom,selector)} $var $=function(selector){
    return zepto.init(selector)
}
Copy the code
// This is the constructorfunction Z(dom, selector) {
    var i, len = dom ? dom.length : 0
    for (i = 0; i < len; i++) {
        this[i] = dom[i]
    }
    this.length = len
    this.selector = selector || ' '
}  

zepto.Z = function(dom, selector) {
    return new Z(dom, selector)
}
Copy the code
$.fn = {
    constructor:zepto.Z,
    css:function(key,value){},
    html:function(value){}
}

zepto.Z.prototype = Z.prototype = $.fn 
Copy the code

Simple Zepto implementation

MyZepto. Js

(function(window) {
    var zepto = {};

    function Z(dom, selector) {
        var i, len = dom ? dom.length : 0;
        for (i = 0; i < len; i++) {
            this[i] = dom[i];
        }
        this.length = len;
        this.selector = selector || ' ';
    }

    zepto.Z = function(dom, selector) {
        return new Z(dom, selector);
    }

    zepto.init = function(selector) {
        var slice = Array.prototype.slice;
        var dom = slice.call(document.querySelectorAll(selector));
        return zepto.Z(dom, selector);
    }

    var $ = function(selector) {
        return zepto.init(selector);
    }

    window.$ = $;

    $.fn = {
        css: function(key, value) {
            console.log(key, value);
        },
        html: function() {
            return "html";
        }
    }

    Z.prototype = $.fn

})(window)
Copy the code

How does jquery use prototypes

var jQuery = function(selector){// Notice the new keyword, the constructor is found in the first stepreturnnew jQuery.fn.init(selector); } // Define the constructor var init = jquery.fn.init =function(selector){ var slice = Array.prototype.slice; var dom = slice.call(document.querySelectorAll(selector)); var i,len=dom? dom.length:0;for(i = 0; i<len; i++) this[i] = dom[i]; this.length = len; this.selector = selector ||' '; } // constructor = {constructor: jQuery, CSS:function(key, value) {},
    html: function(value) {}} // Define prototype init.prototype = jquery.fnCopy the code

Extensibility of prototypes

How to demonstrate the extensibility of a prototype

  • conclusionzeptoandjqueryUse of prototypes
  • Plug-in mechanism

Why put the prototype on $.fn

init.prototype = jQuery.fn;

zepto.Z.prototype = Z.prototype = $.fn

Because you want to extend plug-ins

// make a simple plugin $.fn.getNodeName =function() {return this[0].nodeName
}
Copy the code

benefits

  • only$Will be exposed to thewindowOn global variables
  • Unify plug-in extensions to$.fn.xxxThis interface is easy to use

asynchronous

What is single threading and what does asynchrony have to do with it

  • Single thread: Only one thread can do one thing at a time. Two JS segments cannot be executed at the same time
  • Reason: Avoid DOM rendering conflicts
  • Solution: Asynchronous

Why js has only one thread: avoid DOM rendering collisions

  • The browser needs to render the DOM
  • JS can modify the DOM structure
  • Browser DOM rendering pauses while JS executes
  • JS cannot be executed at the same time.
  • Webworkers support multithreading, but do not have DOM access

 

What is the event – loop

  • Event polling, JS to achieve asynchronous specific solutions
  • Synchronous code, direct execution (main thread)
  • Asynchronous functions are first placed in asynchronous queues (task queues)
  • After the synchronization function is completed, polling the functions that execute the asynchronous queue
setTimeout(function(){ console.log(1); }, 100); // After 100ms, the asynchronous queue is emptysetTimeout(function(){ console.log(2); }) console.log(3) // After 3, there are only 2 tasks in the asynchronous queue, so there are no tasks in the asynchronous queue, so we poll the asynchronous queue until 1 is put into the asynchronous queue after 100ms. Execute 1 on the main threadCopy the code
$.ajax({
	url:'./data.json',
	success:function(){// If the network request is successful, success will be placed in the asynchronous queue console.log().'a'); }})setTimeout(function(){
	console.log('b')
},100)

setTimeout(function(){
	console.log('c');
})
console.log('d') / / print results: / / / / / / c/d/c d/a/a / / / / / / a/b/b won't appear dacb real environmentCopy the code

Solution problems

  • Problem 1: not in accordance with the written execution, poor readability
  • Problem two: Callback is not easily modularized

Has jQuery Deferred been used

  • The change of jQuery1.5
  • Using jQuery Deferred
  • Introduce the Promise concept initially

 

JQuery1.5 before

var ajax = $.ajax({
	url:'./data.json',
	success:function(){
		console.log('success1');
		console.log('success2');
		console.log('success3');
	},
	error:function(){
		console.log('error'); } }) console.log(ajax); // Return an XHR objectCopy the code

 

After jQuery1.5

The first way:

var ajax = $.ajax('./data.json');
ajax.done(function(){
	console.log('success1')
})
.fai(function(){
	console.log('fail')
})
.done(function(){
	console.log('success2'); }) console.log(ajax); / / deferred objectCopy the code

The second way is:

var ajax = $.ajax('./data.json');
ajax.then(function(){
	console.log('success1')},function(){
	console.log('error1');
})
.then(function(){
	console.log('success2');
},function(){
	console.log('error');
})

Copy the code
  • You can’t change the asynchronous and single threaded nature of JS
  • Callback can only be written to eliminate the form
  • It is a syntactic sugar, but decouples the code
  • Good withdrawal: Open closed principle (open for extensions, closed for modifications)

Using jQuery Deferred

Give a very simple code, using the setTimeout function

var wait = function(){
	var task = function(){
		console.log('Execution completed');
	}
	setTimeout(task,2000)
}

wait(a);Copy the code

New requirement: There may be a lot of code in several steps to perform some particularly complex operations after execution

function waitHandle(){ var dtd = $.Deferred(); // Create a deferred object varwait = function(DTD){// Requires passing in a Deferred object var task =function(){
			console.log("Execution completed"); dtd.resolve(); // Dtd.reject () // Async task failure or error};setTimeout(task,2000);
		returndtd; } // Notice that there is already a return valuereturn wait(dtd); } // use var w = waithandle().function(){
	console.log('ok1');
},function(){
	console.log('err2');
})
.then(function(){
	console.log('ok2');
},function(){
	console.log('err2'); }) // There is also W.wait W.AilCopy the code

Summary: DTD apis fall into two categories, with different intentions

  • The first category:dtd.resolvedtd.reject
  • The second category:dtd.then,dtd.done,dtd.fail
  • These two categories should be separated, otherwise the consequences are serious! It can be executed last in the code abovedtd.reject()Try the consequences

Use a DTD. Promise ()

function waitHandle(){
	var dtd = $.Deferred();
	var wait = function(){
		var task = function(){
			console.log('Execution completed');
			dtd.resolve();
		}
		setTimeout(task,2000)
		returndtd.promise(); // Note that we return a promise instead of a deferred object}return wait(dtd)
}


var w = waitHandle(); / / promise object $. When (w). Then (function(){
	console.log('ok1');
},function(){
	console.log('err1');
})

//w.reject()  //w.reject is not a function
Copy the code

Listener invocation: Passively listens and does not interfere with the success or failure of a promise

  • You can give an example of the changes to ajax in jQuery1.5
  • Explains how to easily encapsulate and use deferred
  • Illustrate the difference between Promise and Defrred

To understand it, you need to know its past lives

Basic use and principles of Promise

The basic grammar

fucntion loadImg() {
    var promise = new Promise(function(resolve,reject) {
        var img = document.getElementById("img")
        img.onload = function(){
            resolve(img)
        }
        img.onerror  = function(){
            reject()
        }
    })
    return promise
}

var src = ""
var result = loadImg(src)
result.then(function() {
    console.log(1, img.width)
    return img
}, fucntion() {
    console.log('error 1')
}).then(function(img) {
    console.log(1, img.width)
})
Copy the code

Exception handling

provisions

  • thenAccept only one function (only one successful callback) and use it allcatchCatch exceptions

There are two anomalies:

  • Program logic exception
  • Within the business,reject(), etc.

The process passes information out in reject(‘ image path error ‘), which can be caught by ‘.catch()’

var src = ""
var result = loadImg(src)
result.then(function() {
    console.log(1, img.width)
    return img
}).then(function(img) {
    console.log(1, img.width)
}).catch(function(ex) {console.log(ex)})Copy the code

Several series

var scr1 = 'https://www.imooc.com/static/img/index/logo_new.png';
var result1 = loadImg(src1);
var src2 = 'https://www.imooc.com/static/img/index/logo_new1.png';
var result2 = loadImg(src2);


result1.then(function(img1) {
    console.log('First image load completed', img1.width);
    returnresult2; / / important}). Then (function(img2) {
    console.log('Second image load completed', img2.width);
}).catch(function(ex) {
    console.log(ex);
})
Copy the code

Promise. All and Promise. Race

  • Promise.allTo receive apromiseArray of objects
  • After all operations are complete, execute them in a unified mannersuccess
Promise.all([result1, result2]).then(datas => {console.log(datas[0]); console.log(datas[0]); console.log(datas[1]); })Copy the code
  • Promise.raceReceive one containing multiplepromiseArray of objects
  • As long as one is done, executesuccess
Promise.race([result1, result2]). Then (data => {//data that is the return value of the first completed Promise console.log(data); })Copy the code

Promise standard

  • state
  • Three states:pending.fulfilled.rejected
    • Initial state:pending
    • pendingintofulfilledOr,pendingintorejected
    • The change in state is irreversible
  • then
    • promiseMust be implementedthenThis method
    • then()Two functions must be accepted as standards
    • thenThe return must be onepromiseThe instance

No return is result returned by default

Promise to summarize

  • The basic grammar
  • How to catch exceptions (Errorandreject)
  • Benefits of multiple series-chain executions
  • Promise.allandPromise.race
  • PromiseStandard – State change,thenfunction

Introduce async/await(difference and connection with Promise)

In THE ES7 proposal, it is used a lot and Babel has supported it

Koa framework async/await replaces generator

The solution is asynchronous execution and writing logic

Then simply splits the callback

var w = watiHandle()
w.then(function() {... },function() {... }) .then(function() {... },function() {... })Copy the code

Async /await is the most direct way to write async/await

const load = async function(){
    const result1 = await loadImg(src1)
    console.log(result1)
    const result2 = await loadImg(src2)
    console.log(result2)
}
load()
Copy the code

usage

  • useawaitMust be used after the functionasynclogo
  • awaitFollowed by onePromiseThe instance
  • Need to bebalbel-polyfill(compatible)

The characteristics of

  • Using thePromiseThere is no andPromiseconflict
  • It is written completely synchronously, with no callback function
  • But: can’t changeJSSingle-threaded, asynchronous nature

Summarize the current asynchronous JS scheme

  • jQuery Defered
  • promise
  • async/await
  • Generator (to solve asynchrony is not to solve asynchrony)

Virtual DOM

What is vDOM? Why does vDOM exist?

What is the vdom

  • Virtual DOM
  • Simulate the DOM structure with JS
  • The comparison of DOM changes is done in the JS layer (Turing-complete language: language that can implement various logic).
  • Improved redraw performance

DOM

<ul id="list">
    <li class="item">Item 1</li>
    <li class="item">Item 2</li>
</ul>
Copy the code

Virtual DOM

{
    tag: 'ul',
    attrs: {
        id: 'list'
    },
    children: [{
            tag: 'li',
            attrs: { className: 'item' },
            children: ['item1']
        },
        {
            tag: 'li',
            attrs: { className: 'item' },
            children: ['item2']}]} //className replaces class because class is a reserved js wordCopy the code

The biggest performance drain on browsers is DOM manipulation, DOM manipulation is very expensive and now browsers execute JS very fast and that’s why vDOM exists

A requirements scenario

// Modify any information, and the table will be modified as well [{name:'zhangsan',
        age: 20,
        address: 'beijing'
    },
    {
        name: 'lisi',
        age: 21,
        address: 'shanghai'
    },
    {
        name: 'wangwu',
        age: 22,
        address: 'guangzhou'}]Copy the code

withjQeryimplementation

Funciton render(data) {// this function is funciton render(data) {'#btn-change').click(function(){
    data[1].age = 30;
    data[2].address = 'shenzhen'; render(data); }) // Render (data)Copy the code
//render functionfunction render(data) {
    $container = $("#container"); // Empty the existing content$container.html(' '); // Splice table var$table = $('<table>')
    $table.append($('<tr><td>name</td><td>age</td><td>address</td></tr>'))
    data.forEach(item => {
        $table.append($('<tr><td>' + item.name + '</td><td>' + item.age + '</td><td>' + item.address + '</td></tr>'))
        $container.append($table)}); } // Only render once, relatively efficient //DOM rendering is the most expensive and can only be avoidedCopy the code

Problems encountered

  • DOM manipulation is “expensive” and JS runs efficiently
  • Minimize DOM manipulation, not “clean up “(clear reset)
  • The more complex the project, the more severe the impact
  • Vdom solves this problem
var div = document.createElement('div');
var item,result = ' ';
for(item in div){
	result += '|'+ item; } console.log(result); // The default DOM node created by the browser, Attributes are a lot of //result |align|title|lang|translate|dir|dataset|hidden|tabIndex|accessKey|draggable|spellcheck|autocapitalize|contentEditable|is ContentEditable|inputMode|offsetParent|offsetTop|offsetLeft|offsetWidth|offsetHeight|style|innerText|outerText|onabort|o nblur|oncancel|oncanplay|oncanplaythrough|onchange|onclick|onclose|oncontextmenu|oncuechange|ondblclick|ondrag|ondragend |ondragenter|ondragleave|ondragover|ondragstart|ondrop|ondurationchange|onemptied|onended|onerror|onfocus|oninput|oninva lid|onkeydown|onkeypress|onkeyup|onload|onloadeddata|onloadedmetadata|onloadstart|onmousedown|onmouseenter|onmouseleave| onmousemove|onmouseout|onmouseover|onmouseup|onmousewheel|onpause|onplay|onplaying|onprogress|onratechange|onreset|onres ize|onscroll|onseeked|onseeking|onselect|onstalled|onsubmit|onsuspend|ontimeupdate|ontoggle|onvolumechange|onwaiting|onw heel|onauxclick|ongotpointercapture|onlostpointercapture|onpointerdown|onpointermove|onpointerup|onpointercancel|onpoint erover|onpointerout|onpointerenter|onpointerleave|nonce|click|focus|blur|namespaceURI|prefix|localName|tagName|id|className|classList|slot|attributes|shadowRoot|assignedSlot|innerHTML|outerHTML|scrollTop|scrollLeft|scr ollWidth|scrollHeight|clientTop|clientLeft|clientWidth|clientHeight|attributeStyleMap|onbeforecopy|onbeforecut|onbeforep aste|oncopy|oncut|onpaste|onsearch|onselectstart|previousElementSibling|nextElementSibling|children|firstElementChild|la stElementChild|childElementCount|onwebkitfullscreenchange|onwebkitfullscreenerror|setPointerCapture|releasePointerCapture|hasPointerCapture|hasAttributes|getAttributeNames|getAttribute|getAttributeNS|setAttribute|setAttributeNS|removeAttribute|removeAttributeNS|hasAttribute|hasAttributeNS|toggleAttribute|getAttributeNode|getAttributeN odeNS|setAttributeNode|setAttributeNodeNS|removeAttributeNode|closest|matches|webkitMatchesSelector|attachShadow|getElementsByTagName|getElementsB yTagNameNS|getElementsByClassName|insertAdjacentElement|insertAdjacentText|insertAdjacentHTML|requestPointerLock|getClie ntRects|getBoundingClientRect|scrollIntoView|scrollIntoViewIfNeeded|animate|computedStyleMap|before|after|replaceWith|re move|prepend|append|querySelector|querySelectorAll|webkitRequestFullScreen|webkitRequestFullscreen|scroll|scrollTo|scrol lBy|createShadowRoot|getDestinationInsertionPoints|ELEMENT_NODE|ATTRIBUTE_NODE|TEXT_NODE|CDATA_SECTION_NODE|ENTITY_REFER ENCE_NODE|ENTITY_NODE|PROCESSING_INSTRUCTION_NODE|COMMENT_NODE|DOCUMENT_NODE|DOCUMENT_TYPE_NODE|DOCUMENT_FRAGMENT_NODE|N OTATION_NODE|DOCUMENT_POSITION_DISCONNECTED|DOCUMENT_POSITION_PRECEDING|DOCUMENT_POSITION_FOLLOWING|DOCUMENT_POSITION_CO NTAINS|DOCUMENT_POSITION_CONTAINED_BY|DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC|nodeType|nodeName|baseURI|isConnected|ow nerDocument|parentNode|parentElement|childNodes|firstChild|lastChild|previousSibling|nextSibling|nodeValue|textContent|h asChildNodes|getRootNode|normalize|cloneNode|isEqualNode|isSameNode|compareDocumentPosition|contains|lookupPrefix|lookupNamespaceURI|isDefaultNamespace|insertBe fore|appendChild|replaceChild|removeChild|addEventListener|removeEventListener|dispatchEventCopy the code

vdomHow to apply, coreAPIWhat is the

Introduce snabbdom

A library that implements VDOM, vUE Upgrade 2.0 borrows snabbDOM algorithms

var container = document.getElementById('container')

var vnode = h('div#container.two.classes', { on: { click: someFn } }, [
    h('span', { style: { fontWeight: 'bold' }, 'This is bold' }),
    'and this is just normal text',
    h('a', { props: { href: '/foo'}},'I\'ll take you places') ]) //patch into empty DOM element - this modifies the DOM as a side effect patch(container, vnode) var newVnode = h('div#container.two.classes', { on: { click: anotherEventHandle } }, [
        h('span', { style: { fontWeight: 'normal', fontStyle: 'italic'}},'this is now italic type'),
        'and this is still just normal text',
        h('a', { props: { href: '/bar'}},'I\'ll take you places') ]) //send `patch` invocation patch(vnode, newVnode); //Snabbdom efficiently updates the old view to the new stateCopy the code

H function

{
    tar: 'ul',
    attrs: {
        id: 'list'
    },
    children: [
    {
        tag: 'li',
        attrs: {
            className: 'item',
            children: ['item1']
        }
    },
    {
        tag: 'li',
        attrs: {
            className: 'item'
        },
        children: ['item2']]}}Copy the code

The corresponding vnode

var vnode = h('ul#list', {}, [
    h('li.item', {}, 'Item1'),
    h('li.item', {}, 'Item')])Copy the code

The patch function

var vnode = h('ul#list', {}, [
    h('li.item', {}, 'Item1'),
    h('li.item', {}, 'Item2')
])

var container = document.getElementById('container'Var btnChange = document.getelementById ('btn-change')
btnChange.addEventListener('click'.function() {
    var newVnode = h('ul#list', {}, [
        h('li.item', {}, 'Item 111'),
        h('li.item', {}, 'Item 222'),
        h('li.item', {}, 'Item 333')
    ])
    patch(vnode, newVnode)
})
Copy the code
<div id="container"></div>
<button id="btn-change">change</button>
<script src="https://cdn.bootcss.com/snabbdom/0.7.2/snabbdom.js"></script>
<script src="https://cdn.bootcss.com/snabbdom/0.7.2/snabbdom-class.js"></script>
<script src="https://cdn.bootcss.com/snabbdom/0.7.2/snabbdom-props.js"></script>
<script src="https://cdn.bootcss.com/snabbdom/0.7.2/snabbdom-style.js"></script>
<script src="https://cdn.bootcss.com/snabbdom/0.7.2/snabbdom-eventlisteners.js"></script>
<script src="https://cdn.bootcss.com/snabbdom/0.7.2/h.js"></script>

Copy the code
  <script type="text/javascript"Var patch = snabbdom.init([snabbdom_class, snabbdom_props, snabbdom_style, Var h = snabbdom.h var container = document.getelementById ('container'Var vnode = h('ul#list',{},[
        h('li.list', {},'Item1'),
        h('li.list', {},'Item2'),

    ])
    patch(container,vnode)


    document.getElementById('btn-change').addEventListener('click'.function(){// generate newVode var newVnode = h('ul#list',{},[
            h('li.list', {},'Item1'),
            h('li.item', {},'Item B'),
            h('li.item', {},'Item 3')
        ])
        patch(vnode,newVnode)
    })


    </script>
Copy the code

Re-implement the previous demo(withsnabbdomImplementation)

 var snabbdom = window.snabbdom
    var patch = snabbdom.init([
        snabbdom_class,
        snabbdom_props,
        snabbdom_style,
        snabbdom_eventlisteners
    ])
    var h = snabbdom.h
    var container = document.getElementById('container')
    var btnChange = document.getElementById('btn-change')
    var vnode
    var data = [{
            name: 'zhangsan',
            age: 20,
            address: 'beijing'
        },
        {
            name: 'zhangsan',
            age: 20,
            address: 'shanghai'
        },
        {
            name: 'zhangsan',
            age: 20,
            address: 'shenzhen'
        }
    ]
    
    data.unshift({
        name:'Name:',
        age:'Age:',
        address:'Address:'
    })


    render(data);

    function render(data){
        var newVnode = h('table',{},data.map(function(item){
            var tds = [],i
            for(i in item){
                if(item.hasOwnProperty(i)){
                    tds.push(h('td',{},item[i]+' '))}}return h('tr',{},tds)
        }))
        if(vnode){
            patch(vnode,newVnode)
        }elseVnode = {patch (container, newVnode)}} btnChange newVnode / / store the current vnode results. AddEventListener ('click'.function(){
        data[1].age = 30
        data[2].address = 'shenzhen'
        //re-render
        render(data)
    })
Copy the code

Core API

  • Use of h function
 h('< tag name >', {... Attribute... },[... child element...] ) h('< tag name >', {... Attribute... },'... ')
Copy the code
  • Patch function Usage
patch(container,vnode) 

patch(vnode,newVnode)  //rerender

Copy the code

Let me introduce the diff algorithm

What is the Diff algorithm

Diff in Linux: Find the difference between two files:

diff log1.txt log2.txt
Copy the code

Git diff: The difference between before and after the change

git diff xxxx.js
Copy the code

Some online differentiation sites on the web

http://tool.oschina.net/diff/
Copy the code

Diff algorithm is not a concept proposed by VDOM. It has always existed and is now applied to VDOM. It compares two virtual DOM

To numerous is Jane

  • diffThe algorithm is very complex, very difficult to achieve, a large amount of source code
  • Cut to the chase, explain the core process, and don’t care about details
  • Most interviewers don’t know the details, but they care about the core process
  • Stripped of the complexity, it is still very challenging

Why does VDOM use diff

  • DOMOperations are “expensive”, so keep them to a minimumDOMoperation
  • Find out theDOMNodes that must be updated are updated, others are not updated
  • The process of “finding out” requiresdiffalgorithm

Diff algorithm to achieve the diFF implementation process

  • patch(container,vnode)

How do I use VNodes to generate real DOM nodes

 {
    tag: 'ul',
    attrs: {
        id: 'list'
    },
    children: [
        {
            tag: 'li',
            attrs: {
                className: 'item'
            },
            children:['item 1']]}}Copy the code
<ul id = "list">
    <li class='item'>Item 1</li>
</ul>
Copy the code

Simple implementation algorithm

function createElement(vnode) {
    var tag = vnode.tag;
    var attrs = vnode.attrs || {};
    var children = vnode.children || [];
    if(! tag) {returnVar elem = document.createElement(tag); // attribute var attrName;for (attrName in atts) {
        if(attrs.hasOwnProperty(attrName)) { elem.setAttribute(attrName, Attrs [attrName])}} // Children.array.forEach(childVnode => {em.appendChild(createElement(childVnode))});return elem;
}
 
Copy the code
  • patch(vnode,newVnode)
 {
    tag: 'ul',
    attrs: { id: 'list' },
    children: [{
            tag: 'li',
            attrs: { className: 'item' },
            children: ["Item 1"]
        },
        {
            tag: 'li',
            attrs: {
                className: 'item',
                children: ['Item 2'}}]}Copy the code

Contrast:

{
    tag: 'ul',
    attrs: { id: 'list' },
    children: [{
            tag: 'li',
            attrs: { className: 'item' },
            children: ["Item 1"]
        },
        {
            tag: 'li',
            attrs: {
                className: 'item',
                children: ['Item 222']
            }
        },
        {
            tag: 'li',
            attrs: {
                className: 'item',
                children: ['Item 3'}}]}Copy the code

Simple implementation

 functionupdateChildren(vnode, newVnode) { var children = vnode.children || []; var newChildren = newVnode.children || []; ForEach ((child, index) => {var newChild = newChildren[index];if (newChild == null) {
            return;
        }
        if (child.tag === newChild.tag) {
            updateChildren(child, newChild)
        } else {
            replaceNode(child, newChild)
        }
    });
}
Copy the code
  • Nodes are added and deleted
  • Node reordering
  • Node properties, styles, event bindings
  • How to actively squeeze performance

MVVMandVue

usejQueryAnd using a framework

Separation and decoupling of data and view (Closed open principle)

  • jqueryThe data and view are mixed together, which does not meet the open and closed principle
  • vue: Combines data with Vue objectsViewIt’s completely separated

Data-driven views

  • jqueryIt goes against the grain,jqueryModify the view directlyDOM
  • vueOperations on data no longer need to reference the correspondingDOMObject, throughVueThe object of thisvmImplement binding to each other. A data-driven view that only cares about data changes,DOMOperation encapsulated

rightMVVMThe understanding of the

MVC

MVVM

  • Model: Data, model
  • View: Views, templates (views and models are separate)
  • ViewModel: connectionModelandView

MVVM is not an innovation, ViewModel is a kind of micro innovation developed from MVC, combined with the innovation of front-end scenarios

How to implement MVVM

VueThe three elements

  • responsive:vueHow to listen indataEach property of the
  • Template engine: How are vue templates parsed and instructions processed
  • Apply colours to a drawing:vueHow does the template render intohtmlAnd the rendering process

vueHow to achieve reactive in

What is reactive

  • Modify thedataAfter the property,vueListen immediately (and render the page immediately)
  • dataProperty is proxied tovmon

Object.defineProperty

API added in ES5, so Vue does not support older browsers (because older browsers do not support this property)

var obj = {};
    var _name = 'zhangsan';

    Object.defineProperty(obj,"_name",{
        get:function(){
            console.log("get");
            return _name;
        },
        set:function(newVal){ console.log(newVal); _name = newVal; }}); Console. log(obj.name) // Can listen to obj.name ='list'
Copy the code

Analog implementation

var vm = new Vue({
    el: '#app',
    data: {
        price: 100,
        name: 'zhangsan'}})Copy the code
var vm = {}
var data = {
    name: 'zhangsan',
    price: 100
}

var key, value
for (key inData) {// Hit closure. Create a new function that guarantees the independent scope of the key (function(key) {
        Object.defineProperty(vm, key, {
            get: function() {
                console.log('get')
                return data[key]
            },
            set: function(newVal) {
                console.log('set')
                data[key] = newVal
            }
        })
    })(key)
}

Copy the code

vueHow to parse templates

What is a template

  • Essence: string; Have logic, asv-if.if-else-if, embeddedJS variable.
  • withhtmlThe format is very similar, but very different (static), and eventually you have to convert tohtmlAccording to
  • The template must eventually be converted toJScode
    • 1. Because there is logic (v-for.v-if) must be usedJSTo achieve (Turing complete)
    • 2, convert tohtmlRender the page, must useJSTo achieve
    • Therefore, it is important to convert the template to oneJSFunction (renderFunction)

renderfunction

Look at the use of with()

function fn1() {
    with(obj) {
        console.log(name);
        console.log(age);
        getAddress()
    }
}

Copy the code

The simplest example

<div id="app">
    <p>{{price}}</p>
</div>
Copy the code
With (this) {//this: vmreturn _c(
        'div', 
        {
            attrs: { "id": "app" }
        }, 
        [
            _c('p'[_v(_s(price))])}Copy the code
ƒ (a, b, c, d) {return createElement(vm, a, b, c, d, false); }

//vm._v
ƒ createTextVNode (val) {
  returnNew VNode(undefined, undefined, String(val))}return val == null? ' ': typeof val === 'object'? JSON.stringify(val, null,2): String(val)
}
Copy the code
  • All the information in the template is includedrenderIn the function
  • thisnamelyvm
  • pricenamelythis.price, i.e.,dataIn theprice
  • _cnamelythis._cnamelyvm._c

A more complicated example

    <div id="app">
        <div>
            <input v-model="title">
            <button v-on:click="add">submit</button>
        </div>
        <div>
            <ul>
                <li v-for="item in list">{{item}}</li>
            </ul>
        </div>
    </div>
Copy the code

How to find the render function: code.render

How the template generates the render function:

Precompilation has been supported since vue2.0. We write templates in the development environment, compile and package them, and generate the render function (JS code) in the production environment.

With (this){// this is vmreturn _c(
                'div',
                {
                    attrs:{"id":"app"}
                },
                [
                    _c(
                        'div',
                        [
                            _c(
                                'input',
                                {
                                    directives:[
                                        {
                                            name:"model",
                                            rawName:"v-model",
                                            value:(title),
                                            expression:"title"
                                        }
                                    ],
                                    domProps:{
                                        "value":(title)
                                    },
                                    on:{
                                        "input":function($event) {if($event.target.composing)return;
                                            title=$event.target.value
                                        }
                                    }
                                }
                            ),
                            _v(""),
                            _c(
                                'button',
                                {
                                    on:{
                                        "click":add
                                    }
                                },
                                [_v("submit")]
                            )
                        ]
                    ),
                    _v(""),
                    _c('div',
                        [
                            _c(
                                'ul',
                                _l((list),function(item){return _c('li',[_v(_s(item))])})
                            )
                        ]
                    )
                ]
            )
        }

Copy the code
//vm._l
 function renderList(val,render) {
        var ret, i, l, keys, key;
        if (Array.isArray(val) || typeof val === 'string') {
            ret = new Array(val.length);
            for(i = 0, l = val.length; i < l; i++) { ret[i] = render(val[i], i); }}else if (typeof val === 'number') {
            ret = new Array(val);
            for(i = 0; i < val; i++) { ret[i] = render(i + 1, i); }}else if (isObject(val)) {
            keys = Object.keys(val);
            ret = new Array(keys.length);
            for(i = 0, l = keys.length; i < l; i++) { key = keys[i]; ret[i] = render(val[key], key, i); }}if (isDef(ret)) {
            (ret)._isVList = true;
        }
        return ret
    }

Copy the code
  • v-modelHow is that done?
  • v-on:clickHow is that done
  • v-forHow is that done

Render function and DOM

  • The “logic” in the template (v-for.v-ifThe problem of)
  • That leaves the problem of template generating HTML
  • Also, what is vm_c?renderWhat does the function return
    • Vm._c is essentially equivalent tosnabbdomIn thehfunction
    • renderAfter the function executes, it returnsvnode
vm._update(vnode) {
    const prevVnode = vm._vnode
    vm._vnode = vnode
    if(! prevVnode) { vm.$sel = vm.__patch__(vm.$sel, vnode) // Same as the patch function in snabbdom}else {
        vm.$sel = vm.__patch__(prevVnode, vnode)
    }
}

funciton updateComponentVnode vm._update(vm._render())} {//vm._render ()}Copy the code
  • updateComponentImplemented in thevdomthepatch
  • The first rendering of the page executesupdateComponent
  • dataFor each attribute modification, runupdataCommponent

vueImplementation process of

Step 1: Parse the template into the Render function

  • withThe use of the
  • All the information in the template is capturedrenderFunction contains
  • Used in the templatedataProperties in, all become JS variables
  • In the templatev-model,v-if,v-onIt all becomes JS logic
  • renderThe function returnsvnode

Step 2: Responsive listening

  • Object.defineProperty
  • willdataProperty proxy tovmon

Step 3: Render for the first time, display the page, and bind dependencies

  • First render, executeupdateaComponent, the implementation ofvm._render()
  • performrenderFunction, which accesses thevm.listandvm.title
  • It’s going to be reactivegetMethod listens on (why listen on GET? Don’t you just listen to set?
    • dataThere are a number of attributes in the. Some will be used and some may not be used
    • The one that’s being used goes togetWhat’s not used doesn’t goget
    • Did not go togetAttributes in,setWhen we don’t need relationships
    • Avoid unnecessary repetitive rendering
  • performupdateComponent, will govdomthepatchmethods
  • patchwillvnodeTo renderDOMThe initial rendering is complete

Step 4: Data property changes, rerender is triggered

  • Property modification, to be responsivesetListen to the
  • setPerformed in theupdateaComponetn
  • updateComponentTo performvm._render()
  • The generatedvnodeandprevVnodeThrough thepatchTo compare
  • Render to thehtmlIn the

Componentization and React

  • Relationship between JSX and VDOM
  • So let’s talk about the setState process
  • React and Vue

A little bit about componentization

todolist Demo1

The command line

  • npm i create-react-app -g
  • create-react-app react-test
  • npm start
  • app.js
import Todo from './components/todo/index.js';

class App extends Component {
  render() {
    return (
      <div className="App"> <Todo></Todo> </div> ); }}export default App;

Copy the code
  • src = > components = > todo
import React, { Component } from 'react'

class Todo extends Component {
    constructor(props) {
        super(props)
    }
    render() {
        return ( 
            <p> this is todo component </p>
        )
    }
}

export default Todo

Copy the code

todolist Demo2

list => todo => index.js

import React, { Component } from 'react'

class List extends Component{
    constructor(props){
        super(props)
    }
    render() {
        const list = this.props.data
        return (
            <ul>
                {
                    list.map((item,index) =>{
                        return <li key={index}>{item}</li>  
                    })
                }
            </ul>
        )
    }
}

export default List
Copy the code

Have to add the key

todo.js

import React, { Component } from 'react'
import List from './list/index.js';
import Input from './input/index.js';

class Todo extends Component {
    constructor(props) {
        super(props)
        this.state = {
            list:[]
        }
    }
    render() {
        returnBind (this)}/> <List data={this.state. List}/> </div>)}/ / Add the List automatically List this.setState({list:currentList.concat(title)})}}export default Todo

Copy the code

list => input => index.js

import React, { Component } from "react";

class Input extends Component {
  constructor(props) {
    super(props);
    this.state = {
      title: ""
    };
  }
  render() {
      return(
        <div>
            <input value={this.state.title} onChange={this.changeHandle.bind(this)} />
            <button onClick={this.clickHandle.bind(this)}>submit</button>
        </div>  
      )
   
  }
  changeHandle(event) {
    this.setState({
      title: event.target.value
    });
  }
  clickHandle() { const title = this.state.title; // addTitle to the list const addTitle = this.props. AddTitle; addTitle(title); // Empty this.setState({title:""}); }}export default Input
Copy the code

A little bit about componentization

Component encapsulation

  • view
  • data
  • Change logic (data-driven view)

Component reuse

  • Props to pass
  • reuse

JSXWhat is the essence

JSX grammar

  • htmlIn the form of
  • Introduce JS variables and expressions
  • if... else...
  • cycle
  • styleAnd the className
  • The event

JSX parses to JS

  • JSX is syntax sugar
  • The development environment compiles JSX to JS code
  • JSX writing method greatly reduces the learning cost and coding workload
  • At the same time,JSXAlso increasesdebugThe cost of
/*JSX code */ var profile = <div> <img SRC ="avater.png" className="profile"/>
    <h3>{[user.firstName,user.lastName].join(' ')} < / h3 > < / div > -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- - / / end parsed into var profile = React.createElement("div",null,
  React.createElement("img",{src:"avater.png",className:"profile"}),
  React.createElement("h3",null,[user.firstName,user.lastName].join("")))
Copy the code

React.createElement Parameter Description

React.createElement('div', {'id':'div1'},child1,child2,child3)
React.createElement('div', {'id':'div1'}, [...]. )Copy the code
  • vdomh()
  • vuethe_c()
  • reactthecreateElement
render(){
        const list = this.props.data
        return{
            <ul>
                {
                    list.map((list,index)=>{
                        return <li key={index}>{item}</li>>
                    })
                }
            </ul>
        }
    }
    
----------------------------------------------------------------------------
function render(){
    const list = this.props.data;
    return React.createElement(
        'ul'.'null',
        list.map((item,index) => {
            return React.createElement(
                "li", {key:index}, item ); })); }Copy the code

JSX independent standard

  • JSXisReactIntroduced, but notReactThe unique
  • ReactIt has been opened up as a stand-alone standard and is available for other projects
  • React.createElementIt’s customizable
  • Description: its own function is complete; Compatibility with other standards and scalability

Hybrid

  • Mobile accounts for the majority of traffic, by farpc
  • First-tier Internet companies have their ownAPP
  • theseAPPThere is a large proportion of front-end code, take wechat for example, you browse wechat content every day, a lot of it is front-end

hybridWhat is it and whyHybrid, how do you do that

hybridText interpretation

  • hybridThis is “hybrid”, which is the mixed development of front-end and client
  • Front-end developers and client personnel need to cooperate to complete
  • Some links may also be involvedserverend

Existence value, why usehybrid

  • Fast iteration update [Key] (without APP review)
  • Smooth experience (similar to NA experience)
  • Reduce development and communication costs, and both ends share a common set of code

webview

  • Is a component in an app (apps can have itwebviewOr not)
  • Used to load h5 pages, a small browser kernel

file:// agreement

  • In fact, from the very beginning of HTML development, the file protocol has been used
    • Load local files, quick
    • Network loading is slow

  • The importance of standards

In order to achieve the same experience as the native, the loading speed must be extremely fast, abnormal fast, and almost as fast as the client

hybridApplicable scenario

  • Using NA: The experience needs to be extreme and changes are not frequent (e.g. the front page of the headlines)
  • Using Hybrid: High experience requirements and frequent changes (e.g., headline news details page)
  • Use H5: Experience is not required, not commonly used (such as reporting, feedback and other pages)

hybridThe specific implementation

  • The front end does a static page (HTML JS CSS), the file to the client
  • The client gets the front-end static page and stores it in the APP as a file
  • The client is in a WebView
  • Load static pages using the File protocol

How to update the APP in real time after it is released

Analysis of the

  • Replace static files on each client
  • Only the client can do it (the client is developed by us)
  • The client downloads the latest static file from serve
  • We maintain static files for the server

The specific implementation

  • A version number is available, for example, 201803211015
  • Compress the static file into a ZIP package and upload it to the server
  • Each time the client starts, it checks the version number on the server
  • If the server version is greater than the client version, download the latest ZIP package
  • After downloading, unpack the package and overwrite the existing files

hybridandh5The difference between

Advantages:

  • Better experience, basically the same as NA experience
  • Fast iteration without APP review

Disadvantages:

  • Development costs are high. Joint investigation, testing and bug checking are more troublesome
  • High operation and maintenance costs. (Refer to the process of updating and going online previously)

Applicable scenarios:

  • hybrid: Stable product functions, high experience requirements, frequent iteration
  • h5: Single operation activities (such as XX red envelope) or not commonly used functions
  • hybridSuitable for product type,h5Operational type

JS communicates with the client

How does the front end get the content

  • News details page applieshybridHow does the front end get news content
  • You can’t get it with Ajax. First cross-domain (ajaxishttpProtocol), the second speed is slow.
  • The client gets the news content, then the JS communication gets the content and renders it.

JS basic form of communication with the client

Schema Protocol introduction and usage

  • The HTTP (S) and File protocols were introduced earlier
  • Schema protocol – A convention for communication between the front-end and the client

function invokScan() {
    window['_invok_scan_callback'] = function(result){
        alert(result)
    }
    var iframe = document.createElement('iframe')
    iframe.style.display = 'none'
    iframe.src = 'weixin://dl/scan? k1=v1&k1=v2&callback=_invok_scan_callback'Var body = document.body body.appendChild(iframe)setTimeout(() => {
        body.removeChild(iframe)
        iframe = none
    });
}
document.getElementById('btn').addEventListener('click'.function() {
    invokScan();
})
Copy the code

The encapsulation used by schema

What we want to achieve after encapsulation:

*/ window.invok.share({title: {title:});'xxxx',content:'xxx'},funciton(result){
    if(result.error === 0){
        alert('Share the success')}else{// share failure alert(result.message)}})Copy the code
/ / sharefunction invokeShare(data,callback){
    _invoke('share',data,callback)} // Log infunction invokeLogin(data,callback){
    _invoke('login',data,callback)function invokeScan(data,callback){
    _invoke('scan',data,callback)
}
Copy the code
Invoke = {share:invokeShare, login:invokeLogin, scan:invokeScan}Copy the code
function_invoke(action,data,callback){// Invoke schema protocol var schema ='myapp://utils';
    scheam += '/' + action;
    scheam += '? a=a';
    var key;
    for(key in data){
        if(data.hasOwnProperty(key)){
            schema += '&' + key + '=' +data[key]
        }
    }
}
Copy the code
// Handle callback var callbackName =' '
if(typeof callback == 'string'){
    callbackName = callback
}else{
    callbackName = action + Date.now()
    window[callbackName] = callback
}

schema += '&callback' + callbackName
Copy the code

(function(window, undefined) {// Call schema encapsulationfunction_invoke(action, data, callback) {var schema ='myapp://utils/'+ action; // Schema +='? a=a';
        var key;
        for (key in data) {
            if (data.hasOwnProperty(key)) {
                schema += '&' + key + '='+ data[key]; }} // handle callback var callbackName =' ';
        if (typeof callback === 'string') {
            callbackName = callback
        } else {
            callbackName = action + Date.now()
            window[callbackName] = callback
        }
        schema += 'allback = callbackName'} // expose the global variable window.invoke = {share:function(data, callback) {
            _invoke('share', data, callback)
        },
        scan: function(data, callback) {
            _invoke('scan', data, callback)
        },
        login: function(data, callback) {
            _invoke('login', data, callback)
        }
    }
})(window)
Copy the code

Built-in online

  • Package the code encapsulated above, calledinvoke.js, built into the client
  • The client starts each timewebview, are executed by defaultinvoke.js
  • Local load, no network request, no hacker can seeschemaProtocol, more secure

conclusion

  • The basic form of communication: invoking capabilities, passing parameters, listening for callbacks
  • Understanding and using the Schema protocol
  • Call the encapsulation of schema code
  • Built-in online: faster and safer