2019web前端javascript--入门级理解原型prototype原型链

写在前面:因为还没开始工作,可能有的部分有错,希望大家能指点出来,这是我看渡一的视频总结的笔记,所有的示例都来自视频,我算是一个搬运工了吧哈哈哈视频讲的很好,强烈推荐大家去看一看ヾ(◍°∇°◍)ノ゙

原型,原型链


是个函数就有原型

原型是构造函数构造出对象的公有祖先

原型

1.定义:原型是function对象的一个属性,它是构造函数制造出的对象的公有祖先,通过该构造函数产生的对象可以继承该原型的属性和方法
示例
//Person.prototype--原型
//↑是Person的爹,在函数Person出生时就有,不是人为写的
//Person.prototype = {} 是祖先
Personn.prototype.name = 'hehe';
Personn.prototype.say = function () {
    console.log('hehe');
};
function Personn(name,age,sex) {
    this.name = name;
    this.age = age;
    this.sex = sex;

}
var person2 = new Personn('xiaoming',18,'male');
var person3 = new Personn();

(1)person2,person3都继承了Personn,虽然1,2都没有name属性,但继承了原型的name属性,1和2访问自己没有的属性,也能访问到

(2)原型也是对象

(3)一般 对象有自己的属性,也有原型给提供的属性

2.利用原型特点和概念,可以提取公有属性
//----固定公有属性-----
Car.prototype={
    height : 1400,
    lang : 4900,
    carName : 'BMW'
};
//----选配属性----
function Car(color,owner) {
    this.color = color;
    this.owner = owner;
}
var car1 = new Car('red','lin');
3.原型的增删改查
Person3.prototype.lastName = 'Deng';
function Person3(name) {
    this.name = name;
}
var person4 = new Person3('xuming');
1.查:(就近原则,对象自己有的话就不访问原型的属性)

对象.属性

2.改:
person4.lastName = 'jame';

//Person3.prototype:
//{lastName: "Deng", constructor: ƒ}

//person4:
//Person3 {name: "xuming", lastName: "jame"}

//person4.__ proto__:
//{lastName: "Deng", constructor: ƒ}

(1)是从自己身上改lastName,相当于给自己增加属性
原型并没有改

(2)原型要修改属性:
Person.prototype.lastName = 'jame'

(3)基本不能通过对象改原型

3.增:

给原型增只能通过函数增加

Person.prototype.lastName = 'jame'
4.删:

对象可以删除对象的属性,不能删除原型的属性

delete person4.lastName
//Person3.prototype
//{lastName: "Deng", constructor: ƒ}
4.对象如何查看对象的构造函数 — > constructor

用来查找创建这个对象的函数

function Car1() {     
}
var car2 = new Car1;

/*car2.constructor↓
ƒ Car1() {

}*/
//---可手动更改constructor--------
Car.prototype = {
    constructor : Person3
}
5.对象如何查看原型 — > 隐式属性 proto
例1.若对象没有该属性,就沿着__ proto__的指向去寻找这个属性
Person5.prototype.name = 'abc';
function Person5() {
  /*  var this = {
        __proto__ : Person.prototype
        __proto__指向该函数的原型
    }*/

}
var obj = {
    name : 'sunny'
};
var person5 = new Person5;
console.log(person5.name);//abc
例2 .__ proto__可以被更改
/*    person5.__proto__ = obj
person5.__proto__ = {name: "sunny"}*/
Person6.prototype.name = 'sunny';
function Person6() {
}
var person6 = new Person6();
Person6.prototype.name = 'cherry';
//Person6.prototype的name已经被改了??执行顺序??
//person6.name = 'cherry'
①Person7.prototype.name = 'sunny';
function Person7() {
}
②Person7.prototype.name = 'cherry';
var person7 = new Person7();
//person7.name = 'cherry'

②覆盖了①

Person8.prototype.name = 'sunny';
function Person8() {
    //var this ={__proto__:Person8.prototype}
}
var person8 = new Person8();
①Person8.prototype = {
    name:'cherry'
};

↑①这一步相当于把自己的空间Person8.prototype换了
但__ proto __ 仍然指向原来的Person8.prototype
__ proto __相当于引用值栈堆间的连线

最后结果:person8.name = ‘sunny’

5.理解例4

var obj1 = {name : 'a'};
var obj2 = obj1;
//obj1 obj2指向同一地址
obj1 = {name : 'b'};
/*    obj2 = 'a'
obj1 = 'b'
obj2重新找了个堆存放a,此时a的地址已经改变了
知识点:引用值*/
Person9.prototype.name = 'sunny';
//1
function Person9() {
}
//2
Person9.prototype = {
    name:'cherry'
};
var person9 = new Person9();

执行顺序从上到下,2把1覆盖了,执行到new时才开始var this,此时prototype已经变为cherry了
person9.name = ‘cherry’
例3是因为已经new完了

原型链

1.如何构成原型链

Grand.prototype.__ proto__ =Object.prototpe(终端)

Grand.prototype.lastName = 'Deng';
function Grand() {
    
}
var grand = new Grand();

Father.prototype = grand;
function Father() {
    this.name = 'xuming';
    this.fortune ={
        car1:'visa'
    }
    this.num = 100
}
var father = new Father();

Son.prototype = father;
function Son() {
    this.hobbit = 'smoke'
}
var son = new Son();

son.name:“xuming”
son.hobbit:“smoke”
son.lastName:“Deng”
son.toString从grand里拿*/


把原型连成链,依照链的顺序(就近)来访问,原型链的连接点就是proto

2.原型链上的增删改查
1.查:就近原则—一直找到终端
2.删:无法通过子孙删,只有本人能删除
3.改:只有本人可以修改
4.增:只能自己增

----------------------------修改:特例-------------------------------

不是所有子孙都修改不了父辈----引用值

this.fortune ={car1:visa}
son把fortune取出来了,并修改了他的值,是调用的修改
谁调用它,引用值操作的都是自己
原始值只能覆盖

son.fortune.car2 ='master';

//-----------输出结果----------------
/*  son
Son {hobbit: "smoke"}
hobbit: "smoke"
*/

/*  father
Grand {name: "xuming", fortune: {…}}
fortune: {car1: "visa", car2: "master"}
name: "xuming"
/
*/
例1.
son.num ++ son给自己赋值并加
son.num = 101
father.num = 100
例2.a.sayName()里有this指向时,谁调用这个方法,this就指向谁
Person10.prototype = {
    name : 'a',
    sayName : function () {
        console.log(this.name);
    }
};
function Person10() {
    this.name = 'b';

}
var person10 = new Person10();

//-----------输出结果----------------
//person10.sayName()='a'只在在Person10.prototype里有sayName方法时
//person10.sayName()='b'
//person10.prototype.sayName = 'a'
例3.
Person11.prototype = {
    height : 100
};
function Person11() {
    this.eat = function () {
        this.height ++;
    }
}
var person11 = new Person11();

person11.eat()
//eat后不加()的话会返回function函数,不会返回结果

//-----------输出结果----------------
/*person11.height=101
person11.__proto__{height: 100}
还是不能改变原型上的内容*/
3.Object.create(原型)

var obj =Object.create(原型)

var obj5 = {name:'sunny',age:123};
var obj51 = Object.create(obj5);
//obj51.name : 'sunny'

//----模拟new Person---
Person12.prototype.name = 'sunny';
function Person12() {
}
var person12 = Object.create(Person12.prototype);
4.绝大多数对象的最终都会继承自Object.prototype
//Object.create(null/undefined)是没有原型的
var obj6 = Object.create(null);//原始值也不能放

obj6.name = 'linda';
//obj6是对象,但没有原型

obj6.__proto__ = {name : 'sunny'};
//obj6.name='linda',说明人为加的proto没有继承属性
5.toStirng 用法

注意:

(1)null和undefined没有toString()方法
且没有原型,即没有 _proto_,因为没法变成包装类


(2)数字能变成包装类–>变为对象–>有原型终端–>有toString()

1.toString重写

一般对象都从终端即Object.prototype调用toString()方法

但如果从中间 Person.prototype = {}插入自己的toString()方法也可以,会覆盖终端的toString(),即重写


重写–同名但功能不同

例1.

//Object.prototype.toString =function(){}     
若没有重写toString(),则调用这个↑

Object.prototype.toString = function(){
return 'haha';//重写
}
Person.prototype = {
/*toString : function () {
return 'hehe';
}*/   //重写,若上面也有重写的方法,还是调用这个,这个覆盖了上面的
};
function Person() {

};
var person = new Person();

注:系统里Number,Boolean,Array,String都有自己的toString()方法
每个类型的对象调用对应的toString()

2.toString—call,apply

(1)对象不使用自己系统自带的toString(),需要用call方法

var num = 123;
num.toString 
//输出"123"
//默认用Number.prototype.toString

想要改变toString方法--调用原型的toString.call
//Object.prototype.toString是系统自带的object的方法
Object.prototype.toString.call(num);
//输出"[object Number]"

因为系统默认输出的方法没有什么用,所以子孙需要重写方法
如:

var foo = true;//true是boolean类型
foo.toString()//自动匹配的方法
//"true"
Object.prototype.toString.call(foo)//重写方法可识别输入类型
//"[object Boolean]"

Boolean.prototype.toString = function () {
    return '改写Number方法成功'//系统的Boolean方法被改写了
}
console.log(foo.toString());// 输出'改写Number方法成功'

(2)document.write()–会隐式的调用toString()方法

证明d.c调用了toString↓

var obj2 = Object.create(null);
1 obj2.toString = function(){
2    return '必须调用toString'	
3 }	
document.write(obj2);

若不写1,2,3行,会报错,因为null和undefined没有原型,1,2,3是自己创建了一个原型的toString方法

小tips

1.js可正常计算范围:
//----解决 0.14 * 100;//14.000000000000002----js精度不准---
问题:Math.random()*100//还是会输出小数
console.log(Math.ceil(2.012));//3  向上取整
console.log(Math.floor(2.012));//2  向下取整
console.log(Math.random());//(0,1)之间的随机数
解决办法:
Math.floor(Math.random()*100)

小数点前16位,小数点后16位

2e-17: 2*10的-17次方

2.数组,对象最好用字面量定义
var obj4 ={};//最好用这种写法
//同 var obj1 = new Object();
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值