一、原型

prototype


原型prototype是function对象的一个属性,它也是一个对象。function是一个对象。
prototype是定义构造函数构造出的每个对象的公共祖先。
函数就有prototype默认属性,不用实例化就有prototype属性

  1. function Handphone() { }
  2. console.log(Handphone.prototype);

image.png
Handphone.prototype是一个对象,可以通过Handphone.prototype.xx来声明、保存数据
那就可以先拿Handphone.prototype.xx来保存数据试试,看看什么效果
结果实例化对象hp1、hp2也有在prototype中添加的属性
这个现象说明,这个prototype属性是定义构造函数构造出的每个对象的公共祖先,构造出来的对象存有prototype的地址,所有被该构造函数构造出的对象都可以继承原型上的属性和方法

  1. function Handphone(color,brand){
  2. this.color=color;
  3. this.brand=brand;
  4. this.screen='18:9';
  5. this.system='Android';
  6. }
  7. Handphone.prototype.rom='64G';
  8. Handphone.prototype.ram='6G';
  9. Handphone.prototype.screen='16:9';
  10. var hp1=new Handphone('red','小米');
  11. var hp2=new Handphone('black','华为');
  12. console.log(hp1.rom);//64G
  13. console.log(hp2.ram);//6G
  14. console.log(hp1.screen);//18:9
  15. console.log(hp2.screen);//18:9

通过实例化对象的增删改查来修改prototype是不行的,修改祖先是不行的

  1. function Test(){}
  2. Test.prototype.name='prototype';
  3. var test=new Test();
  4. console.log(test.name);
  5. test.num=1;
  6. console.log(Test.prototype,test);
  7. console.log(test);
  8. delete test.name;
  9. console.log(Test.prototype,test);
  10. test.name='proto';
  11. console.log(test.prototype,test);

通过prototype增加构造函数的属性、方法,prototype对象也是一个对象,可以通过对象字面量来添加、修改

  1. function Handphone(color, brand, system) {
  2. this.color = color;
  3. this.brand = brand;
  4. this.system = system;
  5. }
  6. Handphone.prototype = {
  7. rom: '64G',
  8. ram: '6G',
  9. screen: '18:9',
  10. system: 'Android',
  11. call: function () {
  12. console.log('I am calling somebody');
  13. }
  14. }
  15. var hp1 = new Handphone('black', 'iPhone', 'IOS');
  16. console.log(hp1);

独有属性写方法里,共有属性写原型prototype里

image.png
constructor

prototype对象中也有属性,prototype对象有什么属性?constructor
原型prototype的一个属性constructor对象,指向该构造函数。
所有该构造函数构造出的对象都可以继承原型上的属性和方法。
constructor可以被更改。

  1. function Handphone(color, brand, system) {
  2. this.color = color;
  3. this.brand = brand;
  4. this.system = system;
  5. }
  6. function Telephone() {}
  7. // 可以更改对象的构造函数
  8. Handphone.prototype = {
  9. constructor: Telephone
  10. }

二、原型链

当构造函数car里什么语句都没有时,this对象中也有默认的属性proto,并不是空的,proto是系统内置、自带的属性
proto属于实例化对象,this中携带proto属性,存着构造函数的prototype地址,没有new实例化对象,不存在this,也就不存在proto对象,但依然有prototype对象

当有this.name=’Mazda’时,this变量中存有name的值,不去proto中找
当没有时,向proto中找

proto内置键名,默认不让修改,但可以修改
proto其实是个键名(键值对),通过键值对找到prototype对象,是存储prototype对象的空间,就是装prototype的容器

构造函数通过new实例化对象,生成proto属性,该属性是一个对象,指向该构造函数的原型。
实例化对象通过proto属性可以访问到该构造函数原型上的属性和方法,形成原型链。

  1. function Car() {
  2. /* var this = {
  3. name:'Mazda',
  4. __proto__: Car.prototype={
  5. name:'Benz'
  6. }
  7. }
  8. return this;
  9. */
  10. // this.name='Mazda';
  11. }
  12. Car.prototype.name = "Benz";
  13. var car = new Car();
  14. console.log(car);
  15. console.log(car.name);

image.png

proto、prototype属性可以被修改。

实例化对象没有prototype属性,有proto属性,构造函数有prototype属性,但这两个是一个东西,都指向一个空间,是一样的地址

  1. //由张三 改成李四
  2. function Person() {}
  3. Person.prototype.name = "张三";
  4. var p1 = {
  5. name: "李四",
  6. };
  7. var person = new Person();
  8. console.log(person.name); // '张三'
  9. person.__proto__ = p1;
  10. console.log(person.name); // '李四'
  11. console.log(person)
  12. console.log(person.prototype)//undefined
  13. // 实例化对象没有prototype属性,有__proto__属性,构造函数有prototype属性,但这两个是一个东西,都指向一个空间,是一样的地址
  14. console.log(person.__proto__)//有值
  1. function Car() { }
  2. Car.prototype.name = 'Mazda';
  3. var car = new Car();
  4. Car.prototype.name= 'Benz';
  5. console.log(car.name); // 'Benz'
  6. // 构造函数的原型添加name属性,空间地址不变
  7. Car.prototype.name = 'Benz';
  8. function Car() { }
  9. var car = new Car();
  10. // 构造函数的原型指向新的对象,新的空间地址
  11. Car.prototype = {
  12. name: 'Mazda'
  13. }
  14. // 实例化出来的对象的__proto__属性指向的是未修改前的Car.ptototype对象
  15. console.log(car.name); // 'Benz'
  16. console.log(car);

新版edge截图,与chrome一样,不同的浏览器不一样,显示结果不一样
[[Prototype]]就是proto
image.png
火狐浏览器截图就是proto
image.png
image.png

  1. function Car() {this.a='1'}
  2. // 构造函数的原型添加name属性,空间地址不变
  3. Car.prototype.name = "Mazda";
  4. var car1 = new Car();
  5. // Car.prototype.name = "Benz";
  6. // 构造函数的原型指向新的对象,新的空间地址
  7. Car.prototype={
  8. name:'Benz'
  9. }
  10. console.log()
  11. var car2=new Car()
  12. console.log(car1.name); // 'Mazda'
  13. console.log(car1);
  14. console.log(car2)

image.png

三、闭包立即执行函数


return形成闭包,将函数内部的AO返回到全局。

  1. function test() {
  2. var a = 1;
  3. function plus1() {
  4. a++;
  5. console.log(a);
  6. }
  7. return plus1;
  8. }
  9. var plus = test();
  10. plus();
  11. plus();
  12. plus();
  1. function test() {
  2. var a = 1;
  3. function plus1() {
  4. a++;
  5. console.log(a);
  6. }
  7. return plus1;
  8. }
  9. var plus = test();
  10. plus();//2
  11. plus();
  12. plus();//4
  13. var plus1=test()
  14. plus1()//2
  15. plus1()
  16. plus1()
  17. plus1()//5

window,将属性和方法挂到全局对象window上,实现全局访问。
实现和return一样的闭包效果

  1. function abc() {
  2. window.a = 3;
  3. }
  4. abc();
  5. console.log(a); // 3
  6. function test() {
  7. var a = 1;
  8. function add() {
  9. a++;
  10. console.log(a);
  11. }
  12. window.add1 = add;
  13. }
  14. test(); // 执行后,可以在全局环境下访问到add方法
  15. add1();
  16. add1();
  17. add1();
  1. function test(){
  2. var a=1;
  3. function add(){
  4. a++;
  5. console.log(a)
  6. }
  7. window.add1=add;
  8. window.add2 = add
  9. }
  10. test()
  11. add1()//2
  12. add1()
  13. add1()
  14. add2()//5

IIFE,声明一个全局变量接收函数返回值,或者直接挂载到window对象上。

  1. var add1 = (function () {
  2. var a = 1;
  3. function add() {
  4. a++;
  5. console.log(a);
  6. }
  7. return add;
  8. })();
  9. add1()
  10. add1()
  11. //-----------------------------------------------------------------------------------------
  12. ;(function () {
  13. var a = 1;
  14. function add() {
  15. a++;
  16. console.log(a);
  17. }
  18. window.add = add;
  19. })();
  20. add();
  21. add();
  22. add();

四、插件开发

因为es5没有块级作用域,防止变量污染,防止全局变量污染,只有window.Test变量是全局的
在前面写;可以,在后面写也可以,在前面写防止忘了

  1. ;(function () {
  2. function Test() { }
  3. Test.prototype = {}
  4. window.Test = Test;
  5. })();
  6. var test = new Test();

都不写;可能也行,但最好写
Test是构造函数,可以生成多个对象
相当于全局有一个Test函数或类,可以直接用,必须实例化

  1. ; (function () {
  2. function Handphone(color, brand, system) {
  3. this.color = color
  4. this.brand = brand;
  5. this.system = system;
  6. }
  7. Handphone.prototype = {
  8. rom: '64G',
  9. ram: '6G',
  10. screen: '18:9',
  11. call: function () {
  12. console.log('')
  13. }
  14. }
  15. window.Handphone = Handphone;
  16. })()
  17. var handphone=new Handphone()
  18. var handphone1=new Handphone()

五、作业

写一个插件,任意传两个数字,调用插件内部方法可进行加减乘除功能

  1. ;(function () {
  2. function Compute(opt) {
  3. this.x = opt.firstNum || 0;
  4. this.y = opt.secondNum || 0;
  5. }
  6. Compute.prototype = {
  7. plus: function () {
  8. return this.x + this.y;
  9. },
  10. minus: function () {
  11. return this.x - this.y;
  12. },
  13. mul: function () {
  14. return this.x * this.y;
  15. },
  16. div: function () {
  17. return this.x / this.y;
  18. }
  19. }
  20. window.Compute = Compute;
  21. })();
  22. var compute = new Compute({
  23. firstNum: 1,
  24. secondNum: 2
  25. });
  26. console.log(compute.plus());
  27. console.log(compute.minus());
  28. console.log(compute.mul());
  29. console.log(compute.div());

写函数思考
1函数功能、用处?传入两个数字,返回数字的运算结果
2参数传入什么?两个数字
3返回什么?根据调用方法返回东西

  1. ;(function() {
  2. function Compute(opt) {
  3. this.x = opt.x;
  4. this.y = opt.y;
  5. }
  6. Compute.prototype={
  7. add:function() {
  8. return this.x+this.y;
  9. },
  10. minus(){
  11. return this.x - this.y
  12. }
  13. }
  14. window.Compute = Compute
  15. })()
  16. var compute=new Compute({x:1,y:5})
  17. console.log(compute.add())//6
  18. console.log(compute.minus())//-4