JavaScript 对象 原型 原型链


对象的创建方法

  1. var obj = {} plainObject 对象字面量/对象直接量
  2. 构造函数
    1. 系统自带的构造函数 new Object()
    2. 自定义函数 new FunctionName()

自定义函数用大驼峰式命名 (所有首字母大写)

构造函数内部原理

  1. 在函数体最前面隐式加上this={}
  2. 执行this.xxx = xxx;
  3. 隐式的返回this

也可以传参

    function Car(number){
    
    
        // this = {};
        this.date = 2020;
        this.number = number;

        //return this;
    }

    new car1 = new Car(1);

包装类

  • new Number()
  • new String()
  • new Boolean()

原始类型没有 属性和方法
调用时实际上自动变成包装类

    //包装类
    var a = 1;

    a.abc = 2;
    // 不忍心报错  自动执行 
    // new Number(1).len = 2;  delete  执行完又删除了

    
    console.log(a.len); // undefined
    // 发现访问属性又自动创建 new Number(4).len  是空的 

字符串有 .length 属性
过程和上面一样

    var str = 'abcd';

    str.length = 2;
    // nwe String('abcd').length = 2;  delete
    
    console.log(str);  // 4
    // new String('abcd').length  本身这个属性是存在的

ps. 渡一 《对象,包装类(下)》后半部分练题

原型

.prototype – 原型 是祖先


    Person.prototype.name= 'hello';
    function Person{
    
    

    }
    var a = new Person();
    console.log(a.name);   // 输出 hello 继承自原型

原型也是对象 可以这样写

    Person.prototype = {
    
    
        name : 'hello'
    }
    ...
    方别写很多

但稍微有区别 后面提到

定义

原型是function对象的一个属性,定义了构造函数 制造出的 对象的公共祖先
通过该构造函数产生的对象可以继承该原型的属性和方法
原型也是对象

功能

减少代码重复
共同部分放进原型中

修改原型

增 删 改 查
只能直接操作prototype操作

不能通过子元素操作

    function Father(){
    
    
        this.num = 1;
    }
    var father = new Father();

    Son.prototype = father;
    function Son(){
    
    
        
    }
    var son = new Son();

    son.num = 2;  
    //son.num ++;   同

    console.log(father.num);  // 1

相当于给son新添加了num属性
father中的属性没有修改 也 没法修改(误)
但这种可以

    function Father(){
    
    
        this.num = 1;
        this.say = {
    
    
            name : 'niko'
        }
    }
    var father = new Father();

    Son.prototype = father;
    function Son(){
    
    
        
    }
    var son = new Son();

    son.say.name = 'dio';   // 二次调用 .name


    console.log(son.say.name);  // dio

成功修改 只能修改方法中的属性 相当于二次调用

constructor

系统自带原型有 constructor 属性
返回构造函数
但可以手动更改

    

_proto_

_proto_指向原型
连接原型和子对象
找不到属性后 找_proto_中的属性

_proto_ 默认储存的原型
但可以修改

两种写法区别

在二次修改时产生区别

    Person.prototype.name = 'hello';

    function Person(){
    
    
        // 系统自动执行 var this = {_proto_ : Person.prototype}
    }

    var person = new Person();

//两种修改方式
// 1.   Person.prototype.name = 'wow';
// 2.   Person.prototype = {
    
    
//       name : 'wow'
//    }
  1. 成功修改 相当于直接改了空间内的数据

  2. Person.prototype.name 还是 hello
    这波啊这波是 创建新空间 注意构造函数中的注释 引用的是_proto_ 的指向
    方便理解:

    var obj = {
    
    name : 'a'};
    var obj1 = obj ;
    obj = {
    
    name : 'b'};   //  obj1 指向的还是a

    Person.prototype = {
    
    name : 'a'};
    _proto_ = Person.prototype;
    Person.prototype = {
    
    name : 'b'};

换了个空间

1改房间中属性
2直接换房间

注意刚才的顺序!!

    Person.prototype.name = 'hello';

    function Person(){
    
    
        // 系统自动执行 var this = {_proto_ : Person.prototype}
    }

    Person.prototype = {
    
    
       name : 'wow'
    }

    var person = new Person();

现在成功修改 new在后面

原型链

原型链构成就不用我多说了吧

增删改查

同上面原型

this 小知识

    Son.prototype = {
    
    
        name : 'niko',
        sayName : function (){
    
    
            console.log(this.name);
        }  
    }

    function Son () {
    
    
        this.name = 'dio';
    }

    var son = new Son();   // dio

this 指向调用方法的人 此处是 son 调用

Object.create(原型)

更方便的构建

    var obj = {
    
    name : 'sunny' , age : 123};
    var obj1 = Object.create(obj);  // obj1 原型就是obj  可以使用name和age

    等同于
    
    Obj.prototype.name = 'sunny';
    function Obj() {
    
    

    }
    var obj1 = new Obj();
    //var obj1 = Object.creat(Obj.prototype);  和上面相等  构造函数是空的就一样

绝大多数 对象最终端都是 Object.prototype

原型链终端 Object.prototype
里面有toString 等方法 (包装类也有自己的toString)

注意绝大多数,有特例,用Object.creat() 构造时
原型可以是 null

    var obj = Object.creat(null);

就没有Object.prototype 中的属性方法了
设置为null之后 人为的添加 _proto_ 无法使用
(睡前疑问) _proto_ 和 .prototype

toString 重写

123.toString报错 点识别成浮点型数字 得赋值给变量 借助中间量调用
123的toString不是Object的 是 Number自己的方法

    var num = 123;
    num.toString();   --> // new Number(num).toString();
    
    Number.prototype.toString = function(){
    
    }   --> 有自己的toString
    Number.prototype._proto_=Object.prototype

这种情况叫 方法重写 : 同名方法实现不同功能 z
在原型链 前端 覆盖

调用 document.write(xx); 时 调用toSting(); 方法

题外话 精度

js可正常计算的范围 小数点前16位 后16位

call / apply

作用 改变 this 指向
目的是 把执行函数里的this改变成传入的对象
区别 传参列表不同

    var name = "1";
    var obj = {
    
    
        name:2,
        prop: {
    
    
            name:3,
            getName: function() {
    
    
                return this.name;
            }
        }
    }
    console.log(obj.prop.getName()); //3
    console.log(obj.prop.getName.call(obj)); //2
    console.log(obj.prop.getName.call(this)); //1  在全局的this 是window

如果想得到3 直接 obj.prop.getName() 即可,这事方法的当前对象是prop

如果想得到2 我们可以 obj.prop.getName.call(obj) 就是把obj对象传到方法内,这时候的this对象是obj, this.name 等同于obj.name

1也是同理 obj.prop.getName.call(this) 这里的this是当前页面 传window也是一样的

当然也可以使用apply, apply 和 call 的不同在于call,就是call方法接受的是若干个参数的列表,而apply方法接受的是一个包含多个参数的数组。 apply(thisargs,[])用数组给方法传递参数, call(this, param1,param2); 下面一个小例子

    function callTest(name, price) {
    
    
        console.info(name + "-" + price);
    }
    callTest.call(this, 'superbing', 100);
 
    callTest.apply(this, ['superbing', 200]);

实用示例

借用别人的函数实现自己的功能

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

    function Student(name,age,sex,tel,grade){
    
    
        // var this ={}   等待赋值
        Person.call(this,name,age,sex);
        this.tel = tel;
        this.grade = grade;
    }

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

把Student对象传到Person里 使Person中的this实际上指的是Student中的变量
相当于把Person的三句拿到Student里了
别人的构造完全符合自己的时候简写

prototype 和 proto

这个不错

猜你喜欢

转载自blog.csdn.net/S_aitama/article/details/107393260