1: js实现一个继承方法// 借用构造函数继承实例属性
// js实现一个继承方法,借用构造函数继承实例属性
function Person(){
this.name="xiaomi";
this.age=21;
}
Person.prototype.eat=function(){console.log("food");}
function Coder(){
this.weight=120;
this.height=170;
Person.call(this) // 拿到父类的数据
}
Coder.prototype= new Person(); // 继承父类的方法,此时也拿到父类的属性
Coder.prototype.constructor=Coder; // 改变原型对象下的constructor指针的指向
var me= new Coder();
console.log(me); //Coder { weight: 120, height: 170, name: 'xiaomi', age: 21 }
console.log(me.__proto__); //Coder { name: 'xiaomi', age: 21, constructor: [Function: Coder] }
me.eat(); //food
2: 实现一个基本的Event Bus
(1): 前置知识,了解 new Map() 对象的属性和方法
// ES6中的 new Map() 对象的使用
// clear: 从映射中移除所有的元素
// delete: 从映射中移除指定的元素
// forEach: 对映射中的每个元素执行指定操作
// get: 返回映射中的制定元素
// has: 如果映射包含指定元素则返回true
// set: 添加一个新建元素到映射
// toString: 返回映射的字符串形式
// valueOf: 返回制定对象的原始值
var myMap= new Map();
console.log(myMap);
// size 可以返回映射中的元素数
myMap.set(1,"one");
myMap.set("2", "two");
myMap.set(true,"yes");
myMap.set("函数",function(){console.log("test")})
myMap.set(undefined, "未定义");
myMap.set({name: "xiaoming"},"对象");
myMap.set(Symbol(), "symbol对象");
myMap.set(1,"one2");
myMap.set(1,"one3");
console.log(myMap.get("函数"));
myMap.clear(); // 清空 map
myMap.delete(1); // 删除: key 为1的元素
myMap.forEach((item,key,mapObj)=>{
console.log(item,key);
});
console.log(myMap.get(1));
console.log(myMap.get({name: "xiaoming"})); // undefined ,两个对象不是一个
console.log(myMap.get(true));
console.log(myMap.has("2")); // true , 是否包含指定元素
实现EventEmitter原理代码:
// 实现一个基本的Event Bus
// 定义一个对象; 存储事件, 定义事件, 触发事件
// 事件: (事件类型,事件处理函数)
class EventEmitter {
constructor() {
this.events = new Map();// 用于存储事件
// 添加事件类型以及其事件处理函数
this.addListener=function(type, callback){
// 对于这个事件类型没有其对应的事件处理函数
// 所以说对于一个事件类型只存在一个事件处理函数
if(!this.events.get(type)){
this.events.set(type,callback);
}
}
// 触发事件
this.emit=function(type){
let handel=this.events.get(type);
handel.call(this,...[...arguments].slice(1))
}
}
}
var eventEmitter= new EventEmitter();
eventEmitter.addListener("click", function(a,b){
console.log("啊,被点击啦");
console.log(a,b);
})
eventEmitter.emit("click",12,45);
3: 实现一个双向数据绑定
(1): 前置知识(代码中的注释是根据整体代码的语义进行注释的)
// configurable特性表示对象的属性是否可以被删除,
// 以及除value和writable特性外的其他特性是否可以被修改。
var obj={}
Object.defineProperty(obj, "name",{
value: "xiaowang",
writable: true, // 如果不进行配置,对象的属性值不可以修改
enumerable: true, // 使对象的属性是可以枚举的
// configurable: true
});
delete obj.name; // 由于configurable 默认为false,不可以配置,所以不能删除
console.log(obj); // { name: 'xiaowang' }
console.log(obj.name); // xiaowang
// 当试图改变不可配置属性(除了value和writable 属性之外)
// 的值时会抛出TypeError,除非当前值和新值相同。
Object.defineProperty(obj,"name",{
value: "xiaowangfwv",
writable: true,
enumerable: true, // 改为false的话会报错:Cannot redefine property: name
});
// 注意如果是在字面对象上面定义的属性:
// 其配置属性: writable, configurable, enumerable,
// 等配置属性的默认值都是:true
var obj={
name: "xiaowang",
age:21
}
Object.defineProperty(obj,"name",{
value: "xiaolan"
})
console.log(obj);
原理代码:
前台数据input 输入框value值发生改变时,后台接收到数据(并监听数据发生改变),
进而去向前台进行渲染新的数据,实现了双向数据绑定(前台->后台, 后台->前台)
let obj = {}
let input = document.getElementById('input')
let span = document.getElementById('span')
// 数据劫持
Object.defineProperty(obj, 'text', {
configurable: true,
enumerable: true,
get() {
console.log('获取数据了')
},
set(newVal) {
console.log('数据更新了')
input.value = newVal
span.innerHTML = newVal
}
})
// 输入监听
input.addEventListener('keyup', function(e) {
obj.text = e.target.value
})