JavaScript函数原型链知识记录

1 构造函数

构造函数是专门用于创建对象的
function Person(myName, myAge) {
            // let obj = new Object();  // 系统自动添加的
            // let this = obj; // 系统自动添加的
            this.name = myName;
            this.age = myAge;
            this.say = function () {
                console.log("hello world");
            }
            // return this; // 系统自动添加的
        }
1.当我们new Person("lnj", 34);系统做了什么事情1.1会在构造函数中自动创建一个对象1.2会自动将刚才创建的对象赋值给this1.3会在构造函数的最后自动添加return this;
        let obj1 = new Person("lnj", 34);
        let obj2 = new Person("zs", 44);
        console.log(obj1);
        console.log(obj2);

构造函数的优化:

上面构造函数的定义有一个弊端,如下

let obj1 = new Person("lnj", 34);let obj2 = new Person("zs", 44); 由于两个对象中的say方法的实现都是一样的, 但是保存到了不同的存储空间中 所以有性能问题console.log(obj1.say === obj2.say); // false

通过三个等号来判断两个函数名称, 表示判断两个函数是否都存储在同一块内存中

优化方式1:

function mySay() {
            console.log("hello world");
        }
        function Person(myName, myAge) {
            // let obj = new Object();  // 系统自动添加的
            // let this = obj; // 系统自动添加的
            this.name = myName;
            this.age = myAge;
            this.say = mySay;
            // return this; // 系统自动添加的
        }
        let obj1 = new Person("lnj", 34);
        let obj2 = new Person("zs", 44);
        console.log(obj1.say === obj2.say); // true

但是这种方式也是有弊端的,

1.1阅读性降低了1.2污染了全局的命名空间

优化方式2:

function Person(myName, myAge) {
            // let obj = new Object();  // 系统自动添加的
            // let this = obj; // 系统自动添加的
            this.name = myName;
            this.age = myAge;
            // this.say = fns.mySay;
            // return this; // 系统自动添加的
        }
        Person.prototype = {
            say: function () {
                console.log("hello world");
            }
        }
        let obj1 = new Person("lnj", 34);
        obj1.say();
        let obj2 = new Person("zs", 44);
        obj2.say();
        console.log(obj1.say === obj2.say); // true

通过改写构造函数的 原型对象,让方法say变得公用

3 prototype特点:

1.1存储在prototype中的方法可以被对应构造函数创建出来的所有对象共享1.2prototype中除了可以存储方法以外, 还可以存储属性1.3prototype如果出现了和构造函数中同名的属性或者方法, 对象在访问的时候, 访问到的是构造函中的数据

2.prototype应用场景

prototype中一般情况下用于存储所有对象都相同的一些属性以及方法
如果是对象特有的属性或者方法, 我们会存储到构造函数中
function Person(myName, myAge) {
            this.name = myName;
            this.age = myAge;
            this.currentType = "构造函数中的type";
            this.say = function () {
                console.log("构造函数中的say");
            }
        }
        Person.prototype = {
            currentType: "人",
            say: function () {
                console.log("hello world");
            }
        }
        let obj1 = new Person("lnj", 34);
        obj1.say();
        console.log(obj1.currentType);
        let obj2 = new Person("zs", 44);
        obj2.say();
        console.log(obj2.currentType);

4  prototype,constructor, __proto__的三角恋关系

1.每个"构造函数"中都有一个默认的属性, 叫做prototype  prototype属性保存着一个对象, 这个对象我们称之为"原型对象"2.每个"原型对象"中都有一个默认的属性, 叫做constructor  constructor指向当前原型对象对应的那个"构造函数"3.通过构造函数创建出来的对象我们称之为"实例对象"  每个"实例对象"中都有一个默认的属性, 叫做__proto__  __proto__指向创建它的那个构造函数的"原型对象"
function Person(myName, myAge) {
            this.name = myName;
            this.age = myAge;
        }
        let obj1 = new Person("lnj", 34);

        console.log(Person.prototype);
        console.log(Person.prototype.constructor);
        console.log(obj1.__proto__);

5 Function函数

1.JavaScript中函数是引用类型(对象类型), 既然是对象,  所以也是通过构造函数创建出来的,"所有函数"都是通过Function构造函数创建出来的对象

2.JavaScript中只要是"函数"就有prototype属性 "Function函数"的prototype属性指向"Function原型对象"

3.JavaScript中只要"原型对象"就有constructor属性  "Function原型对象"的constructor指向它对应的构造函数

4.Person构造函数是Function构造函数的实例对象, 所以也有__proto__属性  Person构造函数的__proto__属性指向"Function原型对象"

5 Object函数

1. JavaScript函数是引用类型(对象类型), 所以Function函数也是对象

2."Function构造函数"也是一个对象, 所以也有__proto__属性  "Function构造函数"__proto__属性指向"Function原型对象"

3. JavaScript中还有一个系统提供的构造函数叫做Object   只要是函数都是"Function构造函数"的实例对象

4.只要是对象就有__proto__属性, 所以"Object构造函数"也有__proto__属性  "Object构造函数"的__proto__属性指向创建它那个构造函数的"原型对象"

5.只要是构造函数都有一个默认的属性, 叫做prototype  prototype属性保存着一个对象, 这个对象我们称之为"原型对象"

6.只要是原型对象都有一个默认的属性, 叫做constructor  constructor指向当前原型对象对应的那个"构造函数"

function Person(myName, myAge) {
            this.name = myName;
            this.age = myAge;
        }
        let obj1 = new Person("lnj", 34);
         console.log(Function.__proto__);
         console.log(Function.__proto__ === Function.prototype); // true

         console.log(Object);
         console.log(Object.__proto__);
         console.log(Object.__proto__ === Function.prototype); // true
         console.log(Object.prototype);
         console.log(Object.prototype.constructor);

         console.log(Object.prototype.constructor === Object); // true
         console.log(Object.prototype.__proto__); // null

6 函数对象关系

1.所有的构造函数都有一个prototype属性, 所有prototype属性都指向自己的原型对象2,所有的原型对象都有一个constructor属性, 所有constructor属性都指向自己的构造函数3.所有函数都是Function构造函数的实例对象4.所有函数都是对象, 包括Function构造函数5.所有对象都有__proto__属性6.普通对象的__proto__属性指向创建它的那个构造函数对应的"原型对象"

7.所有对象的__proto__属性最终都会指向"Object原型对象"

8."Object原型对象"的__proto__属性指向NULL
Object ,Function,实例对象的总图:
function Person(myName, myAge) {
            this.name = myName;
            this.age = myAge;
        }
        let obj1 = new Person("lnj", 34);

        console.log(Function.prototype.__proto__);
        console.log(Person.prototype.__proto__);
        console.log(Function.prototype.__proto__ === Person.prototype.__proto__);//true
        console.log(Function.prototype.__proto__ === Object.prototype);//true
        console.log(Person.prototype.__proto__ === Object.prototype);//true

7 原型链

1.对象中__proto__组成的链条我们称之为原型链2.对象在查找属性和方法的时候, 会先在当前对象查找  如果当前对象中找不到想要的, 会依次去上一级原型对象中查找  如果找到Object原型对象都没有找到, 就会报错
function Person(myName, myAge) {
            this.name = myName;
            this.age = myAge;
            // this.currentType = "构造函数中的type";
            // this.say = function () {
            //     console.log("构造函数中的say");
            // }
        }

        Person.prototype = {
            // 注意点: 为了不破坏原有的关系, 在给prototype赋值的时候, 需要在自定义的对象中手动的添加constructor属性, 手动的指定需要指向谁
            constructor: Person,
            // currentType: "人",
            // say: function () {
            //     console.log("hello world");
            // }
        }
        let obj1 = new Person("lnj", 34);
        // obj1.say();
        console.log(obj1.currentType);
        // console.log(Person.prototype.constructor);

8 属性注意点

 在给一个对象不存在的属性设置值的时候, 不会去原型对象中查找, 如果当前对象没有就会给当前对象新增一个不存在的属性
function Person(myName, myAge) {
            this.name = myName;
            this.age = myAge;
        }
        Person.prototype = {
            constructor: Person,
            currentType: "人",
            say: function () {
                console.log("hello world");
            }
        }
        let obj = new Person("lnj", 34);
        // console.log(obj.currentType); // "人"
        // console.log(obj.__proto__.currentType); // "人"

        // 注意点: 在给一个对象不存在的属性设置值的时候, 不会去原型对象中查找, 如果当前对象没有就会给当前对象新增一个不存在的属性
        obj.currentType = "新设置的值";
        console.log(obj.currentType); // 新设置的值
        console.log(obj.__proto__.currentType); // "人"

9 js三大特性之一-封装性

1.局部变量和局部函数无论是ES6之前还是ES6, 只要定义一个函数就会开启一个新的作用域只要在这个新的作用域中, 通过let/var定义的变量就是局部变量只要在这个新的作用域中, 定义的函数就是局部函数

2.什么是对象的私有变量和函数默认情况下对象中的属性和方法都是公有的, 只要拿到对象就能操作对象的属性和方法外界不能直接访问的变量和函数就是私有变量和是有函数构造函数的本质也是一个函数, 所以也会开启一个新的作用域, 所以在构造函数中定义的变量和函数就是私有和函数*//*3.什么是封装?封装性就是隐藏实现细节,仅对外公开接口

4.为什么要封装?4.1不封装的缺点:当一个类把自己的成员变量暴露给外部的时候,那么该类就失去对属性的管理权,别人可以任意的修改你的属性4.2封装就是将数据隐藏起来,只能用此类的方法才可以读取或者设置数据,不可被外部任意修改. 封装是面向对象设计本质(将变化隔离)。这样降低了数据被误用的可能 (提高安全性和灵活性)
function Person() {
            this.name = "lnj";
            // this.age = 34;
            let age = 34;
            this.setAge = function (myAge) {
                if(myAge >= 0){
                    age = myAge;
                }
            }
            this.getAge = function () {
                return age;
            }
            this.say = function () {
                console.log("hello world");
            }
            /*
            // 由于构造函数也是一个函数, 所以也会开启一个新的作用域
            // 所以在构造函数中通过var/let定义的变量也是局部变量
            // 所以在构造函数中定义的函数也是局部函数
            var num = 123;
            let value = 456;
            function test() {
                console.log("test");
            }
            */
        }
        let obj = new Person();
        // 结论: 默认情况下对象的属性和方法都是公开的, 只要拿到对象就可以操作对象的属性和方法
        // console.log(obj.name);
        // obj.age = -3;
        // console.log(obj.age);
        // obj.say();

        // console.log(age);
        obj.setAge(-3);
        console.log(obj.getAge());

10 私有属性注意点

 在给一个对象不存在的属性设置值的时候, 不会去原型对象中查找, 如果当前对象没有就会给当前对象新增一个不存在的属性 由于私有属性的本质就是一个局部变量, 并不是真正的属性, 所以如果通过 对象.xxx的方式是找不到私有属性的, 所以会给当前对象 

11 属性方法分类

1.在JavaScript中属性和方法分类两类1.1实例属性/实例方法在企业开发中通过实例对象访问的属性, 我们就称之为实例属性在企业开发中通过实例对象调用的方法, 我们就称之为实例方法1.2静态属性/静态方法在企业开发中通过构造函数访问的属性, 我们就称之为静态属性在企业开发中通过构造函数调用的方法, 我们就称之为静态方法
 function Person() {
            this.name = "lnj";
            this.say = function () {
                console.log("hello world");
            }
        }

        // 通过构造函数创建的对象, 我们称之为"实例对象"
        let obj = new Person();
        console.log(obj.name);
        obj.say();

        obj.age = 34;
        console.log(obj.age);
        obj.eat = function () {
            console.log("eat");
        }
        obj.eat();

        // 构造函数也是一个"对象", 所以我们也可以给构造函数动态添加属性和方法
        Person.num = 666;
        Person.run = function () {
            console.log("run");
        }
        console.log(Person.num);
        Person.run();

12 bind call apply

1.this是什么?谁调用当前函数或者方法, this就是谁*/

/*2.这三个方法的作用是什么?这三个方法都是用于修改函数或者方法中的this的2.1.bind方法作用修改函数或者方法中的this为指定的对象, 并且会返回一个修改之后的新函数给我们注意点: bind方法除了可以修改this以外, 还可以传递参数, 只不过参数必须写在this对象的后面2.2.call方法作用修改函数或者方法中的this为指定的对象, 并且会立即调用修改之后的函数注意点: call方法除了可以修改this以外, 还可以传递参数, 只不过参数必须写在this对象的后面2.3.apply方法作用修改函数或者方法中的this为指定的对象, 并且会立即调用修改之后的函数注意点: apply方法除了可以修改this以外, 还可以传递参数, 只不过参数必须通过数组的方式传递
let obj = {
            name: "zs"
        }

         function test(a, b) {
             console.log(a, b);
             console.log(this);
         }
         test(10, 20);
         window.test();
         let fn = test.bind(obj, 10, 20);
         fn();

         test.call(obj, 10, 20);

         test.apply(obj, [10, 20]);

        function Person() {
            this.name = "lnj";
            this.say = function () {
                console.log(this);
            }
        }
        let p = new Person();
         p.say();
         let fn = p.say.bind(obj);
         fn();
         p.say.call(obj);
        p.say.apply(obj);

13 js三大特性之继承性

方式一:

function Person() {
            this.name = null;
            this.age = 0;
            this.say = function () {
                console.log(this.name, this.age);
            }
        }
        let per = new Person();
        per.name = "lnj";
        per.age = 34;
        per.say();

        // 在企业开发中如果构造函数和构造函数之间的关系是is a关系, 那么就可以使用继承来优化代码, 来减少代码的冗余度
        // 学生 is a 人 , 学生是一个人
        function Student() {
            // this.name = null;
            // this.age = 0;
            // this.say = function () {
            //     console.log(this.name, this.age);
            // }
            this.score = 0;
            this.study = function () {
                console.log("day day up");
            }
        }
        Student.prototype = new Person();
        Student.prototype.constructor = Student;

        let stu = new Student();
        stu.name = "zs";
        stu.age = 18;
        stu.score = 99;
        stu.say();
        stu.study();

弊端:

调用子类构造函数创建对象的时候,无法访问父类的属性

 function Person(myName, myAge) {
            this.name = myName;
            this.age = myAge;
            this.say = function () {
                console.log(this.name, this.age);
            }
        }
       // let per = new Person("lnj", 34);
       //  per.say();

        // 学生 is a 人 , 学生是一个人
        function Student(myName, myAge, myScore) {
          //无法访问到父类的属性
            this.score = myScore;
            this.study = function () {
                console.log("day day up");
            }
        }

        // let stu = new Student();
        // stu.name = "zs";
        // stu.age = 18;
        // stu.score = 99;
        // stu.say();
        // stu.study();

方式二:

function Person(myName, myAge) {
            // let per = new Object();
            // let this = per;
            // this = stu;
            this.name = myName; // stu.name = myName;
            this.age = myAge; // stu.age = myAge;
            this.say = function () { // stu.say = function () {}
                console.log(this.name, this.age);
            }
            // return this;
        }
        function Student(myName, myAge, myScore) {
            // let stu = new Object();
            // let this = stu;
            Person.call(this, myName, myAge); //  Person.call(stu);
            this.score = myScore;
            this.study = function () {
                console.log("day day up");
            }
            // return this;
        }
        let stu = new Student("ww", 19, 99);
        // stu.name = "zs";
        // stu.age = 18;
        // stu.score = 99;
        console.log(stu.score);
        stu.say();
        stu.study();

弊端:访问不到 父类 原型对象 中的属性和方法

方式三:

 function Person(myName, myAge) {
            // let per = new Object();
            // let this = per;
            // this = stu;
            this.name = myName; // stu.name = myName;
            this.age = myAge; // stu.age = myAge;
            this.sex = 1;
            // this.say = function () { // stu.say = function () {}
            //     console.log(this.name, this.age);
            // }
            // return this;
        }
        Person.prototype.say = function () {
            console.log(this.name, this.age);
        }

        function Student(myName, myAge, myScore) {
            Person.call(this, myName, myAge);
            this.score = myScore;
            this.study = function () {
                console.log("day day up");
            }
        }
        // 注意点: 要想使用Person原型对象中的属性和方法, 那么就必须将Student的原型对象改为Person的原型对象才可以
        Student.prototype = Person.prototype;
        Student.prototype.constructor = Student;

        let stu = new Student("ww", 19, 99);
        console.log(stu.score);
        stu.say();
        stu.study();

弊端:让子类的原型对象和父类的原型对象是一个,如果在其中一个 修改原型对象,会影响另一个

方式四:终极方案

1.js中继承的终极方法1.1在子类的构造函数中通过call借助父类的构造函数1.2将子类的原型对象修改为父类的实例对象
function Person(myName, myAge) {
            // let per = new Object();
            // let this = per;
            // this = stu;
            this.name = myName; // stu.name = myName;
            this.age = myAge; // stu.age = myAge;
            // return this;
        }
        Person.prototype.say = function () {
            console.log(this.name, this.age);
        }
        function Student(myName, myAge, myScore) {
            Person.call(this, myName, myAge);
            this.score = myScore;
            this.study = function () {
                console.log("day day up");
            }
        }
        /*
        弊端:
        1.由于修改了Person原型对象的constructor属性, 所以破坏了Person的三角恋关系
        2.由于Person和Student的原型对象是同一个, 所以给Student的元素添加方法, Person也会新增方法
         */
        // Student.prototype = Person.prototype;

        Student.prototype = new Person();
        Student.prototype.constructor = Student;
        Student.prototype.run = function(){
            console.log("run");
        }

        let per = new Person();
        per.run();

14 js三大特性之多态性

 /*
        1.什么是强类型语言, 什么是是弱类型语言
        1.1什么是强类型语言:
        一般编译型语言都是强类型语言,
        强类型语言,要求变量的使用要严格符合定义
        例如定义 int num; 那么num中将来就只能够存储整型数据
        1.2什么是弱类型语言:
        一般解释型语言都是弱类型语言,
        弱类型语言, 不会要求变量的使用要严格符合定义
        例如定义 let num; num中既可以存储整型, 也可以存储布尔类型等
        1.3由于js语言是弱类型的语言, 所以我们不用关注多态

        2.什么是多态?
        多态是指事物的多种状态
        例如:
        按下 F1 键这个动作,
        如果当前在 webstorm 界面下弹出的就是 webstorm 的帮助文档;
        如果当前在 Word 下弹出的就是 Word 帮助;
        同一个事件发生在不同的对象上会产生不同的结果。

        3.多态在编程语言中的体现
        父类型变量保存子类型对象, 父类型变量当前保存的对象不同, 产生的结果也不同
        */

        // function Animal(myName) {
        //     this.name = myName;
        //     this.eat = function () {
        //         console.log(this.name + " 动物吃东西");
        //     }
        // }
        function Dog() {
            // Animal.call(this, myName);
            this.eat = function () {
                console.log(" 狗吃东西");
            }
        }
        // Dog.prototype = new Animal();
        // Dog.prototype.constructor = Dog;

        function Cat() {
            // Animal.call(this, myName);
            this.eat = function () {
                console.log(" 猫吃东西");
            }
        }
        // Cat.prototype = new Animal();
        // Cat.prototype.constructor = Cat;

        // function feed(Dog animal) {
        //     animal.eat(); // 狗吃东西
        // }
        // function feed(Cat animal) {
        //     animal.eat(); // 猫吃东西
        // }
        // function feed(Animal animal) {
        //     animal.eat(); // 狗吃东西
        // }
        function feed(animal){
            animal.eat();
        }
        let dog = new Dog();
        feed(dog);

        let cat = new Cat();
        feed(cat);


原文地址:https://www.cnblogs.com/xiaonanxia/p/10926617.html

时间: 2024-08-26 21:31:58

JavaScript函数原型链知识记录的相关文章

Javascript的原型链图

90%的前端或者js程序员或者老师们对Javascript懂得不比这个多 给手机看的 但是这个图里的所有褐色单向箭头链就是Javascript的原型链(颜色标注对理解js原型链很关键) 这图中的各个__proto__ constructor .prototype 都是内部对象 这样画是为了简洁 举个例子 如果考虑__proto__ 作为内部对象 上图变为 原型链就是 constructor 和 prototype如果作为内部对象 放到相应的位置 图就变大麻团了 保证晕倒什么也记不住 不服请看 这

JavaScript继承-原型链继承

//原型链继承 function SuperType(){ this.name = 'super'; this.girlFriends = ["xiaoli","xiaowang"]; } SuperType.prototype.sayName = function(){ console.log(this.name); } function SubType(){ this.age = 20; } //创建SuperType的实例赋给SubType的原型 //实现继承

JavaScript对象、原型、原型链知识总结思维导图

这个思维导图是我对Object,原型,原型链等知识的总结,主要参考高程一书第六章,写完才发现这么多,以后可能会进行精简.内容可能会出现差错,欢迎批评指正.下载==>Github ECMAScript支持面向对象(OO)编程,但不使用类或者接口.对象可以在代码执行过程中创建和增强,因此具有动态性而非严格定义的实体.在没有类的情况下,可以采用下列模式创建对象. 工厂模式,使用简单的函数创建对象,为对象添加属性和方法,然后返回对象.这个模式后来被构造函数模式所取代. 构造函数模式,可以创建自定义引用类

JavaScript (JS) 面向对象编程 浅析 (含对象、函数原型链解析)

1. 构造函数原型对象:prototype ① 构造函数独立创建对象,消耗性能 function Person(name) { this.name = name; this.sayHello = function () { console.log("Hello,my name is " + this.name) } } var P1 = new Person("Tom"); var P2 = new Person("Jim"); P1.sayHe

深入浅出JavaScript之原型链&继承

Javascript语言的继承机制,它没有"子类"和"父类"的概念,也没有"类"(class)和"实例"(instance)的区分,全靠一种很奇特的"原型链"(prototype chain)模式,来实现继承. 这部分知识也是JavaScript里的核心重点之一,同时也是一个难点.我把学习笔记整理了一下,方便大家学习,同时自己也加深印象.这部分代码的细节很多,需要反复推敲.那我们就开始吧. 小试身手 原型链

javascript中原型链与instanceof 原理

instanceof:用来判断实例是否是属于某个对象,这个判断依据是什么呢? 首先,了解一下javascript中的原型继承的基础知识: javascript中的对象都有一个__proto__属性,这个是对象的隐式原型,指向该对象的原型对象.显式的原型对象使用prototype,但是Object.prototype.__proto__=null; 判断某个对象a是否属于某个类A的实例,可以通过搜索原型链. //继承机制 function A(){ } A.prototype.name='licu

原型原型链学习记录

这是一篇学习笔记. 个人心得: 关于原型和原型链这一块,很难,但是,一旦理解,就通了. 对于这一块,我之前不懂的时候,非要去弄明白,特别痛苦,之后,看到了王福朋老师的闭包原型系列,真的是茅塞顿开!看完之后,我就拿起JavaScript高程3,高程3第6章节,耐心跟着看也就明白了.之后,再去做一些图解,如果能够根据继承画出所有的关系,没有矛盾的点,那就基本没问题了.再到网上找差不多的文章看,如果没有冲突点,那这一块就没问题了. 参考的内容: http://www.cnblogs.com/wangf

js原型和原型链知识整理

在清楚了js创建对象和new方法的过程之后,再来看原型的概念就容易理解多了. 原型存在的目的是为了能更加节约内存地继承. 我认为原型中主要需要搞清楚这4个概念,显式原型指向什么,隐式原型指向什么,constructor指向什么,原型链是什么. 一图胜千言.下面这张图就解释了所有这些概念. 下面自己总结了一些原型的基本特征,用于加深理解: 1. 在JS里,万物皆对象.方法(Function)是对象,方法的原型(Function.prototype)是对象.因此,它们都会具有对象共有的特点. 即:对

理解Javascript的原型链

要理解原型链,首先要清楚理解以下几点: 1.所有函数都事Function的实例化,都包含prototype属性,即原型对象. 2.所有对象都有__proto__属性,该属性指向对象构造函数的prototype原型对象. 3.prototype原型对象的constructor属性指向它所在的构造函数,即构造函数本身. 4.prototype是针对函数说的,__proto__是针对对象说的. 5.函数本身也是对象. 认识到以上几点,我们先看一下原型链: function setName() { th