重写内置的New和重写Object.create

202 阅读3分钟

重写内置New

function Dog(name) {
    this.name = name;
}
Dog.prototype.bark = function () {
    console.log('wangwang');
}
Dog.prototype.sayName = function () {
    console.log('my name is ' + this.name);
}
 
/*
 * 重写Object.create:创建某个类的空实例
 */
/* Object.create = function create(prototype) {
    function Func() {}
    Func.prototype = prototype;
    return new Func();
}; */
 
/*
 * _new:创建摸一个类的实例
 * params:
 *    Func创建实例的这个类
 *    剩余的参数都是给Func这个函数传递的实参
 */
function _new(Func, ...args) {
    // 1.创建一个实例对象(对象.__proto__===类.prototype)
    // let obj = {};
    // obj.__proto__ = Func.prototype;

    // Object.create(xxx)创建一个空对象,并且会把xxx作为当前对象的原型链指向
    let obj = Object.create(Func.prototype);
 
    // 2.把类当做普通函数执行(THIS指向的是实例对象)
    let result = Func.call(obj, ...args);
 
    // 3.看一下函数执行是否存在返回值,不存在或者返回的是值类型,则默认返回实例,如果返回的是引用数据类型则返回的不是实例而且自己写的引用类型值
    if (result !== null && /^(object|function)$/.test(typeof result)) {
        return result;
    }
    return obj;
}
let sanmao = _new(Dog, '三毛');
// sanmao.bark(); //=>"wangwang"
// sanmao.sayName(); //=>"my name is 三毛"
// console.log(sanmao instanceof Dog); //=>true

Object.create

var obj = Object.create(null);
// 把obj.__proto__去掉了,浏览器断开了内置的原型链查找(破坏了原始的机制)
obj.__proto__ = Array.prototype;
// 这仅仅是给obj设置了一个私有的属性__proto__
console.log(obj.slice);
// 私有属性中没有slice  =>undefined */
 
var obj = Object.create({}); //=>这样不会破坏内置的原型链查找机制
obj.__proto__ = Array.prototype;
console.log(obj.slice); 

Array.prototype.push:向数组末尾追加新的内容

Array.prototype.push = function push(val) {
    // this -> 当前操作的实例 arr
    // 1.向数组(THIS)末尾追加新的内容【数组索引是连续的,所以新增加这一项的索引肯定在原始最大的索引上加1】
    // this[this.length] = val;
 
    // 2.原始数组(THIS)的长度在之前的基础上会自动加1
    // this.length++;
 
    // 3. 返回新增后数组的长度
};
 
let arr = [10, 20];
let res = arr.push(30);
// res=3 新增数组的长度
*/
 
/* 
let obj = {
    2: 3,
    3: 4,
    length: 2,
    push: Array.prototype.push
}
obj.push(1);
/!*
 * 1. obj[obj.length]=1   =>obj[2]=1
 * 2. obj.length++   =>obj.length=3
 * 
 * {2:1,3:4,length:3,push:...}
 *!/
obj.push(2);
/!*
 * 1. obj[obj.length]=2  =>obj[3]=2
 * 2. obj.length++   =>obj.length=4
 *!/
console.log(obj); //{2:1,3:2,length:4,push:...} 
*/

= == ===

= 赋值:变量和值的关联

== 比较:如果左右两边的数据类型不一致,则默认转换为一致的(对象==字符串,把对象转换为字符串,剩下的情况(除了null/undefined)一般都是要转换为数字)

=== 绝对比较:类型和值都得相同,类型不一样,也不会默认去转(推荐)

  • 基本数据类型转换为数字,默认都是隐式调用Number()处理的
  • 对象转为数字,需要先转换为字符串(先调用valueOf方法,获取其原始值(基本数据类型基于构造函数创建出来的对象,他们的原始值都是基本值),如果原始值不是基本类型值,则继续调用toString),然后再把字符串转换为数字
var a = {
    i: 0,
    // 给当前对象重写“私有”方法valueOf/toString,这样就不会在向原型上找内置的方法
    // valueOf:function(){}
    valueOf() {
        // this => a
        return ++this.i;
    }
};
if (a == 1 && a == 2 && a == 3) {
    console.log('OK');
} 
 
 
var a = [1, 2, 3];
// 让A的私有属性toString等于ARRAY原型上的shift(每次执行都是删除数组第一项,返回的结果是删除的那一项)
a.toString = a.shift;
if (a == 1 && a == 2 && a == 3) {
    console.log('OK');
} 

Object.defineProperty 数据劫持(劫持对象中的某个属性)

在每一次获取a值的时候,我们把它劫持到,返回我们需要的值

Object.defineProperty(window, 'a', {
    get() {
        // 在每一次获取window.a的时候被触发执行
        // 返回啥值,本次获取的值就是啥
    },
    set(val) {
        // 在每一次给window.a赋值的时候执行
    }
}); */
 
var i = 0;
Object.defineProperty(window, 'a', {
    get() {
        return ++i;
    }
});
if (a == 1 && a == 2 && a == 3) {
    console.log('OK');
}