JS基础知识(二)原型和原型链

原型和原型链

问题:

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

  2. 写一个原型链继承的例子

  3. 描述new 一个对象的过程

  4. Zepto(或其他框架)源码中如何使用原型链

     

知识点: 

1.构造函数

function Foo (name, age) {
	this.name = name;
	this.age = age;
	this.class = 'class-1';
}


Foo
/* ƒ Foo (name, age) {
	this.name = name;
	this.age = age;
	this.class = 'class-1';
} */
var f = new Foo('xiaoming', 12)

f
//Foo {name: "xiaoming", age: 12, class: "class-1"}

 建议构造函数的首字母用大写便于阅读。

构造函数会默认return this.

这里讲一下“var f = new Foo('xiaoming', 12)”也就是new一个对象的过程:

首先先传入相应的参数在这个构造函数,然后其实先有一个this,为空对象,再将其进行赋值。像我们前一次讲到的对象是属于引用类型,引用类型可以无限的扩展属性,这里this.name,this.age都可以有点像那个无限扩展属性,给他加上属性,然后赋值,然后最后再返回一个return this。再将这个this传回来,赋值给f.

2.构造函数--扩展

语法糖:

语法糖就是一种便捷写法。在达到相同的目的情况下,更简便的方法。

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

对于一个变量的所有东西都有构造函数,对象,函数,数组都是有构造函数的.

对于1,2,3都推荐前者,易读且性能更好

//构造函数拓展
var a = {}

var b = []

function fn (){}

var a = new Object

var b = new Array

fn = new Function (...)

 

3.原型规则和示例

5条原型规则

原型规则是学习原型链的基础
(1)所有的引用类型(数组,对象,函数),都可以可自由扩展属性(除了null除外)

(2)所有的引用类型(数组,对象,函数),都有一个_proto_属性(简称他隐式原型),属性值是一个普通的对象。

(3)所有的函数,都有一个prototype(显式原型)属性,属性值也是一个普通的对象

(4)所有的引用类型(数组,对象,函数),_proto_属性值指向它的构造函数”prototype ”的属性值

(5) 当试图得到一个对象的某个属性时,如果这个对象本身没有这个属性,那么会去它的_proto_(即它的构造函数的prototype)中寻找。

var obj = {}

obj.a = 100

obj.b = 'abc'

obj
//{a: 100, b: "abc"}

var arr = [1,2,3]

arr.a = 100

arr
//(3) [1, 2, 3, a: 100]

function fn () {}

fn.a = 100

fn.b =200
obj
//{a: 100, b: "abc"}
arr
//(3) [1, 2, 3, a: 100]
fn
//ƒ fn () {}
obj.__proto__
//{constructor: ƒ, __defineGetter__: ƒ, __defineSetter__: ƒ, hasOwnProperty: ƒ, __lookupGetter__: ƒ, …}
arr.__proto__
//[constructor: ƒ, concat: ƒ, find: ƒ, findIndex: ƒ, pop: ƒ, …]
fn.__proto__
//ƒ () { [native code] }
fn
//ƒ fn () {}
Object
//ƒ Object() { [native code] }
fn.prototype
//{constructor: ƒ}
Object.prototype
//{constructor: ƒ, __defineGetter__: ƒ, __defineSetter__: ƒ, hasOwnProperty: ƒ, __lookupGetter__: ƒ, …}
obj
//{a: 100, b: "abc"}
obj.__proto__
//{constructor: ƒ, __defineGetter__: ƒ, __defineSetter__: ƒ, hasOwnProperty: ƒ, __lookupGetter__: ƒ, …}
Object
//ƒ Object() { [native code] }
Object.prototype
//{constructor: ƒ, __defineGetter__: ƒ, __defineSetter__: ƒ, hasOwnProperty: ƒ, __lookupGetter__: ƒ, …}
obj.__proto__ === Object.prototype
//true

4.原型链

 以一个例子来具体来看:

f是 通过构造函数Foo new的一个对象,他有一个自己的方法printName。同时构造函数还增加了一个方法的alertName。

Foo像一个类,而f是他类别下面一个具体的实例。

类的方法他都有,实例还有自己单独的方法。

 

function Foo(name,age){
	this.name = name;
}


Foo.prototype.alertName= function(){
	alert(this.name)
}

var f = new Foo('dd',13)

f.printName = function () {
	console.log(this.name)
}

f
//Foo {name: "dd", printName: ƒ}
f.printName()
//dd
f.alertName()

f.toString()
//"[object Object]"

f
//Foo {name: "dd", printName: ƒ}
f.__proto__
//{alertName: ƒ, constructor: ƒ}
Object
//ƒ Object() { [native code] }
Object.prototype
//{constructor: ƒ, __defineGetter__: ƒ, __defineSetter__: ƒ, hasOwnProperty: ƒ, __lookupGetter__: ƒ, …}
f.__proto__.__proto__
/*{constructor: ƒ, __defineGetter__: ƒ, __defineSetter__: ƒ, hasOwnProperty: ƒ, __lookupGetter__: ƒ, …}
constructor: ƒ Object()
hasOwnProperty: ƒ hasOwnProperty()
isPrototypeOf: ƒ isPrototypeOf()
propertyIsEnumerable: ƒ propertyIsEnumerable()
toLocaleString: ƒ toLocaleString()
toString: ƒ toString()
valueOf: ƒ valueOf()
__defineGetter__: ƒ __defineGetter__()
__defineSetter__: ƒ __defineSetter__()
__lookupGetter__: ƒ __lookupGetter__()
__lookupSetter__: ƒ __lookupSetter__()
get __proto__: ƒ __proto__()
set __proto__: ƒ __proto__()*/

 

 

其中含有一个this,this要看具体的情形来判断的,当比如说f.name这个this就是指向f. 

4.1 实现一个new的方法

function create() {
  let obj = {}
  let Con = [].shift.call(arguments)
  obj.__proto__ = Con.prototype
  let result = Con.apply(obj, arguments)
  return result instanceof Object ? result : obj
}

 

  • 创建一个空对象
  • 获取构造函数
  • 设置空对象的原型
  • 绑定 this 并执行构造函数
  • 确保返回值为对象

5.instanceof

用于判断引用类型属于哪个构造函数的方法 

var arr = [1,2,3]

arr instanceof Array
//true
typeof arr
//"object"

虽然instanceof 不能判断原始类型,我们可以通过改造来实现。

class PrimitiveString {
  static [Symbol.hasInstance](x) {
    return typeof x === 'string'
  }
}
console.log('hello world' instanceof PrimitiveString) // true

// Symbol.hasIntance是一个方法可以自定义判断构造函数是否将对象识别为实例

5.1实现一个instanceof 

function myInstanceof(left, right) {
  let prototype = right.prototype
  left = left.__proto__
  while (true) {
    if (left === null || left === undefined)
      return false
    if (prototype === left)
      return true
    left = left.__proto__
  }
}
  • 首先获取类型的原型
  • 然后获得对象的原型
  • 然后一直循环判断对象的原型是否等于类型的原型,直到对象原型为 null,因为原型链最终为 null

6.使用Object.prototype.toString.call(arr) === '[object Array]'

function isArray(o) {
  return Object.prototype.toString.call(o);
}
var arr=[2,5,6,8];
var obj={name:'zhangsan',age:25};
var fn = function () {}
console.log(isArray(arr)); //[object Array]
console.log(isArray(obj)); //[object Object]
console.log(isArray(fn));  //[object function]

7.ES5定义了Array.isArray:

Array.isArray([]) //true

问题解决:

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

    instanceof
    Object.prototype.toString.call(arr) === '[object Array]'
    Array.isArray([])

  2. 写一个原型链继承的例子
     

    function Elem(id){
    	this.ele = document.getElementById(id);
    }
    
    Elem.prototype.html = function (value) {
    	var ele = this.ele;
    	if (value) {
    		ele.innerHTML = value;
    		return this;
    	}else {
    		return ele.innerHTML
    	}
    }
    
    Elem.prototype.on = function (type,fn) {
    	var ele = this.ele;
    	ele.addEventListener(type,fn);
    }
    
    
    var a = new Elem('article');
    a.on('click',function() {
    	alert('hello');
    });
    console.log(a.html());

    这里的return this可以使得在后面调用时候,进行循环调用。

  3. 描述new 一个对象的过程
    先传入相应的参数,也可以不传,然后在构造函数里面有一个this的空对象,对他进行扩展属性赋值,再返回一个this。将他返回给那个对象。

  4. Zepto(或其他框架)源码中如何使用原型链
    可以自行去查找相关资料看一下。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值