原生JS基础知识
原型
-
定义 : 原型是function对象的一个属性 , 其值类型为对象 , 它定义了构造函数 new 出的所有对象的公共祖先 , 通过该构造函数产生的对象 , 可以继承该原型的属性和方法
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VXjHGY5m-1581835275380)(./原型.png)]
-
构造函数通过访问其隐式属性
prototype
可以查看原型function Person() {} Person.prototype // 原型
-
利用原型的特点和属性 ,
可以提取共有属性
// before function Car(color, owner) { this.color = color; this.owner = owner; this.height = 1400; this.lang = 4900; this.carName = "BMW"; } // after Car.prototype.height = 1400; Car.prototype.lang = 4900; Car.prototype.carName = "BMW"; function Car(color, owner) { this.color = color; this.owner = owner; } // simplify Car.prototype = { height: 1400, lang: 4900, carName: "BMW", } function Car(color, owner) { this.color = color; this.owner = owner; }
-
对象通过访问其隐式属性
__proto__
可以查看该对象的原型var p = new Person(); function Person() { // var this = Object.create(Person.prototype); ... // return this; }
-
对象通过访问属性
constructor
可以查看其构造函数function Person() {} var p = new Person(); p.constructor; // p.__proto__.constructor ( 继承 )
-
__proto__指向的原型可手动更改 , 让对象"认贼作父"
function Person() {} Person.prototype.name = '父'; var p = new Person(); console.log(p.name); // 通过__proto__访问p的原型上的name属性 , 打印结果为 : 父 var obj = { name: '贼' } p.__proto__ = obj; console.log(p.name); // 贼
-
对象的构造函数constructor可手动更改 , 让对象"认贼作父"
function Wang() {} function Li() {} Wang.prototype = { constructor: Li } var xiaoWang = new Wang(); console.log(xiaoWang.constructor); // function Li() {}
原型链
GrandFather.prototype.__proto__ === Object.prototype
GrandFather.prototype.lastName = 'liu';
function GrandFather() {}
var grandfather = new GrandFather();
Father.prototype = grandfather;
function Father() {}
var father = new Father();
Son.prototype = father;
function Son() {}
var son = new Son();
console.log(son.lastName); // 'liu'
-
Object.create(原型)
-
原型必填 , 且为对象或null
-
Object.create(null)
可创造出无原型的对象 , 故Object.prototype
是JS中绝大多数对象的最顶部原型而非全部 , 且手动增添属性__proto__
并无继承功效var obj = Object.create(null); obj.__proto__ = { name: 'father' }; console.log(obj.name); // undefined
-
-
原型链编程之重写方法
f : Object.prototype.toString : "[object Number]" "[object String]" "[object Boolean]" "[object Array]" "[object Object]" f : Number.prototype.toString f : String.prototype.toString f : Boolean.prototype.toString f : Array.prototype.toString
var num = 123; num.toString(); // 先使用包装类包装成对象 , 然后依据原型链的就近访问原则调用Number.prototype.toString方法 , 返回 "123" Object.prototype.toString.call(123); // "[object Number]"
-
Tips : . 被识别成小数点的优先级高于被识别成访问属性/方法的符号 , 故
123.toString()
会报错 -
Tips : document.write 方法会隐式调用 toString 方法再将结果打印在浏览器页面上
// 验证 var obj = Object.create(null); // 创建无原型对象( 也就无toString ) obj.toString = function () { return 'haha' } // 手动添加 toString 方法 document.write(obj); // 页面显示 'haha'
-
call / apply
-
再看函数的执行
function foo() {} foo(); // 真实面目为 ```foo.call()```
-
call改变this指向
function Person(name) { this.name = name; } Person('liu'); // 此时函数Person中的this默认指向window var obj = {} Person.call(obj, 'liu'); // 此时函数Person中的this指向obj
-
call的高级用法 ( 借用别的方法实现自己的功能 )
function Person(name, sex) { this.name = name; this.sex = sex; }
// before function Student(name, sex, age, grade) { this.name = name; this.sex = sex; this.age = age; this.grade = grade; } var student = new Student('xiaoliu', 'male', 18, 'three');
// after function Student(name, sex, age, grade) { Person.call(this, name, sex); this.age = age; this.grade = grade; } var student = new Student('xiaoliu', 'male', 18, 'three');
-
apply 和 call 都能改变this指向 , 但call逐个传递参数 , 而apply传递实参列表arguments
function Person(name, age, sex) {} var obj = {} Person.call(obj, 'xiaoliu', 18, 'male'); Person.apply(obj, ['xiaoliu', 18, 'male']);