都是绑定在使用构造函数建立出来的对象p上; 最终使用的时候也是使用对象p来进行访问;javascript
function Person(name, age, doFunc) { this.name = name; this.age = age; this.doFunc = doFunc; } var p1 = new Person('sz', 18, function () { console.log('sz在上课'); }); var p2 = new Person('王二小', 18, function () { console.log('王二小在放羊'); });
函数本质也是一个对象, 既然是个对象, 那么就能够动态的添加属性和方法java
只要函数存在, 那么绑定在它身上的属性和方法, 也会一直存在编程
eg,记录总共建立了多少我的对象:segmentfault
// 1. 设置一个全局的变量 var personCount = 0; function Person(name, age, doFunc) { this.name = name; this.age = age; this.doFunc = doFunc; personCount++; } var p1 = new Person('sz', 18, function () { console.log('sz在上课'); }); var p2 = new Person('王二小', 18, function () { console.log('王二小在放羊'); }); console.log('总共建立了'+ personCount + '我的'); //2
function Person(name, age, doFunc) { this.name = name; this.age = age; this.doFunc = doFunc; if (!Person.personCount) { Person.personCount = 0; //建立静态属性 } Person.personCount++; } //建立静态方法 Person.printPersonCount = function () { console.log('总共建立了'+ Person.personCount + '我的'); }; var p1 = new Person('sz', 18, function () { console.log('sz在上课'); }); var p2 = new Person('王二小', 18, function () { console.log('王二小在放羊'); }); Person.printPersonCount();
内置对象
• String
• Number
• Boolean
• Object
• Function
• Array
• Date
• RegExp
• Error数组
获取根据本身声明的构造函数建立的对象浏览器
console.info("-->str") var str = "aaa"; console.log(typeof str); //string console.log(str.constructor.name); //String console.log(Object.prototype.toString.call(str)); //[object String] console.info("-->obj") var obj = { 'name': '张三' }; console.log(typeof obj); //object console.log(obj.toString()); //[object Object] console.log(obj.constructor.name); //Object console.log(Object.prototype.toString.call(obj)); //[object Object] console.info("-->arr") var arr = [1, 2, 3]; console.log(typeof arr); //object console.log(arr.toString()); //1,2,3 console.log(arr.constructor.name); //Array console.log(Object.prototype.toString.call(arr)); //[object Array] console.info("-->date") var date = new Date(); console.log(typeof date); //object console.log(date.toString()); //Wed Oct 09 2019 00:08:15 GMT+0800 (中国标准时间) console.log(date.constructor.name); //Date console.log(Object.prototype.toString.call(date)); //[object Date]
仍是使用 实例化对象.constructor.name
函数
function Person(name, age) { // var this = new Object(); 自定义类型系统都把this指向Object,因此Object.prototype.toString.call(...) 获取都是 [object Object] this.name = name; this.age = age; } function Dog(name, age) { this.name = name; this.age = age; } function Cat(name, age) { this.name = name; this.age = age; } // 1. 实例化-->实例 var p = new Person('zs', 18); var d = new Dog('小花', 8); var c = new Cat('小猫', 3); // object console.log(typeof p); console.log(typeof d); console.log(typeof c); // [object Object] console.log(p.toString()); console.log(d.toString()); console.log(c.toString()); // [object Object] console.log(Object.prototype.toString.call(p)); console.log(Object.prototype.toString.call(d)); console.log(Object.prototype.toString.call(c)); console.log(p.constructor.name); //Person console.log(d.constructor.name); //Dog console.log(c.constructor.name); //Cat
类型验证使用 instanceof
post
function Person(name, age) { this.name = name; this.age = age; } function Dog(name, age) { this.name = name; this.age = age; } function Cat(name, age) { this.name = name; this.age = age; } // 1. 实例化-->实例 var p = new Person('zs', 18); var d = new Dog('小花', 8); var c = new Cat('小猫', 3); //true console.log(p instanceof Person); console.log(d instanceof Dog); console.log(c instanceof Cat); //true console.log(p instanceof Object); console.log(d instanceof Object); console.log(c instanceof Object); //false console.log(p instanceof Dog); console.log(d instanceof Cat); console.log(c instanceof Person); console.log(p); console.log(d); console.log(c); //true console.log([] instanceof Object);
function Person(name, age) { this.name = name; this.age = age; } // 原型对象 Person.prototype.run = function () { console.log('跑'); };
console.log(Person.prototype);
浏览器学习
> {run: ƒ, constructor: ƒ} > run: ƒ () > constructor: ƒ Person(name, age) > __proto__: Object
.__proto__看起来很像一个属性,可是实际上它更像一个getter/setter测试
var p = new Person(); console.log(p.__proto__);
浏览器
> {run: ƒ, constructor: ƒ} > run: ƒ () > constructor: ƒ Person(name, age) > __proto__: Object
__proto__
是一个非标准属性
即ECMAScript中并不包含该属性,这只是某些浏览器为了方便开发人员开发和调试而提供的一个属性,不具有通用性
建议:在调试的时候可使用该属性,但不能出如今正式的代码中
.__proto__
是可设置属性,可使用ES6的Object.setPrototypeOf(..)进行设置。然而,一般来讲你不须要修改已有对象的[[Prototype]]。
var newYX = { 'add': function () { console.log('sum'); } }; p.__proto__ = newYX; console.log(p.__proto__);
浏览器
> {add: ƒ} > add: ƒ () > __proto__: Object
in 判断一个对象, 是否拥有某个属性(若是对象身上没有, 会到原型对象里面查找)
function Person(name, age) { this.name = name; this.age = age; } Person.prototype.address = '上海'; var p = new Person('撩课', 18); // console.log(name in p); // false console.log('name' in p); // true console.log('address' in p); // true
只到对象自身查找
function Person(name, age) { this.name = name; this.age = age; } Person.prototype.address = '上海'; var p = new Person('张三', 20); console.log(p.hasOwnProperty('name')); // true console.log(p.hasOwnProperty('address')); // false
是的,它们执行相同的操做,都遍历原型链以查找其中的特定对象。
二者的区别在于它们是什么,以及如何使用它们,例如isPrototypeOf
是对象上可用的函数。它容许您测试一个特定对象是否在另外一个对象的prototype
链中,由于此方法是在object
上定义的原型,它对全部对象均可用。
instanceof
是一个操做符,它须要两个操做数,一个对象和一个构造函数,它将测试传递的函数原型属性是否存在于对象链上(经过[[HasInstance]](V)
内部操做,仅在函数对象中可用)。
B.isPrototypeOf(a) 判断的是A对象是否存在于B对象的原型链之中,检查B
a instanceof B 判断的是B.prototype是否存在与A的原型链之中,检查B.prototype
isPrototypeOf() 与 instanceof 运算符不一样。在表达式 "object instanceof AFunction"中,object 的原型链是针对 AFunction.prototype 进行检查的,而不是针对 AFunction 自己。
function A () { this.a = 1; } function B () { this.b = 2; } B.prototype = new A(); B.prototype.constructor = B; function C () { this.c = 3; } C.prototype = new B(); C.prototype.constructor = C; var c = new C(); // instanceof expects a constructor function c instanceof A; // true c instanceof B; // true c instanceof C; // true // isPrototypeOf, can be used on any object A.prototype.isPrototypeOf(c); // true B.prototype.isPrototypeOf(c); // true C.prototype.isPrototypeOf(c); // true
function Person(first, last, age, gender, interests) { this.name = { first, last }; this.age = age; this.gender = gender; this.interests = interests; }; Person.prototype.greeting = function() { console.log('Hi! I\'m ' + this.name.first + '.'); }; function Teacher(first, last, age, gender, interests, subject) { Person.call(this, first, last, age, gender, interests); //用的是传送给Teacher(),而不是Person()的值 this.subject = subject; } var p = new Person("张","三",22,"男",["篮球","KTV"]); var t = new Teacher("李","四",18,"男",["英语","计算机"],"编程"); t.greeting(); //TypeError: t.greeting is not a function //这里 Teacher 不能获取 greeting...
这里主要调用Person.call(this, first, last, age, gender, interests);
定义 Teacher() 构造器函数,
咱们颇有效的在Teacher()构造函数里运行了Person()构造函数,获得了和在Teacher()里定义的同样的属性,可是用的是传送给Teacher(),而不是Person()的值(咱们简单使用这里的this做为传给call()的this,意味着this指向Teacher()函数)。
咱们须要让Teacher()从Person()的原型对象里继承方法
Teacher.prototype = Object.create(Person.prototype);
在这个例子里咱们用这个函数来建立一个和Person.prototype同样的新的原型属性值(这个属性指向一个包括属性和方法的对象),而后将其做为Teacher.prototype的属性值。
看看比较
如今Teacher()的prototype的constructor属性指向的是Person(), 这是由咱们生成Teacher()的方式决定的。
这或许会成为很大的问题,因此咱们须要将其正确设置——您能够回到源代码,在底下加上这一行代码来解决:
Teacher.prototype.constructor = Teacher;
注:每个函数对象(Function)都有一个
prototype
属性,而且只有函数对象有prototype
属性,由于prototype
自己就是定义在Function
对象下的属性。当咱们输入相似var person1=new Person(...)
来构造对象时,JavaScript实际上参考的是Person.prototype
指向的对象来生成person1
。另外一方面,Person()
函数是Person.prototype
的构造函数,也就是说Person===Person.prototype.constructor
(不信的话能够试试)。在定义新的构造函数
Teacher
时,咱们经过function.call
来调用父类的构造函数,可是这样没法自动指定Teacher.prototype
的值,这样Teacher.prototype
就只能包含在构造函数里构造的属性,而没有方法。所以咱们利用Object.create()
方法将Person.prototype
做为Teacher.prototype
的原型对象,并改变其构造器指向,使之与Teacher
关联。任何您想要被继承的方法都应该定义在构造函数的
prototype
对象里,而且永远使用父类的prototype
来创造子类的prototype
,这样才不会打乱类继承结构。
new 与 Object.create 区别
- new的话只能是class(即函数),可是Object.create()的参数能够为对象也能够为函数,
- 若是Object.create()的参数是对象的话,那么新的对象会继承原对象的属性;若是参数是类(函数)的话,Object.create()的参数为类(函数)原型,如您所说的,它没有绑定this,并无属性被继承。
- Object.create(null)能够实现一个空对象,即没有原型的对象,但使用new就办不到。
Object.assign(目标对象, ...源对象)
方法用于将全部可枚举属性的值从一个或多个源对象复制到目标对象。它将返回目标对象。
//再建立一个基类 function Animal(age) { this.age = age; } Animal.prototype.say = function(language) { console.log('you say ' + language); } function Student(name, sex, age) { Person.call(this, name, sex); Animal.call(this, age); } //原型链拼接 Student.prototype = Object.create(Person.prototype); Object.assign(Student.prototype, Animal.prototype); Student.prototype.constructor = Student; Student.prototype.getInfo = function() { console.log('getInfo: [name:' + this.name + ', sex:' + this.sex + ', age:' +this.age + '].'); }; var s = new Student('coco', 'femal', 25);
function Animal(name, age) { this.name = name; this.age = age; } Animal.prototype.eat = function () { console.log('吃'); }; Animal.prototype.run = function () { console.log('跑'); } function Person(name, age, job) { Animal.call(this, name, age); this.job = job; } Person.prototype = Object.create(Animal.prototype); Person.prototype.constructor = Person; //Person.prototype.jump 原型方法必须写在继承后 Person.prototype.jump = function () { console.log('跳'); }; function Student(name, age, job, className) { Animal.call(this, name, age); Person.call(this, name, age, job); this.className = className; } Student.prototype = Object.create(Person.prototype); Student.prototype.constructor = Student; //原型方法必须写在继承后 Student.prototype.study = function () { console.log('学习'); } function Adolescent(name, age, job, className,sex) { Animal.call(this, name, age); Person.call(this, name, age, job); Person.call(this, name, age, job,className); this.sex = sex; } Adolescent.prototype = Object.create(Student.prototype); Adolescent.prototype.constructor = Adolescent; //原型方法必须写在继承后 Student.prototype.play = function () { console.log('跳绳'); } this.a2 = new Adolescent('张同窗',18,'学生','高2.1版',"女"); this.s1 = new Student('张同窗',18,'学生','高2.1版'); this.p1 = new Person('王老师',26,'教师'); this.a1 = new Animal('校长',44);
原型方法必须写在设置原型 XXX.prototype = Object.create(...)
和设置构造器引用XXX.prototype.constructor = xxx
以后,不容会丢失。
直接给对象动态添加属性和方法 弊端: 若是操做不少个对象, 则没法共享 代码比较冗余
例子:arr2的run不能执行~
var arr = [1,2,3]; arr.run = function () { console.log('跑'); } arr.run(); var arr2 = [2]; arr.run = function () { console.log('跑'); }
直接给Array原型对象添加方法 弊端: 可能会产生覆盖的状况
例子:覆盖push
Array.prototype.push = function () { console.log('跑'); }; var arr = [1,2,3]; arr.push(); var arr2 = [2]; arr2.push();
提供一个新的构造函数 修改构造函数的原型指向为数组的原型对象 为了可以获取数组里面的属性和方法 问题: 依然会修改数组原型对象内容 优化 原型对象就是一个对象 能够直接根据Array建立一个对象, 给新建立的函数原型对象进行赋值
function MyArray() {} MyArray.prototype = new Array(); MyArray.prototype.run = function () { console.log('跑'); }; var arr = new MyArray(); arr.run();
var obj1 = {name: '张三', age: 18}; var obj2 = {}; for (var key in obj1) { obj2[key] = obj1[key]; } console.log(obj2);
方法用于将全部可枚举属性的值从一个或多个源对象复制到目标对象。它将返回目标对象。
var obj3 = {className: '六班'}; Object.assign(obj3, obj1, {address: '重庆'}); console.log(obj3);
深拷贝/浅拷贝
区别:在于对引用值的处理
深拷贝实现
var obj = { name: "唐三三", age: 30, friend: ['张森', '夏赢'], address: { city: '重庆', county: '渝北' }, play: function () { console.log(this.name + '喜欢桌球'); } } //deep Copy function deepCopySource2Target(source, target) { for (var key in source) { var sourceValue = source[key]; if (!(sourceValue instanceof Object)) { //value object target[key] = sourceValue; } else { //object object var temp = new sourceValue.constructor; deepCopySource2Target(sourceValue, temp); target[key] = temp; } } } var newObj = {}; deepCopySource2Target(obj, newObj); console.log(newObj); newObj.play();