vue源码入门前需要掌握的js技术

vue源码入门前需要掌握的js技术

js函数涉及到作用域时,函数定义时作用域以及很多东西无法确定,只有调用它时才能确定

call

作用是改变作用域,但是很多博客解释的非常复杂,这个解释比较清楚,直接上代码,上下两段代码等价。

function add(c,d) {
        return this.a + this.b + c + d;
    }
    const obj = {a: 1, b: 2};
    console.log(add.call(obj, 3, 4)); // 10
    // 等价于
    const o = {
        a: 1,
        b: 2,
        add: function(c,d) {
            return this.a + this.b + c + d;
        }
    };
    console.log(o.add(3,4)) // 10
    // 感觉相当于把add这个方法拉到obj这个作用域里来

apply

apply和call区别在于apply第二个参数是Array,而call是将一个个传入,将第一段代码改写可得

    function add(c,d) {
        return this.a + this.b + c + d;
    }
    const obj = {a: 1, b: 2};
    console.log(add.apply(obj, [3, 4])); // 10
    // 或者
    const e = [3, 4];
    console.log(add.apply(obj, e)); // 10

bind

bind 的作用和call很像,也会将它的第一个参数变成函数运行时的作用域对象,后边的参数作为函数的参数传入,但是它的独特型在于它会新建一个函数,上述的作用发生在这个新的函数被调用时,而且,当这个新函数作为构造函数时,它当时绑定的this对象(也就是刚刚的第一个参数)会失效,不过后边的参数依然有效。

    function foo(c,d) {
        this.b = 100;
        console.log(this.a);
        console.log(this.b);
        console.log(c)
        console.log(d)
    }
    var func = foo.bind({a: 1},'no.1')
    func('no.2')
        // 1
        // 100
        // no.1
        // no.2
    // 即使call也不能改变this
    func.call({a: 2},'no3')
        // 1
        // 100
        // no.1
        // no.3
    // 当 bind 返回的函数作为构造函数的时候,
    // bind 时指定的 this 值会失效,但传入的参数依然生效。
    // 所以使用func为构造函数时,this不会指向{a: 1}对象,this.a的值为undefined
    new func('no.4')

类数组对象转数组

类数组对象虽然可以访问到某个键值,但是却不能进行遍历

es5和es6都有各自的方法实现:

    const list = document.getElementsByTagName('li')
    console.log(Array.isArray(list)) // 不是数组
    console.log(list[2].innerHTML) // 可以输出其下某个元素的值
    console.log(list.forEach); // 无法进行遍历
    // ES5方法将类数组对象数组化
    var es5 = Array.prototype.slice.call(list)
    // 或者使用 var es5 = [].slice.call(list)
    console.log(es5)
    // ES6方法将类数组对象数组化
    var es6 = Array.from(list)
    console.log(es6)

vue原理的实现主要是通过 Object对象的defineProperty属性来完成的

obj是要定义新属性的对象

props是新属性的名字

descriptor是配置选项,含有:

  • configurable 是否可以重新定义

  • enumerable 是否可以枚举(object.keys())

  • value 初始值

  • writable 是否可以修改属性值

  • get 回调函数,初始计算得到当前属性

  • set 回调函数,监视当前属性值的变化

定义新属性时不能直接对象.属性这样去设置,应该使用Object.defineProperty(obj, prop, descriptor),需要注意的是:valuewritable不能与get set同时使用,同时使用会报错:Uncaught TypeError: Invalid property descriptor. Cannot both specify accessors and a value or writable attribute, # at Function.defineProperty

const obj = {
        firstName: 'ma',
        lastName: 'bo'
    }
// 使用 value 和writable
    Object.defineProperty(obj, 'fullName',{
        configurable: true,
        enumerable: true,
        value: 'mo--b',
        writable: true,
    })
    console.log(obj.fullName) // mo--b

    const obj = {
        firstName: 'ma',
        lastName: 'bo'
    }
  // 使用get set
    Object.defineProperty(obj, 'fullName',{
        configurable: true,
        enumerable: true,
        get() { // 回调函数,初始计算得到当前属性
            return this.firstName + this.lastName
        },
        set(value) { // 回调函数,监视当前属性值的变化
           const names = value.split('--')
           this.firstName = names[0]
           this.lastName = names[1]
        }
    })
    console.log(obj.fullName) // mabo
    obj.fullName = 'lx--y'
    console.log(obj.firstName, obj.lastName) // lx y
// 因为可枚举因此,若设置为不可枚举,则结果只有 ["firstName", "lastName"]
console.log(Object.keys(obj)) // ["firstName", "lastName", "fullName"]

obj.hasOwnProperty(prop)

判断吗obj自身有无prop属性

console.log(obj.hasOwnProperty('fullName' )) // true

你可能感兴趣的:(vue,vue源码)