[JS]16.实现New以及扩展原型链方法

162 阅读2分钟

1. 实现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);
}

let wangcai = new Dog('旺财')
wangcai.sayName();
wangcai.bark();

// 实现一个new
function _new () {
  // complete code ...
}
let sanmao = _new(Dog, '三毛')
sanmao.bark();   // => 'wangwang'
sanmao.sayName();  // => 'my name is 三毛'
console.log(sanmao instanceof Dog);  // => true
  • 实现
    • 但是 proto 在IE浏览器中不能使用
function _new(Ctor, ...params) {

  // Ctor -> Dog  params -> ['三毛']
  // 1. 创建一个实例对象,实例对象的__proto__是所属类的prototype
  
  let obj = {};
  obj.__proto__ = Ctor.prototype;    
  
  // 2. 把构造函数当普通函数执行,包括私有上下文,作用域链,初始化this,形参赋值等一系列操作,this指向创建的实例对象(基于call)
  
  // Ctor(...params) 执行构造函数
  let result = Ctor.call(obj, ...params); // 改变this,指向obj
  
  // 3. 观察函数执行的返回结果,如果没有返回值,或者返回基本类型,默认返回实例对象,否则返回以自己的值为主
  
  if(/^(object|function)$/.test(typeof result)) return result;
  return obj;
  
}
  • 优化
    • 利用Object.create([obj])
    • Object.create 也不兼容 IE678
// Object.create(pro) 先创建一个空对象,把pro作为当前空对象的__proto__
// 把pro作为当前创建的空对象的原型
// 如果pro传的是null,则当前空对象没有__proto__
let pro = {
  A: 10,
  B: 20
}
console.log(Object.create(pro))

image.png

function _new(Ctor, ...params) {
  // let obj = {};
  // obj.__proto__ = Ctor.prototype;    
  let obj = Object.create(Ctor.prototype)
  let result = Ctor.call(obj, ...params); // 改变this,指向obj
  if(/^(object|function)$/.test(typeof result)) return result;
  return obj;
}
  • 处理IE中可以用的
// 重写的方法只考虑pro传递的是一个对象
Object.create = function(pro) {
  function Proxy() {}
  Proxy.prototype = pro;
  return new Proxy;
}

function _new(Ctor) {
  // 获取除第一个参数以外,剩余传递的参数信息,以数组形式保存到params中
  var params = [].slice.call(arguments, 1)
  
  var obj = Object.create(Ctor.prototype)
  
  // apply第二个参数可以直接传递数组,call第二个参数必须一个个传
  var result = Ctor.apply(obj, params); 
  
  if(/^(object|function)$/.test(typeof result)) return result;
  return obj;
}

2. 扩展内置类原型上的方法

  • 原型链上重写方法会覆盖原有,注意命名
function unique(arr) {
  // 先基于Set去重,再转为数组
  let result = new Set(arr);
  result = Array.from(result);
  return result
}

Array.prorotype.unique = function unique() {
  // this - >arr 当前操作类的实例 数组的扩展方法
  let result = new Set(this);
  result = Array.from(result);
  return result  // 返回结果还是数组,可以调用数组其他方法,链式调用
}

// 先去重 再排序
// sort 是 Array.prototype上的方法,数组可以直接调用
let arr = [1,2,3,2,3,4,2,3,4,2,3,2,3,4,5,3,4];
let result = arr.sort((a, b) => a - b);
console.log(arr, result) // 原始结果改变,返回结果也是排序后的数组

arr.unique().sort(...)