【javaScript学习】代码练习

97 阅读4分钟

每每有空 看一看;敲一敲

1.数据劫持 Object.defineProperty和proxy

/**
 * proxy   Object.defineProperty
 */
//proxy 代理 对比 object.defineProperty
handler = {
  set(target, key, value) {
    console.log(key, "set");
    target[key] = value;
    return true;
  },
};
var target = {};
var proxydata = new Proxy(target, handler);

/**
 * 数据劫持    defineProperty
 */
function definePropertydata() {
  let _val = "";
  let _nameList = [];

  Object.defineProperties(this, {
    aname: {
      get() {
        return _val;
      },
      set(newVal) {
        _val = newVal;
        _nameList.push(_val);
      },
    },
    bname: {
      get() {
        return _val;
      },
      set(newVal) {
        _val = newVal;
        _nameList.push(_val);
      },
    },
  });

  this.getNameList = function() {
    return _nameList;
  };
}

var backDefineData = new definePropertydata();
backDefineData.aname = "test get aname";
backDefineData.bname = "test get bname";

console.log(backDefineData.getNameList());

2.原型 原型链

/**
 * 原型  原型链
 */
//函数  两个价值 1.实现具体   2.作为对象
//函数 既是函数也是对象 既有 prototype 也有__proto__


//原型与隐式原型的关系
//每一个构造函数都有prototype原型属性,通过构造函数创建出来的对象都继承自该原型属性。
//对象.__ptoto__ == 构造器.prototype
//对象的隐式原型等于 创建这个对象的构造器的原型

//经典题目
function Func() {
  this.name = 11;
} //既有 prototype 也有__proto__
//每個对象都有__proto__

Func.prototype.func = function() {
  // console.log('222');
};

var nfunc = new Func();
nfunc.func();
nfunc.name;

console.log(nfunc.__proto__ == Func.prototype);

//nfunc.__proto__ == Func.prototype
//Func.prototype__proto__ == Object.prototype;
//Object.prototype.__proto__ == null

function Munc(name, sex) {
  this.name = name;
  this.sex = sex;
}

Munc.prototype.hellword = function() {
  console.log(this.name, this.sex);
};

var m_func = new Munc("111", "man");
m_func.hellword();

3.实现 一个new功能

/**
 *
 * 实现 一个new功能
 */
///A.实现一个new  1.新建一个空对象  2 对象的__proto__ == 调用者的prototype 3.改变指向 apply
//备注:函数上的方法 是挂载在__proto__上的
//第一步 空位对象
//第二步 通过原型链  让 空对象的__proto__ == 传入对象的prototype 目的是空对象可以调用到传入对象的方法
//第三步 通过apply或call 改变this指向  目的是 让空对象可以访问传入对象的属性值
function _new() {
  var _object = {};

  let constructor = [].shift.apply(arguments); //arguments是类数组对象 需要转换 或者用Array.prototype
  _object.__proto__ = constructor.prototype;

  let resback = constructor.apply(_object, arguments);

  return resback;
}
//B 第二种 更简洁的  利用 Object.create 创建一个新对象
function _new() {
  var _object = {};
  let nModel = Array.prototype.shift.call(arguments);
  _object = Object.create(nModel);
  let res = nModel.apply(_object, arguments);
  return res;
}

4.实现一个 call 功能

/**
 * 实现一个 call 功能
 */
Function.prototype._call = function(object, ...arg) {
  object.fn = this;
  let backfn = object.fn(...arg);
  delete object.fn;
  return backfn;
};
function f(name, age) {
  return this.value + name + age;
}
let newModel = { value: 100 };

console.log(f._call(newModel, 1, 2));
//call  bind apply 区别
//apply 和 call 基本类似,他们的区别只是传入的参数不同
//apply 参数  数组或类数组
//bind()方法创建一个新的函数, 当被调用时,将其this关键字设置为提供的值,在调用新函数时,在任何提供之前提供一个给定的参数序列。
//bind 是创建一个新的函数,我们必须要手动去调用

5.valueOf 的使用

//valueOf 的使用 (当值 进行 == <> + - */ 时 会自动调用)
//同理 toString 一样  优先级 valueOf ; toString 偏向于显示  valueOf偏向于运算
let age = {
  i: 1,
  valueOf: () => {
    age.i++;
  },
};
if (age == 1) {
  console.log("判断时候自动调用了!" + age);
}

6.reduce 计算最大和最小值

//reduce 计算最大和最小值
let max = datalist.reduce((currentdata, item) => {
  return currentdata.count >= item.count ? currentdata.count : item.count;
});
let min = datalist.reduce((currentdata, item) => {
  return currentdata.count <= item.count ? currentdata.count : item.count;
});

7.数组或类数组 去重并合并 关键字 filter concat

let a = [
  { name: "aa", sex: "bb" },
  { name: "dd", sex: "bb" },
  { name: "ee", sex: "bb" },
  { name: "ff", sex: "bb" },
];
let b = [
  { name: "aa", sex: "bb" },
  { name: "bb", sex: "bb" },
  { name: "cc", sex: "bb" },
];

let find_data = a.map((item) => item.name);
let new_data = b.filter((v) => !find_data.includes(v.name));
let result = a.concat(new_data);
console.log(result);

8.正则表达式

//正则表达式
// /xxxx/
//  /xxx/i  不区分大小写
//  /xxx/g  全局搜索
//  /xxx/m  多行搜索
// []  表达式 [A-Z] A到Z
// [^]  取反

//元字符  \w ===[0-9A-z] \d===[0-9]

//n+  {1,正无穷}   demo:'abcd' => ['abcd']
//--贪婪模式
//n* {0,正无穷}  demo:'abcd' => ['abcd']['']
//n?  {0或1}     demo:'abcd' => ['a']['b']['c']['d']['']
//n{1,2}         demo:'abcd' => ['ab']['cd']
//^n   n开头
//n$   n结尾
//?=n  匹配后面紧跟n的
//?!n  匹配不是紧跟着n的

//子表达式 () /(a)(b)/  (a)第一个表达式 (b)第二个表达式
//反向引用 \x x表示第几个表达式  \1  /(a)\1\1\1/  表示取第一个表达式 需要几次就写几次
//子表达式具有记忆功能 会按照子表达的规则去匹配

9.递归方法

function formatRouterTree(datalist) {
  let parentRouter = datalist.filter((pi) => pi.pid == 0);
  let childrenRoter = datalist.filter((ci) => ci.pid != 0);
  dataTreelist(parentRouter, childrenRoter);
  //递归方法
  function dataTreelist(parentRouter, childrenRoter) {
    parentRouter.map((p) => {
      childrenRoter.map((c, i) => {
        if (c.pid == p.id) {
          let _c = JSON.parse(JSON.stringify(childrenRoter));
          _c.splice(i, 1);
          dataTreelist([c], _c);

          if (p.children) {
            p.children.push(c);
          } else {
            p.children = [c];
          }
        }
      });
    });
  }

  return parentRouter;
}

10.模拟实现VUE 数据双向绑定

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <div id="app">
      <div>
        <input type="text" v-wc="name" placeholder="姓名" />
        <input type="text" v-wc="age" placeholder="年龄" />
        <input type="text" v-wc="email" placeholder="email" />
        <input type="text" v-wc="tel" placeholder="tel" />
      </div>
      <div>
        <p>姓名:<span>{{name}}</span> </p>
        <p>年龄:<span>{{age}}</span></p>
        <p>email:<span>{{email}}</span></p>
        <p>tel:<span>{{tel}}</span></p>
      </div>
    </div>
  </body>
</html>

<script type="text/javascript" src="./src/libs/MVVM.js"></script>
<script>
  const app = new MVVM('#app',{
      name:'wzt',
      age:'18',
      email:'123',
      tel:'44',
  });
</script>


class MVVM {
  constructor(el, data) {
    this.el = document.querySelector(el);
    this._data = data;
    this.domdata = {};
    this.init();
  }
  init() {
    this.initData();
    this.initDom();
  }
  initDom() {
    this.bindInput(this.el);
    this.bindDom(this.el);
  }
  //1.实现数据相应 (数据劫持)  definePrototy || proxy
  initData() {
    const _this = this;
    this.data = {};

    for (let key in this._data) {
      console.log(key);
      Object.defineProperty(this.data, key, {
        get() {
          console.log(1111);
          return _this._data[key];
        },
        set(newVal) {
          console.log(222);
          //绑定值到元素上
          _this.domdata[key].innerHTML = newVal;
          _this._data[key] = newVal;
        },
      });
    }
  }
  //2.捕获 input 绑定事件 keyup  值  改变数据   (找到指令 如 v-model)
  bindInput(el) {
    const _allinputs = el.querySelectorAll("input");
    _allinputs.forEach((input) => {
      const _findmodel = input.getAttribute("v-wc"); //找到属性值
      if (_findmodel) {
        //绑定事件
        input.addEventListener(
          "keyup",
          this.handleInput.bind(this, _findmodel, input)
        );
      }
    });
    
  }
  handleInput(key, input) {
    const _value = input.value;
    this.data[key] = _value;
  }
  //3.绑定改变的值到页面p (找到 {{}} )
  bindDom(el) {
    const childnodes = el.childNodes;
    childnodes.forEach((item) => {
      if (item.nodeType == "3") {
        const _value = item.nodeValue;
        if (_value.trim().length) {
          //正则判断 是否有{{}}
          let _valid = /\{\{(.+?)\}\}/.test(_value);
          if (_valid) {
            //找到KEY
            let _key = _value.match(/\{\{(.+?)\}\}/)[1].trim();
            this.domdata[_key] = item.parentNode;
            //找到节点 给节点赋值
            item.parentNode.innerText = this._data[_key] || "";
          }
        }
      }
      item.childNodes && this.bindDom(item);
    });
  }
}

11. js继承 ES5 和 ES6 区别

/**
 * @description 继承 ES5 和 ES6 区别
 * @auth  wzt 
 * @version 1.0
 */

//继承 ES5 (原型链,构造函数,组合继承)
function Student(name, age) {
  this.name = name;
  this.age = age;
}

Student.prototype.Setcourse = function() {
  console.log("aaa");
};

function Flamly(name, age, sex, height) {
  Student.call(this, name, age);
  this.sex = sex;
  this.height = height;
}

Flamly.prototype = Object.create(Student);
Flamly.prototype.constructor = Student;
var s1 = new Flamly("xx", "11");

//继承  ES6

class Person {
  //调用类的构造方法
  constructor(name, age) {
    this.name = name;
    this.age = age;
  }
  //定义一般的方法
  showName() {
    console.log("调用父类的方法");
    console.log(this.name, this.age);
  }
}
let p1 = new Person("kobe", 39);
console.log(p1);
//定义一个子类
class Student extends Person {
  constructor(name, age, salary) {
    super(name, age); //通过super调用父类的构造方法
    this.salary = salary;
  }
  showName() {
    //在子类自身定义方法
    console.log("调用子类的方法");
    console.log(this.name, this.age, this.salary);
  }
}
let s1 = new Student("wade", 38, 1000000000);
console.log(s1);
s1.showName();

微信图片_20210625145221.jpg