天天看点

js学习之旅(十一)原型/原型链/call/apply

原型

  1. 定义:原型是function对象的一个属性,他定义了构造函数制造出的对象的公共祖先.通过该构造函数的对象,可以继承该原型的属性和方法.原型也是对象.
  2. 利用原型特点和概念,可以提取共有属性
  3. 对象如何查看原型–> 隐式属性 proto
  4. 对象如何查看对象的构造函数–> constructor

// 1. 原型对象的公共祖先

function Cat() {}
    
    function Dog() {}
    
    Dog.prototype 
    Cat.prototype
	
           

// 2.原型是一个对象,

Cat.prototype = {
        lastName : 'cat',
        cry : function () {
            document.write('喵喵喵...');
        }
    };

    Dog.prototype.lastName = 'dog';
    Dog.prototype.cry = function () {
        document.write('汪汪汪...')
    }

    function Cat() {
    }
    function Dog() {

    }
    
           

// 3.通过该构造函数的对象,可以继承该原型的属性和方法

Cat.prototype = {
        lastName : 'cat',
        cry : function () {
            document.write('喵喵喵...');
        }
    };

    Dog.prototype.lastName = 'dog';
    Dog.prototype.cry = function () {
        document.write('汪汪汪...')
    }

    function Cat() {
    }
    function Dog() {

    }
    var cat = new Cat();
    var cat1 = new Cat();
    var dog = new Dog();
    console.log(cat.lastName); // cat
    console.log(cat1.lastName); // cat    
    console.log(dog.lastName); // dog
    cat.cry();
    cat1.cry();
    dog.cry();
 
           

// 4.通过该构造函数的对象(以下简称对象),不可以修改/删除/赋值 继承该原型(以下简称原型)的属性和方法;对象的属性和方法与原型有相同属性和方法时,读取的为对象属性和方法;

Cat.prototype = {
        lastName : 'cat',
        cry : function () {
            document.write('喵喵喵...');
        }
    };

    Dog.prototype.lastName = 'dog';
    Dog.prototype.cry = function () {
        document.write('汪汪汪...')
    }

    function Cat() {
    }
    function Dog() {

    }
    var cat = new Cat();
    var cat1 = new Cat();
    var dog = new Dog();
    cat.lastName = 'catt';
    //
    console.log(Cat.prototype.lastName);// cat
    console.log(cat.lastName);  // catt

    Cat.prototype.lastName = 'cattt';
    console.log(Cat.prototype.lastName);// cattt
    console.log(cat.lastName);  // catt
 
           

// 5. 对象的构造函数constructor

function Cat() {}

    function Dog() {

    }
    var cat = new Cat();
    var dog = new Dog();

    console.log(cat.constructor);//ƒ Cat() {}
	// constructor 并不是我们定义的,那么他是哪儿来的呢?由以上知识点猜测:继承
	// 如果有一天找不到cat的构造方法了,可以通过cat.constructor去找寻
	console.log(Cat.prototype);	// 果真有constructor 见图一
           

图一

js学习之旅(十一)原型/原型链/call/apply

// 6. 对象的构造函数可以改变

function Dog() {}
    function Cat() {}
    var cat = new Cat();
    var dog = new Dog();

    console.log(cat.constructor);//ƒ Cat() {}

    console.log(Cat.prototype);

    Cat.prototype = {
        constructor : Dog
    };
    var cat1 = new Cat();
    console.log(cat.constructor);//ƒ Cat() {}
    console.log(cat1.constructor);//ƒ Dog() {}
           

// 7, proto

// 隐式的this,中有一个属性,指向的是改对象的原型
	function Dog() {
        // var this = {
        //     __proto__ : Dog.prototype
        // }

    }
           

// 8. proto 指向是可以更改的

Cat.prototype.name = 'cat';
    function Cat() {
        // var this = {
        //     __proto__ : Cat.prototype
        // }

    }

    var Obj = {
        name : 'obj'
    };

    var cat = new Cat();
    cat.__proto__ = Obj;

    console.log(cat.name);// obj

           

// 9. prototype修改方式遇到的问题

// 1.属性值更改
    Person.prototype.name = 'sunny';
    function Person() {
    }
    Person.prototype.name = 'cherry';
    var p = new Person();
    console.log(p.name);// cherry


	// 2.原型更改
    Person.prototype.name = 'sunny';
    function Person() {
    }
    var p = new Person();
    Person.prototype = {
        name : 'cherry'
    };
    console.log(p.name);// sunny

	var p1 = new Person();
	console.log(p1.name);// cherry
	
	// Person.prototype.name 是属性值的更改
	// 而Person.prototype = {} 是Person中隐式的this里面__proto__ 属性引用的更改.引用更改了,但是p的引用指向还是原来的引用值,在生成的p1是新引用的产物

	// 3.
    var obj = {name : 'a'};
    var obj1 = obj
    obj = {name : 'b'};
    console.log(obj.name); // b
    console.log(obj1.name);// b
    // ----
	Person.prototype = {name : 'a'};
	__proto__ = Person.prototype;
	Person.prototyp = {name : 'b'};

	// 4.
    Person.prototype.name = 'sunny';
    function Person() {
    }
    Person.prototype = {
        name : 'cherry'
    };
    var p = new Person();
    
    // 哈哈,改了两遍才new,new才生成this
    console.log(p.name);// cherry
	

           

原型链

  1. 如何构成原型链
  2. 原型链上属性的增删改查
  3. 绝大多数对象的最终都会继承自Object.prototype
  4. Object.create(原型);

// 10. 原型链

// Grand.prototype.__protto__ = Object.prototype
    Grand.prototype.lastName = 'Deng';
    function Grand(){

    }
    
    var grand = new Grand();

    Father.prototype = grand;
    function Father() {
        this.name = 'xuming';

    }

    var father = new Father();

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

    var son = new Son();

    console.log(son.hobbit);
    console.log(son.name);
    console.log(son.lastName);

	// 1.
    Grand.prototype.lastName = 'Deng';
    function Grand(){

    }

    var grand = new Grand();

    Father.prototype = grand;
    function Father() {
        this.name = 'xuming';
        this.fortune = {
            card1 : 'visa'
        }

    }

    var father = new Father();

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

    var son = new Son();

    // son.fortune = 'one';
    // console.log(son.fortune);
    // console.log(son);
    son.fortune.card2 = 'icbc';
    console.log(son.fortune);
    console.log(father);
	
	
	// 2.
	
    Grand.prototype.lastName = 'Deng';
    function Grand(){}

    var grand = new Grand();

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

    }

    var father = new Father();

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

    var son = new Son();
    son.num ++ ;
    console.log(father.num);// 100
    console.log(son.num); // 101



           

// 11. 父类方法子类调用变量隶属问题

// 1.
    Person.prototype = {
        name : 'a',
        sayName : function () {
            console.log(this.name);
        }
    };

    function Person() {
       this.name = 'b'
    }
    var person = new Person();

    person.sayName(); // a

	// a.sayName() sayName里面的this指向是:谁调用的这个方法中,this就指向谁
	// 2.
    Person.prototype = {
        name : 'a',
        sayName : function () {
            console.log(this.name);
        }
    };

    function Person() {
        this.name = 'b'
    }
    var person = new Person();

    person.sayName(); // b
    Person.prototype.sayName(); // a

           

// 12. 创建

// 自变量
    var obj = {}; // -->new Object();

    // 最好别用
    var obj1 = new Object();

    // var obj2 = Object.create(原型);
    var Objj = {name : 'sunny', age : 123};
    var obj3 = Object.create(Objj);


           
// 1.
    // var obj = Object.create(原型) null/对象
    Person.prototype.name = 'sunny';
    function Person() {}
    var person = Object.create(Person.prototype);

	// 2.
    // Object.create(原型); 创建出来的对象,没有继承Object.prototype
    var obj = Object.create(null);

    obj.toString(); // 报错

    // 3. 自己设置__proto__
    obj.__proto__ = {name : 'sunny'};
    // 不存在继承
    console.log(obj.name); // undefined

// undefined 和 null 为啥没有toString()方法
// 1. undefined 和 null 为原始值
// 2. undefined 和 null 没有包装类 
// 3. undefined 和 null 没有原型
// ** 数字 有包装类哦
           

toString();

true.toString();

    var num = 123;
    num.toString();// 123
    var obj = {};
    obj.toString(); // "[object Object]"
    
    // 对比返回值思考
    // -- > new Number(num).toString();
    // Number 中是有自己的prototype 他将Object中的prototype 进行了重写
    // Number.prototype.toString = function () {};
    // Number.prototype.__proto__ = Object.prototype



	// 重写的
	// Object.prototype.toString
	// Number.prototype.toString
	// Array.prototype.toString
	// Boolean.prototype.toString
	// String.prototype.toString	

	
	console.log(Object.prototype.toString.call(123))// [object Number]		

           

// 衍生:重写

// 2. 重写
    Person.prototype = {
        toString : function () {
            return 'chongxie'
        }
    };
    function Person() {
    }
    var person = new Person();
    console.log(person.toString());// chongxie
 
    // 3. 重写Object内toString()
    Object.prototype.toString = function () {
        return 'Object chongxie';
    }

    function Person() {
    }
    var person = new Person();

    console.log(person.toString());// Object chongxie



           

document.write()

var num = 123;
    document.write(num);    // 123

    var obj = {};
    document.write(obj);    // [object Object]

    var objC = Object.create(null);
    document.write(objC);// 报错 document.write 调用的是原型中toString的方法

    var obj1 = Object.create(null);
    obj1.toString = function () {
        return '测试是否调用toString()';
    };
    document.write(obj1);
           

call/apply

call和apply的相同点:改变this指向

改变this指向

call和apply的不同点:传参列表不同

  1. call 需要把实参按着形参的个数传进去
  2. apply 只能传一个arguments

// 方法调用 之call

function test() {
		console.log('aa');
	}
	test.call();
    test(); // 也可以这样执行 --> test.call();
           

// call 改变this指向

function Person(name, age) {
        this.name = name;
        this.age = age;
    }

    var person = new Person('yang', 100);
    var obj = {};

    console.log(person);

    Person.call(obj, 'deng', 80);       // 他会让Person中的this全部指向obj
    console.log(obj);       // {name: "deng", age: 80} 利用别人的额方法 实现了自己的功能

   // Person 相当于工厂
           

// 应用

function Person(name, age, sex) {
        this.name = name;
        this.age = age;
        this.sex = sex;
    }

    function Student(name, age, sex, tel, grade) {
        // Person.call(Student, name, age, sex); 不对哦
        Person.call(this, name, age, sex);
        this.tel = tel;
        this.grade = grade;
    }

    var student = new Student('sunny', 123, 'male', 139, 2017);
    console.log(student);

           
function Wheel(wheelSize, style) {
        this.style = style;
        this.wheelSize = wheelSize;


    }

    function Sit(c, sitColor) {
        this.c = c;
        this.sitColor = sitColor;

    }

    function Model(height, width, len) {
        this.height = height;
        this.width = width;
        this.len = len;

    }

    function Car(wheelSize, style, c, sitColor, height, width, len) {
        Wheel.call(this, wheelSize, style);
        Sit.call(this, c, sitColor);
        Model.call(this, height, width, len);
    }

    function CarApply(wheelSize, style, c, sitColor, height, width, len) {
        Wheel.apply(this, [wheelSize, style]);
        Sit.apply(this, [c, sitColor]);
        Model.apply(this, [height, width, len]);

    }

    var car = new Car(100, '漂亮', '真皮', 'red', 1000, 1000, 4000 );

    var carApply = new CarApply(100, '漂亮', '真皮', 'red', 1000, 1000, 4000 );
    console.log(car);
    console.log(carApply);

           

继续阅读