javascript考点 —— 原型和原型链

一、构造函数

构造函数的函数名第一个字母必须大写。

构造函数创建对象的过程:先传参数,构造函数中的this变为空对象,然后进行赋值,将this返回,将this赋值给f。

function Foo(name, age){
    this.name = name
    this.age = age
    this.class = 'class-1'
    //return this   默认会返回一个this
}
var f = new Foo('zhangsan',20)

二、构造函数-扩展

  • var a = {}其实是var a = new Object()的语法糖
  • var a = []其实是var a = new Array()的语法糖
  • function Foo(){...}其实是var Foo = new Function(...)
  • 使用instanceof判断一个函数是否是一个变量的构造函数

三、原型规则和示例

1、5条原型规则

  • 所有的引用类型(数组、对象、函数),都具有对象特性,即可资又扩展属性(除了null)
var obj = {}; obj.a = 100;
var arr = []; arr.a = 100;
function fn() {}
fn.a = 100
  • 所有的引用类型(数组、对象、函数),都有一个__proto__(隐式原型)属性,属性值是一个普通对象
var obj = {}; obj.a = 100;
var arr = []; arr.a = 100;
function fn() {}
console.log(obj.__proto__)   //{}
console.log(arr.__proto__)   //[]
console.log(fn.__proto__)    //[Function]
  • 所有函数,都有一个prototype(显式原型)属性,属性值也是一个普通对象
function fn() {}
console.log(fn.prototype)    //fn {}
  • 所有的引用类型(数组、对象、函数),__proto__属性指向它的构造函数的prototype属性值
var obj = {};
console.log(obj.__proto__ === Object.prototype);   //true
  • 当试图得到一个引用类型的某个属性时,如果这个对象本身没有这个属性,那么它会去它的__proto__(即它的构造函数的prototype)中寻找。
function Foo(name, age) {
    this.name = name
}
Foo.prototype.alertName = function() {
    alert(this.name)                //this指向f本身
}
var f = new Foo('zhangsan')
f.printName = function() {
    console.log(this.name)              //this指向f本身
}
f.printName()
f.alertName()       //f没有alertName属性,然后就去隐式原型里面找,隐式原型就是f的构造函数的显示原型

2、循环对象自身的属性

function Foo(name, age) {
    this.name = name
}
Foo.prototype.alertName = function() {
    alert(this.name)
}
var f = new Foo('zhangsan')
f.printName = function() {
    console.log(this.name)
}
f.printName()
f.alertName()
var item
for(item in f){
    //高级浏览器已经在for in中屏蔽了来自原型的属性
    //但是这里建议大家还是加上这个判断,保证程序的健壮性
    if(f.hasOwnProperty(item)){
        console.log(item)          //name  printName
    }
}

四、原型链

首先来看例子:

function Foo(name, age) {
    this.name = name
}
Foo.prototype.alertName = function() {
    //alert(this.name)
}
var f = new Foo('zhangsan')
f.printName = function() {
    console.log(this.name)
}
f.printName()
f.alertName()
f.toString()        //要去f.__proto__.__proto__去查找

然后最后一行。找到toString的路线是:

这里要注意的是,Object.prototype的隐式原型是一个null,为了避免JS中的死循环才这样做的。

五、instanceof

1、作用:用于判断引用类型属于哪个构造函数的方法。

2、f  instanceof  Foo的判断逻辑:

  • f的__proto__一层一层往上,能否对应到Foo.ptototype

3、再试着判断f  instanceof  Object

  • f的__proto__一层一层往上,能否对应到Object.ptototype

六、解题:

  • 如何准确判断一个变量是数组类型

解答:变量名  instanceof  Array。不能用typeof。

  • 写一个原型链继承的例子

解答:

//面试不要这么写,最好写贴近实战的例子
function Animal() {
    this.eat = function() {
        console.log('animal eat')
    }
}
function Dog() {
    this.bark = function() {
        console.log('dog bark')
    }
}
Dog.prototype = new Animal()
var hashiqi = new Dog()
/最好写下面的这个
function Elem(id) {
    this.elem = document.getElementById(id)
}
Elem.prototype.html = function(val) {
    var elem = this.elem
    if(val) {
        elem.innerHTML = val
        return this      //链式操作
    } else {
        return elem.innerHTML
    }
}
Elem.prototype.on = function(type, fn) {
    var elem = this.elem
    elem.addEventListener(type, fn)
    return this
}
var div1 = new Elem('div1')
//console.log(div1.html())

div1.html('<p>hello imooc</p>').on('click', function(){
    alert('clicked')
}).html('<p>javascript</p>')
//这里之所以可以使用链式,是因为每次调用完html或者on都返回了this。
  • 描述new一个对象的过程

解答:(1)创建一个新对象

           (2)this指向这个新对象

           (3)执行代码,即对this赋值

           (4)返回this

  • zepto(或其他框架中)源码中如何使用原型链

解答:最好看过源码

猜你喜欢

转载自blog.csdn.net/zhanghuali0210/article/details/82113578