js原型原型链继承笔记

1.原型的初步认识

    let arr = ['A']
    console.log(arr.concat("B"));

-1.控制台显示
在这里插入图片描述
_proto_就是他的父亲展开之后里面有concat: ƒ concat(),说明它调用的是父亲的方法,下面还有一层_proto就是他的父亲的父亲,里面也有很多方法。整体就有自己-父亲-父亲的父亲,也就是原型链。

 	let obj = {}
    let obj2 = {}
    
    console.log(Object.getPrototypeOf(obj)  == Object.getPrototypeOf(obj2));

Object.getPrototypeOf(obj)获取对象的原型,
-2控制台打印
在这里插入图片描述
obj和obj2都一只有一个_proto_也就是他们的父亲,判断obj和obj2是不是一个父亲,判断结果为true,他们两个是一个父亲。

2.没有原型的对象也是存在的

 	let obj = { name: "小红"}
    -1 console.log(obj.hasOwnProperty("name"));
    let obj2 = Object.create(null,{
      name:{
        value:"小明"
      }
    })
    -2 console.log(obj2.hasOwnProperty("name"));

-1控制台打印
打印结果为true,obj对象里面有name属性,hasOwnProperty是它原型里面的方法。
-2控制台打印
这时会报错
因为用Object.create这样创建的对象,是没有原型的,所以找不到hasOwnProperty这个方法。完全数据字面量,没有原型的关系存在。

3.原型方法与对象方法优先级

	  let obj = {
      show() {
        console.log('小明');
      },
      render() {
        console.log('obj . render ');
      }
    }
    obj.show()//小明
    obj.__proto__.render = function() {
      console.log('小红');
    }
    -1 console.log(obj)
    obj.render();//obj . render

-1控制台打印
在这里插入图片描述
obj自身里面有render方法,但是下面在它的__proto__中也添加了一个render方法,调用的时候是先在自身找,如果自身有的话,就不会调用父亲的。

4.函数拥有多个长辈

 function User() {}
 console.dir(User);

控制台打印
在这里插入图片描述
可以看到它有两个长辈在同一级__proto__,和prototype,他们的使用场景是不一样的。

	function User() {}
	let hd = new User()
    User.prototype.show = function() {
      console.log("小明");
    }
    hd.show()
    console.log(hd);//只有一个长辈__proto__
    console.log(User.prototype === hd.__proto__);

创建一个hd构造函数,hd构造函数没有show方法,在User.prototype中添加show方法,hd.show()就能输出了。由此可见hd和User使用的是一个原型。(User.prototype === hd.proto)结果为true。

function User() {}
User.__proto__.view = function() {
console.log("user function view method")
}
User.view() //user function view method

由此可见__proto__服务于函数对象,prototype服务于函数实例化对象(let hd = new User())
在这里插入图片描述

5.原型关系详情与属性继承实例

    let hd = new Object();
    hd.name = "小明"
    console.dir(hd);
    Object.prototype.show = function() {
      console.log("baidu.com");
    };
    hd.show();

    function User() {

    };
    -1console.dir(User);
    -2console.log(User.prototype.__proto__ === User.__proto__.__proto__);
    -3console.log(Object.protype.__proto__);

	let abc = new User();
	abc.show() //baidu.com
	User.show() //baidu.com

-1控制台打印
在这里插入图片描述
User里面prototype的父级里面有show说明,user.prototype的父级就是Object.prototype
在这里插入图片描述

User里面__proto__的父级里面也有show说明,User的prototype和__proto__指向的都是Objece.prototype
-2控制台打印
true
-3控制台打印
null
在这里插入图片描述

6.系统构造函数的原型提现

 let obj = {}; //new Object
    console.log(obj.__proto__ == Object.prototype); // true
    Object.prototype.show = function() {
      console.log('小明');
    }
    obj.show()

    let arr = []; //new Array
    console.log(arr.__proto__ == Array.prototype);// true

    let str = '';
    console.log(str.__proto__ == String.prototype);// true

    let bool = true;
    console.log(bool.__proto__ == Boolean.prototype);// true

    let reg = /a/i; // new RegExp
    console.log(reg.__proto__ == RegExp.prototype);// true

7.自定义对象的原型设置

 	let obj = { name: "obj"};
    let parent = { name: "parent", show() {
      console.log('parent method:' + this.name);
    }};
    console.log(obj.__proto__ = Object.prototype);
    Object.setPrototypeOf(obj,parent) //parent是obj的父级
    console.log(obj);

    obj.show();//parent method:obj   自身没有这个方法去父级寻找
    parent.show();//parent method:parent
    -1console.log(Object.getPrototypeOf(obj));

Object.setPrototypeOf(obj, prototype)设置一个指定的对象的原型 ( 即, 内部[[Prototype]]属性)到另一个对象或 null。
obj
要设置其原型的对象。.
prototype
该对象的新原型(一个对象 或 null).
-1控制台打印
获取obj的原型,也就是parent ,之前给它设置作为了obj的原型
在这里插入图片描述

8.原型中的constructor引用

    function User(name) {
      this.name = name;
    }
    console.dir(User);
    console.log(User.prototype.__proto__ == Object.prototype); //true
    -1console.log(User.prototype.constructor == User);
    let lisi = new User.prototype.constructor('李四')
    console.log(lisi);

-1控制台打印
true
在这里插入图片描述
所以说User等于User.prototype.constructor

   function User(name) {
      this.name = name;
    }
    //想要在原型中添加多个方法
    User.prototype = {
	show() {
	console.log(this.name)
	},
	show2() {
	console.log(this.name)
	}
	}
	-2console.dir(User)

-2控制台打印
在这里插入图片描述

这种方式往原型中添加多个方法,创建一个新对象,该变了原型。原来的对象里面有个constructor属性,改变原型之后就没有这个属性了。那我们就不能使用这种方式了let lisi = new User.prototype.constructor(‘李四’),如果我们想要使用这种方式,就需要把constructor配置上。

    User.prototype = {
    constructor:User,
	show() {
	console.log(this.name)
	},
	show2() {
	console.log(this.name)
	}
	}

在这里插入图片描述

9.原型链检测之instanceof

function A() {};
    function B() {};
    function C() {};
    let c = new C();
    B.prototype = c
    let b = new B();
    A.prototype = b;
    let a = new A();
  

    console.log(a instanceof B); //true
    console.log(a instanceof C); //true
    console.log(a instanceof C); //true
    console.log(b instanceof A);//false b对象原型链是否有A的构造函数

在这里插入图片描述

10.Object.isPrototype原型检测

isPrototypeOf() 方法用于测试一个对象是否存在于另一个对象的原型链上。

// a.__proto__ = Object.prototype
    let a = { name:'a'};
    // b.__proto__ = Object.prototype
    let b = {};
    let c = {};
    Object.setPrototypeOf(a, b)
    Object.setPrototypeOf(b,c)
    // 一个对象是否在另一个对象的原型链上
    // a对象是否在b.__proto__的原型链上
    console.log(a);
    console.log(b.__proto__.isPrototypeOf(a)); //false  
    console.log(b.isPrototypeOf(a))//true

11.in与hasOwnProperty属性检测差异

 	let a = { url: 'baidu.com' };
    let b = { name: '小明'};
    // Object.prototype.web = 'www'
    // console.log('web' in a); //true
    Object.setPrototypeOf(a,b); //b设置成a的原型
    
    // a里面没有,但是原型里面有,in不仅检测当前对象,还会检测原型链
    console.log('name' in a);  //true

    // hasOwnProperty单纯检测对象
    console.log(a.hasOwnProperty('name'));

    for(const key in a) {
      console.log(key); // url name
      if(a.hasOwnProperty(key)){
        console.log(key);//url
      }
    }

12.使用call和apply借用原型链

1.不传参数写法

    let obj = {
      data: [1,2,3,34,5,6,7]
    }
    //max是obj原型里面的方法
    Object.setPrototypeOf(obj,{
      max() {
        return this.data.sort((a,b) => b - a)[0];
      }

    });
    // 取obj里面的最大值
    console.log(obj.max());//34

    let obj2 = {
      lessons:{ js:87, hph:50, node:99,linux:88 },

      // getter
      //get data() {
        //return Object.values(this.lessons)
     //}
    }
    // 取最大值,借用obj里面的max
   console.log(obj.max.apply(obj2));   //这样写 max里面的this就是obj2,但是obj2里面没有data属性

必须要在obj2里面添加

get data() {
        return Object.values(this.lessons)
      }

2.传递参数写法

 let obj = {
      data: [1,2,3,34,5,6,7]
    }
    Object.setPrototypeOf(obj,{
      max(data) {
        return data.sort((a,b) => b - a)[0];
      }

    });
    // 取obj里面的最大值
    console.log(obj.max(obj.data));//34

    let obj2 = {
      lessons:{ js:87, hph:50, node:99,linux:88 },
    }
    console.log(obj.max.call(null,Object.values(obj2.lessons)));

补充知识JS中的getter和setter

13.优化方法借用

   let obj = {
      data: [1,2,3,34,5,6,7]
    }
    // apply是把data里面的数据展开了一个一个传递进Math.max里面,call是直接把数组作为一个参数传递进去了
    console.log(Math.max.apply(null,obj.data));//34
    let obj2 = {
      lessons:{ js:87, hph:50, node:99,linux:88 },
    }
   console.log(Math.max.apply(null,Object.values(obj2.lessons)));

14.DOM节点借用Array原型方法

<button class="red">Js</button>
<button>node</button>

  let arr = [1, 3, 43];
  let res = arr.filter(item => {
    return item > 39;
  })
  console.dir(Array);//Array.prototype里面有filter方法
  let btns = document.querySelectorAll('button')
  console.log(btns.filter);

  btns = Array.prototype.filter.call(btns,item => {
    // 找button里面含有class的
    return item.hasAttribute('class')
  })
  console.log(btns);//[button.red]

在这里插入图片描述

15.合理的构造函数方法声明

function User(name) {
	this.name = name;
	this.show = function() {
	console.log(this.name)
	}
}

let lisi = new User('李四')
let zhangsan = new User('张三')
console.log(lisi);
console.log(zhangsan);

控制台打印
在这里插入图片描述
他们两个用的是同一个方法,为了优化可以把方法写在原型里面

User.prototype.show = function() {
console.log(this.name);
}
//如果有多个共用方法
User.prototype = {
//通过原型也要找到构造函数
  constructor: User,
  show() {
	console.log(this.name)
  },
  demo() {
  console.log('demo ...')
  }

}

16.this和原型没有关系

let obj = {
name:'张三',
show() {
console.log(this.name)
}
}
console.log(obj.show())   

控制台打印
在这里插入图片描述

let obj = {
name:'张三',

}
let User = {
name:'李四',
show() {
console.log(this.name)
}
}
Object.setPrototypeOf(obj,User);
console.log(obj.show())   

控制台打印
this和原型没太大关系,永远指向调用的属性的对象
在这里插入图片描述

17.不要滥用原型

不建议在系统原型上面修改,当遇到重名方法,会优先使用最后定义的,会造成代码不稳定。

 <button onclick="this.hide()">node</button>
 Object.prototype.hide = function() {
	this.style.display = 'none'
}

18.Object.create()和__proto__

let user = {
show() {
return this.name
}
}
//定义对象的原型,不能获取
let obj = Object.create(user,{
name:{
value:'张三'
}
})
//show方法在obj的原型里面
console.log(obj.show())
let user = {
  show() {
    return this.name
  }
}
let hd = { name:'李四'}
hd.__proto__ = user;//改变原型为user
console.log(hd.show());//李四

19.使用setPrototypeOf替代__proto__

let user = {
  show() {
    return this.name
  }
}
let obj = { name:'李四'}
Object.setPrototypeOf(obj,user)
console.log(obj);
console.log(Object.getPrototypeOf(obj));

20.__proto__原来是属性访问器

set\get

let hd = {
  action:{},
  proto:null,
  get proto() {
    return this.action
  },
  set proto(obj) {
    if(obj instanceof Object) {
      this.action = obj
    }

  }
};
hd.proto = { view:'111'};
hd.proto = '66'
console.log(hd.proto);//{view: "111"}

给__proto__设置属性字符串是,设置不上的,__proto__里面的set、get会对测试的值进行判断的。

let obj = { name:'张三'};
obj.__proto__ = {
  show() {
    console.log(this.name);
  }
}
obj.__proto__ = 99;
-1console.log(obj.__proto__);

-1控制台打印
在这里插入图片描述

如果想给对象__proto__设置属性

let obj = Object.create(null); //不让它有原型
obj.__proto__ = "李四"
console.log(obj)

在这里插入图片描述

21.改变构造函数原型并不是继承

原型的继承而不是改变构造函数的继承

function User() {}
User.prototype.name = function() {
  console.log('user name method');
}
function Admin() {}
// 改变了构造函数的原型
Admin.prototype = User.prototype
Admin.prototype.role = function() {
  console.log('admin a');
}
let b = new Admin();
console.log(b.name);//现在他可以使用User里面的方法

function Member() {}
Member.prototype = User.prototype
Member.prototype.role = function() {
  console.log('member a');
}

let a = new Admin();
console.log(a.role());//member a 这样明显是不对的

继承的时候,自己本身的方法应该要保存,这种改变构造函数原型的不叫继承。
在这里插入图片描述

22.继承是原型的继承

function User() {}
User.prototype.name = function() {
  console.log('user name method');
}
// let hd = new User();
// console.log(hd);


function Admin() {}
// 改变了构造函数的原型
// console.log(Admin.prototype.__proto__ == Object.prototype); true
//方法1
// Admin.prototype.__proto__ = User.prototype
//方法2:创建一个新对象,把User.prototype作为它的原型
Admin.prototype = Object.create(User.prototype)
Admin.prototype.role = function() {
  console.log('admin a');
}
// let a = new Admin();
// console.log(a.role());

function Member() {}
Member.prototype.__proto__ = User.prototype
Member.prototype.role = function() {
  console.log('member a');
}
let a = new Admin();
console.log(a.role());//admin a

方法二:
在这里插入图片描述

23.继承对新增对象的影响

1.

function User() {}
User.prototype.name = function() {
  console.log('user name method');
}
function Admin() {}
let a = new Admin(); 
// 改变原型对象的父级
Admin.prototype.__proto__ =User.prototype
)
Admin.prototype.role = function() {
console.log('admin.role')
}

a.role();

控制台打印
admin.role
2.

function User() {}
User.prototype.name = function() {
  console.log('user name method');
}
function Admin() {}
let a = new Admin(); 
//新建原型对象
 Admin.prototype = Object.create(User.prototype)
Admin.prototype.role = function() {
console.log('admin.role')
}

a.role();

在这里插入图片描述

24.继承对constructor属性的影响

**function User() {}
User.prototype.name = function() {
  console.log('user name method');
}

function Admin() {}

Admin.prototype =Object.create(User.prototype); 
Admin.prototype.role = function() {
  
console.log('admin.role')
}
-1console.dir(Admin);
// 此时Admin.prototype并没有constructor,它继承的是User的constructor
// 要加上
Admin.prototype.constructor = Admin**

-1控制台打印
在这里插入图片描述

25.禁止constructor被遍历

function User() {}
User.prototype.name = function() {
  console.log('user name method');
}

function Admin() {}

Admin.prototype =Object.create(User.prototype); 
Admin.prototype.role = function() {
  
console.log('admin.role')
}

// 查看对象的属性特征
-1console.log(Object.getOwnPropertyDescriptors(Admin.prototype));
//设置constroctor不能被遍历
Object.defineProperty(Admin.prototype,'constructor',{
  value:Admin,
  enumerable:false
})

// // 禁止constoructor被遍历

let a = new Admin();
console.dir(a);
for( const key in a){
  -2console.log(key);
}

-1控制台打印
在这里插入图片描述
-2控制台打印
在这里插入图片描述

26.方法重写与父级属性访问

function User() {};
User.prototype.show = function (){
  console.log('user.name');
}
User.prototype.size = function (){
  return '哈哈哈哈'
}
function Admin() {}
Admin.prototype = Object.create(User.prototype)
Admin.prototype.constructor = Admin
Admin.prototype.show = function() {
  console.log(User.prototype.size() + 'admin.name');
}
let hd = new Admin();
hd.show()   //哈哈哈哈admin.name

27.面向对象的多态

function User() {}
User.prototype.show = function() {
  console.log(this.description());
}
function Admin() {}
Admin.prototype = Object.create(User.prototype)
Admin.prototype.description = function() {
  return '管理员在此'
}

function Member() {}
Member.prototype = Object.create(User.prototype)
Member.prototype.description = function() {
  return '我是会员'
}

for( const obj of [new Admin(),new Member()]){
  obj.show();
}

控制台打印
在这里插入图片描述

28.使用父类构造函数初始属性

function User(name,age){
  this.name = name
  this.age = age 
}
User.prototype.show = function () {
  console.log(this.name,this.age);
}

// function Admin(name,age) {
// User.call(this,name,age);
// }
function Admin(...args){
  console.log(args);//["小明", 18]
  User.apply(this,args)
}
Admin.prototype = Object.create(User.prototype)
 
let xm = new Admin('小明',18)
xm.show() //小明 18

29.使用原型工厂封装继承

function User(name,age) {
  this.name = name;
  this.age = age;

}
User.prototype.show = function() {
  console.log(this.name,this.age);
}
// 封装一个方法
function extent(sub,sup) {
  sub.prototype = Object.create(sup.prototype)
  Object.defineProperty(sub.prototype,'constructor',{
    value:'sub',
    enumerable:false
  })
}
function Admin(...args) {
  User.apply(this,args)
}
extent(Admin,User)

let admin = new Admin('小明',18);
admin.show()//小明 18


function Zoo(...args) {
User.apply(this,args)
}
extent(Zoo,User)
var zoo = new Zoo('狮子',2)//狮子 2
zoo.show()

30对象工厂派生对象并实现继承

function User(name,age){
  this.name = name;
  this.age = age;
}
User.prototype.show = function() {
  console.log(this.name,this.age);
}

function admin(name,age) {
  let obj = Object.create(User.prototype)
  User.call(obj,name,age)
  return obj 
}
  let lisi = new admin('李四','22')
  lisi.show()//李四 22

31.使用mixi实现多继承

Object.assign() 方法
Object.assign() 方法用于将所有可枚举属性的值从一个或多个源对象分配到目标对象。它将返回目标对象。

 function extent(sub, sup) {
      sub.prototype = Object.create(sup.prototype)
      Object.defineProperty(sub.prototype, 'constructor', {
        value: sub,
        enumerable: false
      })
    }
    User.prototype.show = function () {
      console.log(this.name, this.age);
    }

    function User(name,age) {
      this.name = name;
      this.age = age;
    }
    const PanDa = {
      panda() {
        console.log('熊猫');
      }
    }
    const Lion = {
      lion() {
        console.log('狮子');
      }
    }

    function Zoo(name,age) {
      User.call(this,name,age)
    }
    extent(Zoo,User)
    // Zoo.prototype.panda = PanDa.panda
    Zoo.prototype = Object.assign(Zoo.prototype,PanDa,Lion)
    let dog = new Zoo('大黄',5)
    dog.show()//大黄5
    dog.panda()//熊猫
    dog.lion()//狮子
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值